提交 5526a0ac 编写于 作者: V vlivanov

8059877: GWT branch frequencies pollution due to LF sharing

Reviewed-by: psandoz, jrose
上级 99975b6d
...@@ -44,6 +44,10 @@ abstract class DelegatingMethodHandle extends MethodHandle { ...@@ -44,6 +44,10 @@ abstract class DelegatingMethodHandle extends MethodHandle {
super(type, chooseDelegatingForm(target)); super(type, chooseDelegatingForm(target));
} }
protected DelegatingMethodHandle(MethodType type, LambdaForm form) {
super(type, form);
}
/** Define this to extract the delegated target which supplies the invocation behavior. */ /** Define this to extract the delegated target which supplies the invocation behavior. */
abstract protected MethodHandle getTarget(); abstract protected MethodHandle getTarget();
...@@ -88,14 +92,31 @@ abstract class DelegatingMethodHandle extends MethodHandle { ...@@ -88,14 +92,31 @@ abstract class DelegatingMethodHandle extends MethodHandle {
return makeReinvokerForm(target, MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, NF_getTarget); return makeReinvokerForm(target, MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, NF_getTarget);
} }
/** Create a LF which simply reinvokes a target of the given basic type. */
static LambdaForm makeReinvokerForm(MethodHandle target, static LambdaForm makeReinvokerForm(MethodHandle target,
int whichCache, int whichCache,
Object constraint, Object constraint,
NamedFunction getTargetFn) { NamedFunction getTargetFn) {
String debugString;
switch(whichCache) {
case MethodTypeForm.LF_REBIND: debugString = "BMH.reinvoke"; break;
case MethodTypeForm.LF_DELEGATE: debugString = "MH.delegate"; break;
default: debugString = "MH.reinvoke"; break;
}
// No pre-action needed.
return makeReinvokerForm(target, whichCache, constraint, debugString, true, getTargetFn, null);
}
/** Create a LF which simply reinvokes a target of the given basic type. */
static LambdaForm makeReinvokerForm(MethodHandle target,
int whichCache,
Object constraint,
String debugString,
boolean forceInline,
NamedFunction getTargetFn,
NamedFunction preActionFn) {
MethodType mtype = target.type().basicType(); MethodType mtype = target.type().basicType();
boolean customized = (whichCache < 0 || boolean customized = (whichCache < 0 ||
mtype.parameterSlotCount() > MethodType.MAX_MH_INVOKER_ARITY); mtype.parameterSlotCount() > MethodType.MAX_MH_INVOKER_ARITY);
boolean hasPreAction = (preActionFn != null);
LambdaForm form; LambdaForm form;
if (!customized) { if (!customized) {
form = mtype.form().cachedLambdaForm(whichCache); form = mtype.form().cachedLambdaForm(whichCache);
...@@ -105,12 +126,16 @@ abstract class DelegatingMethodHandle extends MethodHandle { ...@@ -105,12 +126,16 @@ abstract class DelegatingMethodHandle extends MethodHandle {
final int ARG_BASE = 1; final int ARG_BASE = 1;
final int ARG_LIMIT = ARG_BASE + mtype.parameterCount(); final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
int nameCursor = ARG_LIMIT; int nameCursor = ARG_LIMIT;
final int PRE_ACTION = hasPreAction ? nameCursor++ : -1;
final int NEXT_MH = customized ? -1 : nameCursor++; final int NEXT_MH = customized ? -1 : nameCursor++;
final int REINVOKE = nameCursor++; final int REINVOKE = nameCursor++;
LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType()); LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
assert(names.length == nameCursor); assert(names.length == nameCursor);
names[THIS_DMH] = names[THIS_DMH].withConstraint(constraint); names[THIS_DMH] = names[THIS_DMH].withConstraint(constraint);
Object[] targetArgs; Object[] targetArgs;
if (hasPreAction) {
names[PRE_ACTION] = new LambdaForm.Name(preActionFn, names[THIS_DMH]);
}
if (customized) { if (customized) {
targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class); targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class);
names[REINVOKE] = new LambdaForm.Name(target, targetArgs); // the invoker is the target itself names[REINVOKE] = new LambdaForm.Name(target, targetArgs); // the invoker is the target itself
...@@ -120,20 +145,14 @@ abstract class DelegatingMethodHandle extends MethodHandle { ...@@ -120,20 +145,14 @@ abstract class DelegatingMethodHandle extends MethodHandle {
targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH
names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs); names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs);
} }
String debugString; form = new LambdaForm(debugString, ARG_LIMIT, names, forceInline);
switch(whichCache) {
case MethodTypeForm.LF_REBIND: debugString = "BMH.reinvoke"; break;
case MethodTypeForm.LF_DELEGATE: debugString = "MH.delegate"; break;
default: debugString = "MH.reinvoke"; break;
}
form = new LambdaForm(debugString, ARG_LIMIT, names);
if (!customized) { if (!customized) {
form = mtype.form().setCachedLambdaForm(whichCache, form); form = mtype.form().setCachedLambdaForm(whichCache, form);
} }
return form; return form;
} }
private static final NamedFunction NF_getTarget; static final NamedFunction NF_getTarget;
static { static {
try { try {
NF_getTarget = new NamedFunction(DelegatingMethodHandle.class NF_getTarget = new NamedFunction(DelegatingMethodHandle.class
......
...@@ -628,8 +628,13 @@ class InvokerBytecodeGenerator { ...@@ -628,8 +628,13 @@ class InvokerBytecodeGenerator {
// Mark this method as a compiled LambdaForm // Mark this method as a compiled LambdaForm
mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Compiled;", true); mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Compiled;", true);
// Force inlining of this invoker method. if (lambdaForm.forceInline) {
mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true); // Force inlining of this invoker method.
mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
} else {
mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
}
// 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
......
...@@ -119,6 +119,7 @@ import static java.lang.invoke.MethodHandleNatives.Constants.*; ...@@ -119,6 +119,7 @@ import static java.lang.invoke.MethodHandleNatives.Constants.*;
class LambdaForm { class LambdaForm {
final int arity; final int arity;
final int result; final int result;
final boolean forceInline;
@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
...@@ -243,11 +244,16 @@ class LambdaForm { ...@@ -243,11 +244,16 @@ 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);
}
LambdaForm(String debugName,
int arity, Name[] names, int result, boolean forceInline) {
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;
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.
...@@ -255,17 +261,23 @@ class LambdaForm { ...@@ -255,17 +261,23 @@ class LambdaForm {
compileToBytecode(); compileToBytecode();
} }
} }
LambdaForm(String debugName, LambdaForm(String debugName,
int arity, Name[] names) { int arity, Name[] names) {
this(debugName, this(debugName, arity, names, LAST_RESULT, true);
arity, names, LAST_RESULT); }
LambdaForm(String debugName,
int arity, Name[] names, boolean forceInline) {
this(debugName, arity, names, LAST_RESULT, forceInline);
} }
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); formals.length, buildNames(formals, temps, result), LAST_RESULT, true);
}
LambdaForm(String debugName,
Name[] formals, Name[] temps, Name result, boolean forceInline) {
this(debugName,
formals.length, buildNames(formals, temps, result), LAST_RESULT, forceInline);
} }
private static Name[] buildNames(Name[] formals, Name[] temps, Name result) { private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
...@@ -279,6 +291,10 @@ class LambdaForm { ...@@ -279,6 +291,10 @@ 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.
...@@ -287,6 +303,7 @@ class LambdaForm { ...@@ -287,6 +303,7 @@ 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;
assert(nameRefsAreLegal()); assert(nameRefsAreLegal());
assert(isEmpty()); assert(isEmpty());
assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature(); assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
......
...@@ -1438,10 +1438,9 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); ...@@ -1438,10 +1438,9 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
/*non-public*/ /*non-public*/
void updateForm(LambdaForm newForm) { void updateForm(LambdaForm newForm) {
if (form == newForm) return; if (form == newForm) return;
assert(this instanceof DirectMethodHandle && this.internalMemberName().isStatic()); newForm.prepare(); // as in MethodHandle.<init>
// ISSUE: Should we have a memory fence here?
UNSAFE.putObject(this, FORM_OFFSET, newForm); UNSAFE.putObject(this, FORM_OFFSET, newForm);
this.form.prepare(); // as in MethodHandle.<init> UNSAFE.fullFence();
} }
private static final long FORM_OFFSET; private static final long FORM_OFFSET;
......
...@@ -30,6 +30,7 @@ import java.security.PrivilegedAction; ...@@ -30,6 +30,7 @@ import java.security.PrivilegedAction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.function.Function;
import sun.invoke.empty.Empty; import sun.invoke.empty.Empty;
import sun.invoke.util.ValueConversions; import sun.invoke.util.ValueConversions;
...@@ -713,10 +714,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -713,10 +714,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
LambdaForm form = makeGuardWithTestForm(basicType); LambdaForm form = makeGuardWithTestForm(basicType);
BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL(); BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL();
BoundMethodHandle mh; BoundMethodHandle mh;
try { try {
mh = (BoundMethodHandle) mh = (BoundMethodHandle)
data.constructor().invokeBasic(type, form, data.constructor().invokeBasic(type, form,
(Object) test, (Object) target, (Object) fallback); (Object) test, (Object) profile(target), (Object) profile(fallback));
} catch (Throwable ex) { } catch (Throwable ex) {
throw uncaughtException(ex); throw uncaughtException(ex);
} }
...@@ -724,6 +726,129 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -724,6 +726,129 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return mh; return mh;
} }
static
MethodHandle profile(MethodHandle target) {
if (DONT_INLINE_THRESHOLD >= 0) {
return makeBlockInlningWrapper(target);
} else {
return target;
}
}
/**
* Block inlining during JIT-compilation of a target method handle if it hasn't been invoked enough times.
* Corresponding LambdaForm has @DontInline when compiled into bytecode.
*/
static
MethodHandle makeBlockInlningWrapper(MethodHandle target) {
LambdaForm lform = PRODUCE_BLOCK_INLINING_FORM.apply(target);
return new CountingWrapper(target, lform,
PRODUCE_BLOCK_INLINING_FORM, PRODUCE_REINVOKER_FORM,
DONT_INLINE_THRESHOLD);
}
/** Constructs reinvoker lambda form which block inlining during JIT-compilation for a particular method handle */
private static final Function<MethodHandle, LambdaForm> PRODUCE_BLOCK_INLINING_FORM = new Function<MethodHandle, LambdaForm>() {
@Override
public LambdaForm apply(MethodHandle target) {
return DelegatingMethodHandle.makeReinvokerForm(target,
MethodTypeForm.LF_DELEGATE_BLOCK_INLINING, CountingWrapper.class, "reinvoker.dontInline", false,
DelegatingMethodHandle.NF_getTarget, CountingWrapper.NF_maybeStopCounting);
}
};
/** Constructs simple reinvoker lambda form for a particular method handle */
private static final Function<MethodHandle, LambdaForm> PRODUCE_REINVOKER_FORM = new Function<MethodHandle, LambdaForm>() {
@Override
public LambdaForm apply(MethodHandle target) {
return DelegatingMethodHandle.makeReinvokerForm(target,
MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, DelegatingMethodHandle.NF_getTarget);
}
};
/**
* Counting method handle. It has 2 states: counting and non-counting.
* It is in counting state for the first n invocations and then transitions to non-counting state.
* Behavior in counting and non-counting states is determined by lambda forms produced by
* countingFormProducer & nonCountingFormProducer respectively.
*/
static class CountingWrapper extends DelegatingMethodHandle {
private final MethodHandle target;
private int count;
private Function<MethodHandle, LambdaForm> countingFormProducer;
private Function<MethodHandle, LambdaForm> nonCountingFormProducer;
private volatile boolean isCounting;
private CountingWrapper(MethodHandle target, LambdaForm lform,
Function<MethodHandle, LambdaForm> countingFromProducer,
Function<MethodHandle, LambdaForm> nonCountingFormProducer,
int count) {
super(target.type(), lform);
this.target = target;
this.count = count;
this.countingFormProducer = countingFromProducer;
this.nonCountingFormProducer = nonCountingFormProducer;
this.isCounting = (count > 0);
}
@Hidden
@Override
protected MethodHandle getTarget() {
return target;
}
@Override
public MethodHandle asTypeUncached(MethodType newType) {
MethodHandle newTarget = target.asType(newType);
MethodHandle wrapper;
if (isCounting) {
LambdaForm lform;
lform = countingFormProducer.apply(target);
wrapper = new CountingWrapper(newTarget, lform, countingFormProducer, nonCountingFormProducer, DONT_INLINE_THRESHOLD);
} else {
wrapper = newTarget; // no need for a counting wrapper anymore
}
return (asTypeCache = wrapper);
}
boolean countDown() {
if (count <= 0) {
// Try to limit number of updates. MethodHandle.updateForm() doesn't guarantee LF update visibility.
if (isCounting) {
isCounting = false;
return true;
} else {
return false;
}
} else {
--count;
return false;
}
}
@Hidden
static void maybeStopCounting(Object o1) {
CountingWrapper wrapper = (CountingWrapper) o1;
if (wrapper.countDown()) {
// Reached invocation threshold. Replace counting behavior with a non-counting one.
LambdaForm lform = wrapper.nonCountingFormProducer.apply(wrapper.target);
lform.compileToBytecode(); // speed up warmup by avoiding LF interpretation again after transition
wrapper.updateForm(lform);
}
}
static final NamedFunction NF_maybeStopCounting;
static {
Class<?> THIS_CLASS = CountingWrapper.class;
try {
NF_maybeStopCounting = new NamedFunction(THIS_CLASS.getDeclaredMethod("maybeStopCounting", Object.class));
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
}
}
static static
LambdaForm makeGuardWithTestForm(MethodType basicType) { LambdaForm makeGuardWithTestForm(MethodType basicType) {
LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWT); LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWT);
......
...@@ -47,10 +47,11 @@ import sun.misc.Unsafe; ...@@ -47,10 +47,11 @@ import sun.misc.Unsafe;
static final boolean TRACE_METHOD_LINKAGE; static final boolean TRACE_METHOD_LINKAGE;
static final boolean USE_LAMBDA_FORM_EDITOR; static final boolean USE_LAMBDA_FORM_EDITOR;
static final int COMPILE_THRESHOLD; static final int COMPILE_THRESHOLD;
static final int DONT_INLINE_THRESHOLD;
static final int PROFILE_LEVEL; static final int PROFILE_LEVEL;
static { static {
final Object[] values = { false, false, false, false, false, null, null }; final Object[] values = new Object[8];
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");
...@@ -59,7 +60,8 @@ import sun.misc.Unsafe; ...@@ -59,7 +60,8 @@ import sun.misc.Unsafe;
values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE"); values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
values[4] = Boolean.getBoolean("java.lang.invoke.MethodHandle.USE_LF_EDITOR"); values[4] = Boolean.getBoolean("java.lang.invoke.MethodHandle.USE_LF_EDITOR");
values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 30); values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 30);
values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0); values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", 30);
values[7] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
return null; return null;
} }
}); });
...@@ -69,7 +71,8 @@ import sun.misc.Unsafe; ...@@ -69,7 +71,8 @@ import sun.misc.Unsafe;
TRACE_METHOD_LINKAGE = (Boolean) values[3]; TRACE_METHOD_LINKAGE = (Boolean) values[3];
USE_LAMBDA_FORM_EDITOR = (Boolean) values[4]; USE_LAMBDA_FORM_EDITOR = (Boolean) values[4];
COMPILE_THRESHOLD = (Integer) values[5]; COMPILE_THRESHOLD = (Integer) values[5];
PROFILE_LEVEL = (Integer) values[6]; DONT_INLINE_THRESHOLD = (Integer) values[6];
PROFILE_LEVEL = (Integer) values[7];
} }
/** Tell if any of the debugging switches are turned on. /** Tell if any of the debugging switches are turned on.
......
...@@ -63,24 +63,25 @@ final class MethodTypeForm { ...@@ -63,24 +63,25 @@ final class MethodTypeForm {
final @Stable LambdaForm[] lambdaForms; final @Stable LambdaForm[] lambdaForms;
// Indexes into lambdaForms: // Indexes into lambdaForms:
static final int static final int
LF_INVVIRTUAL = 0, // DMH invokeVirtual LF_INVVIRTUAL = 0, // DMH invokeVirtual
LF_INVSTATIC = 1, LF_INVSTATIC = 1,
LF_INVSPECIAL = 2, LF_INVSPECIAL = 2,
LF_NEWINVSPECIAL = 3, LF_NEWINVSPECIAL = 3,
LF_INVINTERFACE = 4, LF_INVINTERFACE = 4,
LF_INVSTATIC_INIT = 5, // DMH invokeStatic with <clinit> barrier LF_INVSTATIC_INIT = 5, // DMH invokeStatic with <clinit> barrier
LF_INTERPRET = 6, // LF interpreter LF_INTERPRET = 6, // LF interpreter
LF_REBIND = 7, // BoundMethodHandle LF_REBIND = 7, // BoundMethodHandle
LF_DELEGATE = 8, // DelegatingMethodHandle LF_DELEGATE = 8, // DelegatingMethodHandle
LF_EX_LINKER = 9, // invokeExact_MT (for invokehandle) LF_DELEGATE_BLOCK_INLINING = 9, // Counting DelegatingMethodHandle w/ @DontInline
LF_EX_INVOKER = 10, // MHs.invokeExact LF_EX_LINKER = 10, // invokeExact_MT (for invokehandle)
LF_GEN_LINKER = 11, // generic invoke_MT (for invokehandle) LF_EX_INVOKER = 11, // MHs.invokeExact
LF_GEN_INVOKER = 12, // generic MHs.invoke LF_GEN_LINKER = 12, // generic invoke_MT (for invokehandle)
LF_CS_LINKER = 13, // linkToCallSite_CS LF_GEN_INVOKER = 13, // generic MHs.invoke
LF_MH_LINKER = 14, // linkToCallSite_MH LF_CS_LINKER = 14, // linkToCallSite_CS
LF_GWC = 15, // guardWithCatch (catchException) LF_MH_LINKER = 15, // linkToCallSite_MH
LF_GWT = 16, // guardWithTest LF_GWC = 16, // guardWithCatch (catchException)
LF_LIMIT = 17; LF_GWT = 17, // guardWithTest
LF_LIMIT = 18;
/** Return the type corresponding uniquely (1-1) to this MT-form. /** Return the type corresponding uniquely (1-1) to this MT-form.
* It might have any primitive returns or arguments, but will have no references except Object. * It might have any primitive returns or arguments, but will have no references except Object.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册