提交 9f29ecb6 编写于 作者: A amurillo

Merge

...@@ -38,7 +38,17 @@ import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE; ...@@ -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 * under section 6.5. It needs to be constructed w/ an initialized
* cipher object, and initial counter block(ICB). Given an input X * cipher object, and initial counter block(ICB). Given an input X
* of arbitrary length, it processes and returns an output which has * 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).
* *
* <p>This function is used in the implementation of GCM mode. * <p>This function is used in the implementation of GCM mode.
* *
...@@ -59,6 +69,10 @@ final class GCTR { ...@@ -59,6 +69,10 @@ final class GCTR {
// NOTE: cipher should already be initialized // NOTE: cipher should already be initialized
GCTR(SymmetricCipher cipher, byte[] initialCounterBlk) { GCTR(SymmetricCipher cipher, byte[] initialCounterBlk) {
this.aes = cipher; 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.icb = initialCounterBlk;
this.counter = icb.clone(); this.counter = icb.clone();
} }
...@@ -137,6 +151,8 @@ final class GCTR { ...@@ -137,6 +151,8 @@ final class GCTR {
* Restores the content of this object to the previous saved one. * Restores the content of this object to the previous saved one.
*/ */
void restore() { void restore() {
this.counter = this.counterSave; if (this.counterSave != null) {
this.counter = this.counterSave;
}
} }
} }
...@@ -31,7 +31,6 @@ import java.util.Arrays; ...@@ -31,7 +31,6 @@ import java.util.Arrays;
import sun.invoke.util.VerifyAccess; import sun.invoke.util.VerifyAccess;
import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.LambdaForm.*; import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.MethodTypeForm.*; import static java.lang.invoke.MethodTypeForm.*;
import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleStatics.*;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
......
...@@ -56,9 +56,11 @@ class InvokerBytecodeGenerator { ...@@ -56,9 +56,11 @@ class InvokerBytecodeGenerator {
private static final String OBJ = "java/lang/Object"; private static final String OBJ = "java/lang/Object";
private static final String OBJARY = "[Ljava/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 LF_SIG = "L" + LF + ";";
private static final String LFN_SIG = "L" + LFN + ";"; private static final String LFN_SIG = "L" + LFN + ";";
private static final String LL_SIG = "(L" + OBJ + ";)L" + OBJ + ";"; 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 + ";"; private static final String CLL_SIG = "(L" + CLS + ";L" + OBJ + ";)L" + OBJ + ";";
/** Name of its super class*/ /** Name of its super class*/
...@@ -616,6 +618,15 @@ class InvokerBytecodeGenerator { ...@@ -616,6 +618,15 @@ class InvokerBytecodeGenerator {
return g.loadMethod(g.generateCustomizedCodeBytes()); 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}. * Generate an invoker method for the passed {@link LambdaForm}.
*/ */
...@@ -635,6 +646,16 @@ class InvokerBytecodeGenerator { ...@@ -635,6 +646,16 @@ class InvokerBytecodeGenerator {
mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true); 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 // iterate over the form's names, generating bytecode instructions for each
// start iterating at the first name following the arguments // start iterating at the first name following the arguments
......
...@@ -247,6 +247,7 @@ class Invokers { ...@@ -247,6 +247,7 @@ class Invokers {
int nameCursor = OUTARG_LIMIT; int nameCursor = OUTARG_LIMIT;
final int MTYPE_ARG = customized ? -1 : nameCursor++; // might be last in-argument final int MTYPE_ARG = customized ? -1 : nameCursor++; // might be last in-argument
final int CHECK_TYPE = nameCursor++; final int CHECK_TYPE = nameCursor++;
final int CHECK_CUSTOM = (CUSTOMIZE_THRESHOLD >= 0) ? nameCursor++ : -1;
final int LINKER_CALL = nameCursor++; final int LINKER_CALL = nameCursor++;
MethodType invokerFormType = mtype.invokerType(); MethodType invokerFormType = mtype.invokerType();
if (isLinker) { if (isLinker) {
...@@ -279,6 +280,9 @@ class Invokers { ...@@ -279,6 +280,9 @@ class Invokers {
// mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*) // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*)
outArgs[0] = names[CHECK_TYPE]; 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); names[LINKER_CALL] = new Name(outCallType, outArgs);
lform = new LambdaForm(debugName, INARG_LIMIT, names); lform = new LambdaForm(debugName, INARG_LIMIT, names);
if (isLinker) if (isLinker)
...@@ -386,11 +390,32 @@ class Invokers { ...@@ -386,11 +390,32 @@ class Invokers {
return ((CallSite)site).getTarget(); 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: // Local constant functions:
private static final NamedFunction private static final NamedFunction
NF_checkExactType, NF_checkExactType,
NF_checkGenericType, NF_checkGenericType,
NF_getCallSiteTarget; NF_getCallSiteTarget,
NF_checkCustomized;
static { static {
try { try {
NamedFunction nfs[] = { NamedFunction nfs[] = {
...@@ -399,7 +424,9 @@ class Invokers { ...@@ -399,7 +424,9 @@ class Invokers {
NF_checkGenericType = new NamedFunction(Invokers.class NF_checkGenericType = new NamedFunction(Invokers.class
.getDeclaredMethod("checkGenericType", Object.class, Object.class)), .getDeclaredMethod("checkGenericType", Object.class, Object.class)),
NF_getCallSiteTarget = new NamedFunction(Invokers.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) { for (NamedFunction nf : nfs) {
// Each nf must be statically invocable or we get tied up in our bootstraps. // Each nf must be statically invocable or we get tied up in our bootstraps.
......
...@@ -120,12 +120,14 @@ class LambdaForm { ...@@ -120,12 +120,14 @@ class LambdaForm {
final int arity; final int arity;
final int result; final int result;
final boolean forceInline; final boolean forceInline;
final MethodHandle customized;
@Stable final Name[] names; @Stable final Name[] names;
final String debugName; final String debugName;
MemberName vmentry; // low-level behavior, or null if not yet prepared MemberName vmentry; // low-level behavior, or null if not yet prepared
private boolean isCompiled; 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; public static final int VOID_RESULT = -1, LAST_RESULT = -2;
...@@ -244,16 +246,17 @@ class LambdaForm { ...@@ -244,16 +246,17 @@ class LambdaForm {
LambdaForm(String debugName, LambdaForm(String debugName,
int arity, Name[] names, int result) { int arity, Name[] names, int result) {
this(debugName, arity, names, result, true); this(debugName, arity, names, result, /*forceInline=*/true, /*customized=*/null);
} }
LambdaForm(String debugName, 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)); assert(namesOK(arity, names));
this.arity = arity; this.arity = arity;
this.result = fixResult(result, names); this.result = fixResult(result, names);
this.names = names.clone(); this.names = names.clone();
this.debugName = fixDebugName(debugName); this.debugName = fixDebugName(debugName);
this.forceInline = forceInline; this.forceInline = forceInline;
this.customized = customized;
int maxOutArity = normalize(); int maxOutArity = normalize();
if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) { if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) {
// Cannot use LF interpreter on very high arity expressions. // Cannot use LF interpreter on very high arity expressions.
...@@ -263,21 +266,21 @@ class LambdaForm { ...@@ -263,21 +266,21 @@ class LambdaForm {
} }
LambdaForm(String debugName, LambdaForm(String debugName,
int arity, Name[] names) { int arity, Name[] names) {
this(debugName, arity, names, LAST_RESULT, true); this(debugName, arity, names, LAST_RESULT, /*forceInline=*/true, /*customized=*/null);
} }
LambdaForm(String debugName, LambdaForm(String debugName,
int arity, Name[] names, boolean forceInline) { 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, LambdaForm(String debugName,
Name[] formals, Name[] temps, Name result) { Name[] formals, Name[] temps, Name result) {
this(debugName, 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, LambdaForm(String debugName,
Name[] formals, Name[] temps, Name result, boolean forceInline) { Name[] formals, Name[] temps, Name result, boolean forceInline) {
this(debugName, 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) { private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
...@@ -291,10 +294,6 @@ class LambdaForm { ...@@ -291,10 +294,6 @@ class LambdaForm {
} }
private LambdaForm(String sig) { 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. // 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. // It is used as a template for managing the invocation of similar forms that are non-empty.
// Called only from getPreparedForm. // Called only from getPreparedForm.
...@@ -303,7 +302,8 @@ class LambdaForm { ...@@ -303,7 +302,8 @@ class LambdaForm {
this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity); this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
this.names = buildEmptyNames(arity, sig); this.names = buildEmptyNames(arity, sig);
this.debugName = "LF.zero"; this.debugName = "LF.zero";
this.forceInline = forceInline; this.forceInline = true;
this.customized = null;
assert(nameRefsAreLegal()); assert(nameRefsAreLegal());
assert(isEmpty()); assert(isEmpty());
assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature(); assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
...@@ -375,6 +375,31 @@ class LambdaForm { ...@@ -375,6 +375,31 @@ class LambdaForm {
return true; 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. /** 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) * @return maximum argument list length among the names (since we have to pass over them anyway)
*/ */
...@@ -417,8 +442,8 @@ class LambdaForm { ...@@ -417,8 +442,8 @@ class LambdaForm {
for (int i = arity; i < names.length; i++) { for (int i = arity; i < names.length; i++) {
names[i].internArguments(); names[i].internArguments();
} }
assert(nameRefsAreLegal());
} }
assert(nameRefsAreLegal());
return maxOutArity; return maxOutArity;
} }
......
...@@ -51,7 +51,10 @@ class LambdaFormEditor { ...@@ -51,7 +51,10 @@ class LambdaFormEditor {
static LambdaFormEditor lambdaFormEditor(LambdaForm lambdaForm) { static LambdaFormEditor lambdaFormEditor(LambdaForm lambdaForm) {
// TO DO: Consider placing intern logic here, to cut down on duplication. // TO DO: Consider placing intern logic here, to cut down on duplication.
// lambdaForm = findPreexistingEquivalent(lambdaForm) // 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. /** A description of a cached transform, possibly associated with the result of the transform.
......
...@@ -434,6 +434,8 @@ public abstract class MethodHandle { ...@@ -434,6 +434,8 @@ public abstract class MethodHandle {
// form is not private so that invokers can easily fetch it // form is not private so that invokers can easily fetch it
/*private*/ MethodHandle asTypeCache; /*private*/ MethodHandle asTypeCache;
// asTypeCache is not private so that invokers can easily fetch it // 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. * Reports the type of this method handle.
...@@ -454,9 +456,9 @@ public abstract class MethodHandle { ...@@ -454,9 +456,9 @@ public abstract class MethodHandle {
type.getClass(); // explicit NPE type.getClass(); // explicit NPE
form.getClass(); // explicit NPE form.getClass(); // explicit NPE
this.type = type; 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()); ...@@ -1425,12 +1427,24 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
*/ */
/*non-public*/ /*non-public*/
void updateForm(LambdaForm newForm) { void updateForm(LambdaForm newForm) {
assert(newForm.customized == null || newForm.customized == this);
if (form == newForm) return; if (form == newForm) return;
newForm.prepare(); // as in MethodHandle.<init> newForm.prepare(); // as in MethodHandle.<init>
UNSAFE.putObject(this, FORM_OFFSET, newForm); UNSAFE.putObject(this, FORM_OFFSET, newForm);
UNSAFE.fullFence(); 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; private static final long FORM_OFFSET;
static { static {
try { try {
......
...@@ -597,6 +597,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -597,6 +597,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static final NamedFunction NF_checkSpreadArgument; static final NamedFunction NF_checkSpreadArgument;
static final NamedFunction NF_guardWithCatch; static final NamedFunction NF_guardWithCatch;
static final NamedFunction NF_throwException; static final NamedFunction NF_throwException;
static final NamedFunction NF_profileBoolean;
static final MethodHandle MH_castReference; static final MethodHandle MH_castReference;
static final MethodHandle MH_selectAlternative; static final MethodHandle MH_selectAlternative;
...@@ -614,10 +615,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -614,10 +615,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class, NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
MethodHandle.class, Object[].class)); MethodHandle.class, Object[].class));
NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.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_checkSpreadArgument.resolve();
NF_guardWithCatch.resolve(); NF_guardWithCatch.resolve();
NF_throwException.resolve(); NF_throwException.resolve();
NF_profileBoolean.resolve();
MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference", MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference",
MethodType.methodType(Object.class, Class.class, Object.class)); MethodType.methodType(Object.class, Class.class, Object.class));
...@@ -697,7 +700,26 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -697,7 +700,26 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
@LambdaForm.Hidden @LambdaForm.Hidden
static static
MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) { 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 static
...@@ -708,13 +730,18 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -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)); assert(test.type().equals(type.changeReturnType(boolean.class)) && fallback.type().equals(type));
MethodType basicType = type.basicType(); MethodType basicType = type.basicType();
LambdaForm form = makeGuardWithTestForm(basicType); LambdaForm form = makeGuardWithTestForm(basicType);
BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL();
BoundMethodHandle mh; BoundMethodHandle mh;
try { try {
mh = (BoundMethodHandle) if (PROFILE_GWT) {
data.constructor().invokeBasic(type, form, int[] counts = new int[2];
(Object) test, (Object) profile(target), (Object) profile(fallback)); 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) { } catch (Throwable ex) {
throw uncaughtException(ex); throw uncaughtException(ex);
} }
...@@ -800,7 +827,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -800,7 +827,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle wrapper; MethodHandle wrapper;
if (isCounting) { if (isCounting) {
LambdaForm lform; LambdaForm lform;
lform = countingFormProducer.apply(target); lform = countingFormProducer.apply(newTarget);
wrapper = new CountingWrapper(newTarget, lform, countingFormProducer, nonCountingFormProducer, DONT_INLINE_THRESHOLD); wrapper = new CountingWrapper(newTarget, lform, countingFormProducer, nonCountingFormProducer, DONT_INLINE_THRESHOLD);
} else { } else {
wrapper = newTarget; // no need for a counting wrapper anymore wrapper = newTarget; // no need for a counting wrapper anymore
...@@ -856,7 +883,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -856,7 +883,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
final int GET_TEST = nameCursor++; final int GET_TEST = nameCursor++;
final int GET_TARGET = nameCursor++; final int GET_TARGET = nameCursor++;
final int GET_FALLBACK = nameCursor++; final int GET_FALLBACK = nameCursor++;
final int GET_COUNTERS = PROFILE_GWT ? nameCursor++ : -1;
final int CALL_TEST = nameCursor++; 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 SELECT_ALT = nameCursor++;
final int CALL_TARGET = nameCursor++; final int CALL_TARGET = nameCursor++;
assert(CALL_TARGET == SELECT_ALT+1); // must be true to trigger IBG.emitSelectAlternative 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; ...@@ -864,12 +894,16 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodType lambdaType = basicType.invokerType(); MethodType lambdaType = basicType.invokerType();
Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType); 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[THIS_MH] = names[THIS_MH].withConstraint(data);
names[GET_TEST] = new Name(data.getterFunction(0), names[THIS_MH]); names[GET_TEST] = new Name(data.getterFunction(0), names[THIS_MH]);
names[GET_TARGET] = new Name(data.getterFunction(1), 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]); 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); Object[] invokeArgs = Arrays.copyOfRange(names, 0, ARG_LIMIT, Object[].class);
// call test // call test
...@@ -877,15 +911,18 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -877,15 +911,18 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
invokeArgs[0] = names[GET_TEST]; invokeArgs[0] = names[GET_TEST];
names[CALL_TEST] = new Name(testType, invokeArgs); 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 // call selectAlternative
names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[CALL_TEST], names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[TEST], names[GET_TARGET], names[GET_FALLBACK]);
names[GET_TARGET], names[GET_FALLBACK]);
// call target or fallback // call target or fallback
invokeArgs[0] = names[SELECT_ALT]; invokeArgs[0] = names[SELECT_ALT];
names[CALL_TARGET] = new Name(basicType, invokeArgs); 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); return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform);
} }
...@@ -1615,4 +1652,13 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -1615,4 +1652,13 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
assert(elemType.isPrimitive()); assert(elemType.isPrimitive());
return Lazy.MH_copyAsPrimitiveArray.bindTo(Wrapper.forPrimitiveType(elemType)); 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);
}
}
} }
...@@ -48,9 +48,11 @@ import sun.misc.Unsafe; ...@@ -48,9 +48,11 @@ import sun.misc.Unsafe;
static final int COMPILE_THRESHOLD; static final int COMPILE_THRESHOLD;
static final int DONT_INLINE_THRESHOLD; static final int DONT_INLINE_THRESHOLD;
static final int PROFILE_LEVEL; static final int PROFILE_LEVEL;
static final boolean PROFILE_GWT;
static final int CUSTOMIZE_THRESHOLD;
static { static {
final Object[] values = new Object[7]; final Object[] values = new Object[9];
AccessController.doPrivileged(new PrivilegedAction<Void>() { AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() { public Void run() {
values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES"); values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
...@@ -60,6 +62,8 @@ import sun.misc.Unsafe; ...@@ -60,6 +62,8 @@ import sun.misc.Unsafe;
values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 0); values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 0);
values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", 30); values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", 30);
values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0); 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; return null;
} }
}); });
...@@ -70,6 +74,12 @@ import sun.misc.Unsafe; ...@@ -70,6 +74,12 @@ import sun.misc.Unsafe;
COMPILE_THRESHOLD = (Integer) values[4]; COMPILE_THRESHOLD = (Integer) values[4];
DONT_INLINE_THRESHOLD = (Integer) values[5]; DONT_INLINE_THRESHOLD = (Integer) values[5];
PROFILE_LEVEL = (Integer) values[6]; 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. /** Tell if any of the debugging switches are turned on.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册