Merge
This commit is contained in:
commit
75a181784a
@ -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;
|
||||
@ -693,4 +692,10 @@ class DirectMethodHandle extends MethodHandle {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void customize() {
|
||||
assert(form.customized == null);
|
||||
// No need to customize DMHs.
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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.<init>
|
||||
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 {
|
||||
|
@ -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);
|
||||
}
|
||||
@ -726,7 +753,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
static
|
||||
MethodHandle profile(MethodHandle target) {
|
||||
if (DONT_INLINE_THRESHOLD >= 0) {
|
||||
return makeBlockInlningWrapper(target);
|
||||
return makeBlockInliningWrapper(target);
|
||||
} else {
|
||||
return target;
|
||||
}
|
||||
@ -737,8 +764,13 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
* Corresponding LambdaForm has @DontInline when compiled into bytecode.
|
||||
*/
|
||||
static
|
||||
MethodHandle makeBlockInlningWrapper(MethodHandle target) {
|
||||
LambdaForm lform = PRODUCE_BLOCK_INLINING_FORM.apply(target);
|
||||
MethodHandle makeBlockInliningWrapper(MethodHandle target) {
|
||||
LambdaForm lform;
|
||||
if (DONT_INLINE_THRESHOLD > 0) {
|
||||
lform = PRODUCE_BLOCK_INLINING_FORM.apply(target);
|
||||
} else {
|
||||
lform = PRODUCE_REINVOKER_FORM.apply(target);
|
||||
}
|
||||
return new CountingWrapper(target, lform,
|
||||
PRODUCE_BLOCK_INLINING_FORM, PRODUCE_REINVOKER_FORM,
|
||||
DONT_INLINE_THRESHOLD);
|
||||
@ -800,7 +832,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
|
||||
@ -809,7 +841,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
}
|
||||
|
||||
boolean countDown() {
|
||||
if (count <= 0) {
|
||||
int c = count;
|
||||
if (c <= 1) {
|
||||
// Try to limit number of updates. MethodHandle.updateForm() doesn't guarantee LF update visibility.
|
||||
if (isCounting) {
|
||||
isCounting = false;
|
||||
@ -818,7 +851,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
--count;
|
||||
count = c - 1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -856,7 +889,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 +900,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 +917,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);
|
||||
}
|
||||
@ -1629,4 +1672,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Void>() {
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user