diff --git a/src/share/classes/com/sun/crypto/provider/GCTR.java b/src/share/classes/com/sun/crypto/provider/GCTR.java index d4cd740af7bea80f35b0f532ff981b69110a4d44..f8a3eaa0a4cd11707f655319d6581e283f3f582f 100644 --- a/src/share/classes/com/sun/crypto/provider/GCTR.java +++ b/src/share/classes/com/sun/crypto/provider/GCTR.java @@ -38,7 +38,17 @@ import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE; * under section 6.5. It needs to be constructed w/ an initialized * cipher object, and initial counter block(ICB). Given an input X * of arbitrary length, it processes and returns an output which has - * the same length as X. + * the same length as X. The invariants of this class are: + * + * (1) The length of intialCounterBlk (and also of its clones, e.g., + * fields counter and counterSave) is equal to AES_BLOCK_SIZE. + * + * (2) After construction, the field counter never becomes null, it + * always contains a byte array of length AES_BLOCK_SIZE. + * + * If any invariant is broken, failures can occur because the + * AESCrypt.encryptBlock method can be intrinsified on the HotSpot VM + * (see JDK-8067648 for details). * *

This function is used in the implementation of GCM mode. * @@ -59,6 +69,10 @@ final class GCTR { // NOTE: cipher should already be initialized GCTR(SymmetricCipher cipher, byte[] initialCounterBlk) { this.aes = cipher; + if (initialCounterBlk.length != AES_BLOCK_SIZE) { + throw new RuntimeException("length of initial counter block (" + initialCounterBlk.length + + ") not equal to AES_BLOCK_SIZE (" + AES_BLOCK_SIZE + ")"); + } this.icb = initialCounterBlk; this.counter = icb.clone(); } @@ -137,6 +151,8 @@ final class GCTR { * Restores the content of this object to the previous saved one. */ void restore() { - this.counter = this.counterSave; + if (this.counterSave != null) { + this.counter = this.counterSave; + } } } diff --git a/src/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/share/classes/java/lang/invoke/DirectMethodHandle.java index e9d2526cd8d336b9f082065973f4345ff7d57278..cabd0716341678ae1b0fbe9f8471669e2d09c8e9 100644 --- a/src/share/classes/java/lang/invoke/DirectMethodHandle.java +++ b/src/share/classes/java/lang/invoke/DirectMethodHandle.java @@ -31,7 +31,6 @@ import java.util.Arrays; import sun.invoke.util.VerifyAccess; import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.LambdaForm.*; -import static java.lang.invoke.LambdaForm.BasicType.*; import static java.lang.invoke.MethodTypeForm.*; import static java.lang.invoke.MethodHandleStatics.*; import java.lang.ref.WeakReference; diff --git a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index 6e8d091a6c5afbd6cdbec879d93eb6ed19543c3a..d9c6f0ffbdfdb2954672a47248522cfad8cc4ab1 100644 --- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -56,9 +56,11 @@ class InvokerBytecodeGenerator { private static final String OBJ = "java/lang/Object"; private static final String OBJARY = "[Ljava/lang/Object;"; + private static final String MH_SIG = "L" + MH + ";"; private static final String LF_SIG = "L" + LF + ";"; private static final String LFN_SIG = "L" + LFN + ";"; private static final String LL_SIG = "(L" + OBJ + ";)L" + OBJ + ";"; + private static final String LLV_SIG = "(L" + OBJ + ";L" + OBJ + ";)V"; private static final String CLL_SIG = "(L" + CLS + ";L" + OBJ + ";)L" + OBJ + ";"; /** Name of its super class*/ @@ -616,6 +618,15 @@ class InvokerBytecodeGenerator { return g.loadMethod(g.generateCustomizedCodeBytes()); } + /** Generates code to check that actual receiver and LambdaForm matches */ + private boolean checkActualReceiver() { + // Expects MethodHandle on the stack and actual receiver MethodHandle in slot #0 + mv.visitInsn(Opcodes.DUP); + mv.visitVarInsn(Opcodes.ALOAD, localsMap[0]); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "assertSame", LLV_SIG, false); + return true; + } + /** * Generate an invoker method for the passed {@link LambdaForm}. */ @@ -635,6 +646,16 @@ class InvokerBytecodeGenerator { mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true); } + if (lambdaForm.customized != null) { + // Since LambdaForm is customized for a particular MethodHandle, it's safe to substitute + // receiver MethodHandle (at slot #0) with an embedded constant and use it instead. + // It enables more efficient code generation in some situations, since embedded constants + // are compile-time constants for JIT compiler. + mv.visitLdcInsn(constantPlaceholder(lambdaForm.customized)); + mv.visitTypeInsn(Opcodes.CHECKCAST, MH); + assert(checkActualReceiver()); // expects MethodHandle on top of the stack + mv.visitVarInsn(Opcodes.ASTORE, localsMap[0]); + } // iterate over the form's names, generating bytecode instructions for each // start iterating at the first name following the arguments diff --git a/src/share/classes/java/lang/invoke/Invokers.java b/src/share/classes/java/lang/invoke/Invokers.java index 14aef1bd7b46284b2209727dca4c511dcbd82fb0..e09dc3686c4fecce346a9e2f1716add5a1e105b0 100644 --- a/src/share/classes/java/lang/invoke/Invokers.java +++ b/src/share/classes/java/lang/invoke/Invokers.java @@ -247,6 +247,7 @@ class Invokers { int nameCursor = OUTARG_LIMIT; final int MTYPE_ARG = customized ? -1 : nameCursor++; // might be last in-argument final int CHECK_TYPE = nameCursor++; + final int CHECK_CUSTOM = (CUSTOMIZE_THRESHOLD >= 0) ? nameCursor++ : -1; final int LINKER_CALL = nameCursor++; MethodType invokerFormType = mtype.invokerType(); if (isLinker) { @@ -279,6 +280,9 @@ class Invokers { // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*) outArgs[0] = names[CHECK_TYPE]; } + if (CHECK_CUSTOM != -1) { + names[CHECK_CUSTOM] = new Name(NF_checkCustomized, names[CALL_MH]); + } names[LINKER_CALL] = new Name(outCallType, outArgs); lform = new LambdaForm(debugName, INARG_LIMIT, names); if (isLinker) @@ -386,11 +390,32 @@ class Invokers { return ((CallSite)site).getTarget(); } + /*non-public*/ static + @ForceInline + void checkCustomized(Object o) { + MethodHandle mh = (MethodHandle)o; + if (mh.form.customized == null) { + maybeCustomize(mh); + } + } + + /*non-public*/ static + @DontInline + void maybeCustomize(MethodHandle mh) { + byte count = mh.customizationCount; + if (count >= CUSTOMIZE_THRESHOLD) { + mh.customize(); + } else { + mh.customizationCount = (byte)(count+1); + } + } + // Local constant functions: private static final NamedFunction NF_checkExactType, NF_checkGenericType, - NF_getCallSiteTarget; + NF_getCallSiteTarget, + NF_checkCustomized; static { try { NamedFunction nfs[] = { @@ -399,7 +424,9 @@ class Invokers { NF_checkGenericType = new NamedFunction(Invokers.class .getDeclaredMethod("checkGenericType", Object.class, Object.class)), NF_getCallSiteTarget = new NamedFunction(Invokers.class - .getDeclaredMethod("getCallSiteTarget", Object.class)) + .getDeclaredMethod("getCallSiteTarget", Object.class)), + NF_checkCustomized = new NamedFunction(Invokers.class + .getDeclaredMethod("checkCustomized", Object.class)) }; for (NamedFunction nf : nfs) { // Each nf must be statically invocable or we get tied up in our bootstraps. diff --git a/src/share/classes/java/lang/invoke/LambdaForm.java b/src/share/classes/java/lang/invoke/LambdaForm.java index 2129f8618bdb2273ab73a39380f6e57a5a5d58f4..5c441071b922302039b034c518d26d46153bdccc 100644 --- a/src/share/classes/java/lang/invoke/LambdaForm.java +++ b/src/share/classes/java/lang/invoke/LambdaForm.java @@ -120,12 +120,14 @@ class LambdaForm { final int arity; final int result; final boolean forceInline; + final MethodHandle customized; @Stable final Name[] names; final String debugName; MemberName vmentry; // low-level behavior, or null if not yet prepared private boolean isCompiled; - volatile Object transformCache; // managed by LambdaFormEditor + // Either a LambdaForm cache (managed by LambdaFormEditor) or a link to uncustomized version (for customized LF) + volatile Object transformCache; public static final int VOID_RESULT = -1, LAST_RESULT = -2; @@ -244,16 +246,17 @@ class LambdaForm { LambdaForm(String debugName, int arity, Name[] names, int result) { - this(debugName, arity, names, result, true); + this(debugName, arity, names, result, /*forceInline=*/true, /*customized=*/null); } LambdaForm(String debugName, - int arity, Name[] names, int result, boolean forceInline) { + int arity, Name[] names, int result, boolean forceInline, MethodHandle customized) { assert(namesOK(arity, names)); this.arity = arity; this.result = fixResult(result, names); this.names = names.clone(); this.debugName = fixDebugName(debugName); this.forceInline = forceInline; + this.customized = customized; int maxOutArity = normalize(); if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) { // Cannot use LF interpreter on very high arity expressions. @@ -263,21 +266,21 @@ class LambdaForm { } LambdaForm(String debugName, int arity, Name[] names) { - this(debugName, arity, names, LAST_RESULT, true); + this(debugName, arity, names, LAST_RESULT, /*forceInline=*/true, /*customized=*/null); } LambdaForm(String debugName, int arity, Name[] names, boolean forceInline) { - this(debugName, arity, names, LAST_RESULT, forceInline); + this(debugName, arity, names, LAST_RESULT, forceInline, /*customized=*/null); } LambdaForm(String debugName, Name[] formals, Name[] temps, Name result) { this(debugName, - formals.length, buildNames(formals, temps, result), LAST_RESULT, true); + formals.length, buildNames(formals, temps, result), LAST_RESULT, /*forceInline=*/true, /*customized=*/null); } LambdaForm(String debugName, Name[] formals, Name[] temps, Name result, boolean forceInline) { this(debugName, - formals.length, buildNames(formals, temps, result), LAST_RESULT, forceInline); + formals.length, buildNames(formals, temps, result), LAST_RESULT, forceInline, /*customized=*/null); } private static Name[] buildNames(Name[] formals, Name[] temps, Name result) { @@ -291,10 +294,6 @@ class LambdaForm { } private LambdaForm(String sig) { - this(sig, true); - } - - private LambdaForm(String sig, boolean forceInline) { // Make a blank lambda form, which returns a constant zero or null. // It is used as a template for managing the invocation of similar forms that are non-empty. // Called only from getPreparedForm. @@ -303,7 +302,8 @@ class LambdaForm { this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity); this.names = buildEmptyNames(arity, sig); this.debugName = "LF.zero"; - this.forceInline = forceInline; + this.forceInline = true; + this.customized = null; assert(nameRefsAreLegal()); assert(isEmpty()); assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature(); @@ -375,6 +375,31 @@ class LambdaForm { return true; } + /** Customize LambdaForm for a particular MethodHandle */ + LambdaForm customize(MethodHandle mh) { + LambdaForm customForm = new LambdaForm(debugName, arity, names, result, forceInline, mh); + if (COMPILE_THRESHOLD > 0 && isCompiled) { + // If shared LambdaForm has been compiled, compile customized version as well. + customForm.compileToBytecode(); + } + customForm.transformCache = this; // LambdaFormEditor should always use uncustomized form. + return customForm; + } + + /** Get uncustomized flavor of the LambdaForm */ + LambdaForm uncustomize() { + if (customized == null) { + return this; + } + assert(transformCache != null); // Customized LambdaForm should always has a link to uncustomized version. + LambdaForm uncustomizedForm = (LambdaForm)transformCache; + if (COMPILE_THRESHOLD > 0 && isCompiled) { + // If customized LambdaForm has been compiled, compile uncustomized version as well. + uncustomizedForm.compileToBytecode(); + } + return uncustomizedForm; + } + /** Renumber and/or replace params so that they are interned and canonically numbered. * @return maximum argument list length among the names (since we have to pass over them anyway) */ @@ -417,8 +442,8 @@ class LambdaForm { for (int i = arity; i < names.length; i++) { names[i].internArguments(); } - assert(nameRefsAreLegal()); } + assert(nameRefsAreLegal()); return maxOutArity; } diff --git a/src/share/classes/java/lang/invoke/LambdaFormEditor.java b/src/share/classes/java/lang/invoke/LambdaFormEditor.java index 1c23e94995ac7c5818741fe40c6a9cfa27bfa4de..7bc2dfbebade51557bb3269c61c5580e88b1f7c4 100644 --- a/src/share/classes/java/lang/invoke/LambdaFormEditor.java +++ b/src/share/classes/java/lang/invoke/LambdaFormEditor.java @@ -51,7 +51,10 @@ class LambdaFormEditor { static LambdaFormEditor lambdaFormEditor(LambdaForm lambdaForm) { // TO DO: Consider placing intern logic here, to cut down on duplication. // lambdaForm = findPreexistingEquivalent(lambdaForm) - return new LambdaFormEditor(lambdaForm); + + // Always use uncustomized version for editing. + // It helps caching and customized LambdaForms reuse transformCache field to keep a link to uncustomized version. + return new LambdaFormEditor(lambdaForm.uncustomize()); } /** A description of a cached transform, possibly associated with the result of the transform. diff --git a/src/share/classes/java/lang/invoke/MethodHandle.java b/src/share/classes/java/lang/invoke/MethodHandle.java index 9b586a3179cce393c3fd09c23c07f1782f2e9816..79730644a232729a99b673e536ab50db780fd326 100644 --- a/src/share/classes/java/lang/invoke/MethodHandle.java +++ b/src/share/classes/java/lang/invoke/MethodHandle.java @@ -434,6 +434,8 @@ public abstract class MethodHandle { // form is not private so that invokers can easily fetch it /*private*/ MethodHandle asTypeCache; // asTypeCache is not private so that invokers can easily fetch it + /*non-public*/ byte customizationCount; + // customizationCount should be accessible from invokers /** * Reports the type of this method handle. @@ -454,9 +456,9 @@ public abstract class MethodHandle { type.getClass(); // explicit NPE form.getClass(); // explicit NPE this.type = type; - this.form = form; + this.form = form.uncustomize(); - form.prepare(); // TO DO: Try to delay this step until just before invocation. + this.form.prepare(); // TO DO: Try to delay this step until just before invocation. } /** @@ -1425,12 +1427,24 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); */ /*non-public*/ void updateForm(LambdaForm newForm) { + assert(newForm.customized == null || newForm.customized == this); if (form == newForm) return; newForm.prepare(); // as in MethodHandle. UNSAFE.putObject(this, FORM_OFFSET, newForm); UNSAFE.fullFence(); } + /** Craft a LambdaForm customized for this particular MethodHandle */ + /*non-public*/ + void customize() { + if (form.customized == null) { + LambdaForm newForm = form.customize(this); + updateForm(newForm); + } else { + assert(form.customized == this); + } + } + private static final long FORM_OFFSET; static { try { diff --git a/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/share/classes/java/lang/invoke/MethodHandleImpl.java index 8812b6d2ad6bc4182ee10632beccf305836eee5f..a339e17ca9330c0d1fcb3657be58af50fa61fb47 100644 --- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -597,6 +597,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; static final NamedFunction NF_checkSpreadArgument; static final NamedFunction NF_guardWithCatch; static final NamedFunction NF_throwException; + static final NamedFunction NF_profileBoolean; static final MethodHandle MH_castReference; static final MethodHandle MH_selectAlternative; @@ -614,10 +615,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class, MethodHandle.class, Object[].class)); NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class)); + NF_profileBoolean = new NamedFunction(MHI.getDeclaredMethod("profileBoolean", boolean.class, int[].class)); NF_checkSpreadArgument.resolve(); NF_guardWithCatch.resolve(); NF_throwException.resolve(); + NF_profileBoolean.resolve(); MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference", MethodType.methodType(Object.class, Class.class, Object.class)); @@ -697,7 +700,26 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; @LambdaForm.Hidden static MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) { - return testResult ? target : fallback; + if (testResult) { + return target; + } else { + return fallback; + } + } + + // Intrinsified by C2. Counters are used during parsing to calculate branch frequencies. + @LambdaForm.Hidden + static + boolean profileBoolean(boolean result, int[] counters) { + // Profile is int[2] where [0] and [1] correspond to false and true occurrences respectively. + int idx = result ? 1 : 0; + try { + counters[idx] = Math.addExact(counters[idx], 1); + } catch (ArithmeticException e) { + // Avoid continuous overflow by halving the problematic count. + counters[idx] = counters[idx] / 2; + } + return result; } static @@ -708,13 +730,18 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; assert(test.type().equals(type.changeReturnType(boolean.class)) && fallback.type().equals(type)); MethodType basicType = type.basicType(); LambdaForm form = makeGuardWithTestForm(basicType); - BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL(); BoundMethodHandle mh; - try { - mh = (BoundMethodHandle) - data.constructor().invokeBasic(type, form, - (Object) test, (Object) profile(target), (Object) profile(fallback)); + if (PROFILE_GWT) { + int[] counts = new int[2]; + mh = (BoundMethodHandle) + BoundMethodHandle.speciesData_LLLL().constructor().invokeBasic(type, form, + (Object) test, (Object) profile(target), (Object) profile(fallback), counts); + } else { + mh = (BoundMethodHandle) + BoundMethodHandle.speciesData_LLL().constructor().invokeBasic(type, form, + (Object) test, (Object) profile(target), (Object) profile(fallback)); + } } catch (Throwable ex) { throw uncaughtException(ex); } @@ -800,7 +827,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; MethodHandle wrapper; if (isCounting) { LambdaForm lform; - lform = countingFormProducer.apply(target); + lform = countingFormProducer.apply(newTarget); wrapper = new CountingWrapper(newTarget, lform, countingFormProducer, nonCountingFormProducer, DONT_INLINE_THRESHOLD); } else { wrapper = newTarget; // no need for a counting wrapper anymore @@ -856,7 +883,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; final int GET_TEST = nameCursor++; final int GET_TARGET = nameCursor++; final int GET_FALLBACK = nameCursor++; + final int GET_COUNTERS = PROFILE_GWT ? nameCursor++ : -1; final int CALL_TEST = nameCursor++; + final int PROFILE = (GET_COUNTERS != -1) ? nameCursor++ : -1; + final int TEST = nameCursor-1; // previous statement: either PROFILE or CALL_TEST final int SELECT_ALT = nameCursor++; final int CALL_TARGET = nameCursor++; assert(CALL_TARGET == SELECT_ALT+1); // must be true to trigger IBG.emitSelectAlternative @@ -864,12 +894,16 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; MethodType lambdaType = basicType.invokerType(); Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType); - BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL(); + BoundMethodHandle.SpeciesData data = + (GET_COUNTERS != -1) ? BoundMethodHandle.speciesData_LLLL() + : BoundMethodHandle.speciesData_LLL(); names[THIS_MH] = names[THIS_MH].withConstraint(data); names[GET_TEST] = new Name(data.getterFunction(0), names[THIS_MH]); names[GET_TARGET] = new Name(data.getterFunction(1), names[THIS_MH]); names[GET_FALLBACK] = new Name(data.getterFunction(2), names[THIS_MH]); - + if (GET_COUNTERS != -1) { + names[GET_COUNTERS] = new Name(data.getterFunction(3), names[THIS_MH]); + } Object[] invokeArgs = Arrays.copyOfRange(names, 0, ARG_LIMIT, Object[].class); // call test @@ -877,15 +911,18 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; invokeArgs[0] = names[GET_TEST]; names[CALL_TEST] = new Name(testType, invokeArgs); + // profile branch + if (PROFILE != -1) { + names[PROFILE] = new Name(Lazy.NF_profileBoolean, names[CALL_TEST], names[GET_COUNTERS]); + } // call selectAlternative - names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[CALL_TEST], - names[GET_TARGET], names[GET_FALLBACK]); + names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[TEST], names[GET_TARGET], names[GET_FALLBACK]); // call target or fallback invokeArgs[0] = names[SELECT_ALT]; names[CALL_TARGET] = new Name(basicType, invokeArgs); - lform = new LambdaForm("guard", lambdaType.parameterCount(), names); + lform = new LambdaForm("guard", lambdaType.parameterCount(), names, /*forceInline=*/true); return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform); } @@ -1615,4 +1652,13 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; assert(elemType.isPrimitive()); return Lazy.MH_copyAsPrimitiveArray.bindTo(Wrapper.forPrimitiveType(elemType)); } + + /*non-public*/ static void assertSame(Object mh1, Object mh2) { + if (mh1 != mh2) { + String msg = String.format("mh1 != mh2: mh1 = %s (form: %s); mh2 = %s (form: %s)", + mh1, ((MethodHandle)mh1).form, + mh2, ((MethodHandle)mh2).form); + throw newInternalError(msg); + } + } } diff --git a/src/share/classes/java/lang/invoke/MethodHandleStatics.java b/src/share/classes/java/lang/invoke/MethodHandleStatics.java index 335a32289a7da45633064dacdd0bedf8a468c4eb..144de11094f858b0ad8788575f689fd45daa566f 100644 --- a/src/share/classes/java/lang/invoke/MethodHandleStatics.java +++ b/src/share/classes/java/lang/invoke/MethodHandleStatics.java @@ -48,9 +48,11 @@ import sun.misc.Unsafe; static final int COMPILE_THRESHOLD; static final int DONT_INLINE_THRESHOLD; static final int PROFILE_LEVEL; + static final boolean PROFILE_GWT; + static final int CUSTOMIZE_THRESHOLD; static { - final Object[] values = new Object[7]; + final Object[] values = new Object[9]; AccessController.doPrivileged(new PrivilegedAction() { public Void run() { values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES"); @@ -60,6 +62,8 @@ import sun.misc.Unsafe; values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 0); values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", 30); values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0); + values[7] = Boolean.parseBoolean(System.getProperty("java.lang.invoke.MethodHandle.PROFILE_GWT", "true")); + values[8] = Integer.getInteger("java.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD", 127); return null; } }); @@ -70,6 +74,12 @@ import sun.misc.Unsafe; COMPILE_THRESHOLD = (Integer) values[4]; DONT_INLINE_THRESHOLD = (Integer) values[5]; PROFILE_LEVEL = (Integer) values[6]; + PROFILE_GWT = (Boolean) values[7]; + CUSTOMIZE_THRESHOLD = (Integer) values[8]; + + if (CUSTOMIZE_THRESHOLD < -1 || CUSTOMIZE_THRESHOLD > 127) { + throw newInternalError("CUSTOMIZE_THRESHOLD should be in [-1...127] range"); + } } /** Tell if any of the debugging switches are turned on.