提交 6be16bf0 编写于 作者: V vlivanov

8050053: Improve caching of different invokers

Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
上级 fbfd2d29
...@@ -102,7 +102,7 @@ public class CallSite { ...@@ -102,7 +102,7 @@ public class CallSite {
*/ */
/*package-private*/ /*package-private*/
CallSite(MethodType type) { CallSite(MethodType type) {
target = type.invokers().uninitializedCallSite(); target = makeUninitializedCallSite(type);
} }
/** /**
...@@ -217,21 +217,34 @@ public class CallSite { ...@@ -217,21 +217,34 @@ public class CallSite {
} }
private static final MethodHandle GET_TARGET; private static final MethodHandle GET_TARGET;
private static final MethodHandle THROW_UCS;
static { static {
try { try {
GET_TARGET = IMPL_LOOKUP. GET_TARGET = IMPL_LOOKUP.
findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class)); findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
THROW_UCS = IMPL_LOOKUP.
findStatic(CallSite.class, "uninitializedCallSite", MethodType.methodType(Object.class, Object[].class));
} catch (ReflectiveOperationException e) { } catch (ReflectiveOperationException e) {
throw newInternalError(e); throw newInternalError(e);
} }
} }
/** This guy is rolled into the default target if a MethodType is supplied to the constructor. */ /** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
/*package-private*/ private static Object uninitializedCallSite(Object... ignore) {
static Empty uninitializedCallSite() {
throw new IllegalStateException("uninitialized call site"); throw new IllegalStateException("uninitialized call site");
} }
private MethodHandle makeUninitializedCallSite(MethodType targetType) {
MethodType basicType = targetType.basicType();
MethodHandle invoker = basicType.form().cachedMethodHandle(MethodTypeForm.MH_UNINIT_CS);
if (invoker == null) {
invoker = THROW_UCS.asType(basicType);
invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_UNINIT_CS, invoker);
}
// unchecked view is OK since no values will be received or returned
return invoker.viewAsType(targetType);
}
// unsafe stuff: // unsafe stuff:
private static final long TARGET_OFFSET; private static final long TARGET_OFFSET;
static { static {
......
...@@ -25,8 +25,9 @@ ...@@ -25,8 +25,9 @@
package java.lang.invoke; package java.lang.invoke;
import java.lang.reflect.Array;
import java.util.Arrays; import java.util.Arrays;
import sun.invoke.empty.Empty;
import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
...@@ -40,52 +41,63 @@ class Invokers { ...@@ -40,52 +41,63 @@ class Invokers {
// exact type (sans leading taget MH) for the outgoing call // exact type (sans leading taget MH) for the outgoing call
private final MethodType targetType; private final MethodType targetType;
// FIXME: Get rid of the invokers that are not useful. // Cached adapter information:
private final @Stable MethodHandle[] invokers = new MethodHandle[INV_LIMIT];
// exact invoker for the outgoing call // Indexes into invokers:
private /*lazy*/ MethodHandle exactInvoker; static final int
private /*lazy*/ MethodHandle basicInvoker; // invokeBasic (unchecked exact) INV_EXACT = 0, // MethodHandles.exactInvoker
INV_GENERIC = 1, // MethodHandles.invoker (generic invocation)
// erased (partially untyped but with primitives) invoker for the outgoing call INV_BASIC = 2, // MethodHandles.basicInvoker
// FIXME: get rid of INV_LIMIT = 3;
private /*lazy*/ MethodHandle erasedInvoker;
// FIXME: get rid of
/*lazy*/ MethodHandle erasedInvokerWithDrops; // for InvokeGeneric
// general invoker for the outgoing call
private /*lazy*/ MethodHandle generalInvoker;
// general invoker for the outgoing call, uses varargs
private /*lazy*/ MethodHandle varargsInvoker;
// general invoker for the outgoing call; accepts a trailing Object[]
private final /*lazy*/ MethodHandle[] spreadInvokers;
// invoker for an unbound callsite
private /*lazy*/ MethodHandle uninitializedCallSite;
/** Compute and cache information common to all collecting adapters /** Compute and cache information common to all collecting adapters
* that implement members of the erasure-family of the given erased type. * that implement members of the erasure-family of the given erased type.
*/ */
/*non-public*/ Invokers(MethodType targetType) { /*non-public*/ Invokers(MethodType targetType) {
this.targetType = targetType; this.targetType = targetType;
this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
} }
/*non-public*/ MethodHandle exactInvoker() { /*non-public*/ MethodHandle exactInvoker() {
MethodHandle invoker = exactInvoker; MethodHandle invoker = cachedInvoker(INV_EXACT);
if (invoker != null) return invoker; if (invoker != null) return invoker;
invoker = makeExactOrGeneralInvoker(true); invoker = makeExactOrGeneralInvoker(true);
exactInvoker = invoker; return setCachedInvoker(INV_EXACT, invoker);
return invoker;
} }
/*non-public*/ MethodHandle generalInvoker() { /*non-public*/ MethodHandle genericInvoker() {
MethodHandle invoker = generalInvoker; MethodHandle invoker = cachedInvoker(INV_GENERIC);
if (invoker != null) return invoker; if (invoker != null) return invoker;
invoker = makeExactOrGeneralInvoker(false); invoker = makeExactOrGeneralInvoker(false);
generalInvoker = invoker; return setCachedInvoker(INV_GENERIC, invoker);
return invoker; }
/*non-public*/ MethodHandle basicInvoker() {
MethodHandle invoker = cachedInvoker(INV_BASIC);
if (invoker != null) return invoker;
MethodType basicType = targetType.basicType();
if (basicType != targetType) {
// double cache; not used significantly
return setCachedInvoker(INV_BASIC, basicType.invokers().basicInvoker());
}
invoker = basicType.form().cachedMethodHandle(MethodTypeForm.MH_BASIC_INV);
if (invoker == null) {
MemberName method = invokeBasicMethod(basicType);
invoker = DirectMethodHandle.make(method);
assert(checkInvoker(invoker));
invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_BASIC_INV, invoker);
}
return setCachedInvoker(INV_BASIC, invoker);
}
private MethodHandle cachedInvoker(int idx) {
return invokers[idx];
}
private synchronized MethodHandle setCachedInvoker(int idx, final MethodHandle invoker) {
// Simulate a CAS, to avoid racy duplication of results.
MethodHandle prev = invokers[idx];
if (prev != null) return prev;
return invokers[idx] = invoker;
} }
private MethodHandle makeExactOrGeneralInvoker(boolean isExact) { private MethodHandle makeExactOrGeneralInvoker(boolean isExact) {
...@@ -110,21 +122,6 @@ class Invokers { ...@@ -110,21 +122,6 @@ class Invokers {
} }
} }
/*non-public*/ MethodHandle basicInvoker() {
MethodHandle invoker = basicInvoker;
if (invoker != null) return invoker;
MethodType basicType = targetType.basicType();
if (basicType != targetType) {
// double cache; not used significantly
return basicInvoker = basicType.invokers().basicInvoker();
}
MemberName method = invokeBasicMethod(basicType);
invoker = DirectMethodHandle.make(method);
assert(checkInvoker(invoker));
basicInvoker = invoker;
return invoker;
}
// This next one is called from LambdaForm.NamedFunction.<init>. // This next one is called from LambdaForm.NamedFunction.<init>.
/*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) { /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
assert(basicType == basicType.basicType()); assert(basicType == basicType.basicType());
...@@ -145,87 +142,42 @@ class Invokers { ...@@ -145,87 +142,42 @@ class Invokers {
return true; return true;
} }
// FIXME: get rid of /**
/*non-public*/ MethodHandle erasedInvoker() { * Find or create an invoker which passes unchanged a given number of arguments
MethodHandle xinvoker = exactInvoker(); * and spreads the rest from a trailing array argument.
MethodHandle invoker = erasedInvoker; * The invoker target type is the post-spread type {@code (TYPEOF(uarg*), TYPEOF(sarg*))=>RT}.
if (invoker != null) return invoker; * All the {@code sarg}s must have a common type {@code C}. (If there are none, {@code Object} is assumed.}
MethodType erasedType = targetType.erase(); * @param leadingArgCount the number of unchanged (non-spread) arguments
invoker = xinvoker.asType(erasedType.invokerType()); * @return {@code invoker.invokeExact(mh, uarg*, C[]{sarg*}) := (RT)mh.invoke(uarg*, sarg*)}
erasedInvoker = invoker; */
return invoker;
}
/*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) { /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
MethodHandle vaInvoker = spreadInvokers[leadingArgCount];
if (vaInvoker != null) return vaInvoker;
int spreadArgCount = targetType.parameterCount() - leadingArgCount; int spreadArgCount = targetType.parameterCount() - leadingArgCount;
MethodType spreadInvokerType = targetType MethodType postSpreadType = targetType;
.replaceParameterTypes(leadingArgCount, targetType.parameterCount(), Object[].class); Class<?> argArrayType = impliedRestargType(postSpreadType, leadingArgCount);
if (targetType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) { if (postSpreadType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) {
// Factor sinvoker.invoke(mh, a) into ginvoker.asSpreader().invoke(mh, a) return genericInvoker().asSpreader(argArrayType, spreadArgCount);
// where ginvoker.invoke(mh, a*) => mh.invoke(a*).
MethodHandle genInvoker = generalInvoker();
vaInvoker = genInvoker.asSpreader(Object[].class, spreadArgCount);
} else {
// Cannot build a general invoker here of type ginvoker.invoke(mh, a*[254]).
// Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a)
// where filter(mh) == mh.asSpreader(Object[], spreadArgCount)
MethodHandle arrayInvoker = MethodHandles.exactInvoker(spreadInvokerType);
MethodHandle makeSpreader;
try {
makeSpreader = IMPL_LOOKUP
.findVirtual(MethodHandle.class, "asSpreader",
MethodType.methodType(MethodHandle.class, Class.class, int.class));
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
makeSpreader = MethodHandles.insertArguments(makeSpreader, 1, Object[].class, spreadArgCount);
vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
} }
assert(vaInvoker.type().equals(spreadInvokerType.invokerType())); // Cannot build a generic invoker here of type ginvoker.invoke(mh, a*[254]).
maybeCompileToBytecode(vaInvoker); // Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a)
spreadInvokers[leadingArgCount] = vaInvoker; // where filter(mh) == mh.asSpreader(Object[], spreadArgCount)
return vaInvoker; MethodType preSpreadType = postSpreadType
.replaceParameterTypes(leadingArgCount, postSpreadType.parameterCount(), argArrayType);
MethodHandle arrayInvoker = MethodHandles.invoker(preSpreadType);
MethodHandle makeSpreader = MethodHandles.insertArguments(Lazy.MH_asSpreader, 1, argArrayType, spreadArgCount);
return MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
} }
/*non-public*/ MethodHandle varargsInvoker() { private static Class<?> impliedRestargType(MethodType restargType, int fromPos) {
MethodHandle vaInvoker = varargsInvoker; if (restargType.isGeneric()) return Object[].class; // can be nothing else
if (vaInvoker != null) return vaInvoker; int maxPos = restargType.parameterCount();
vaInvoker = spreadInvoker(0).asType(MethodType.genericMethodType(0, true).invokerType()); if (fromPos >= maxPos) return Object[].class; // reasonable default
varargsInvoker = vaInvoker; Class<?> argType = restargType.parameterType(fromPos);
return vaInvoker; for (int i = fromPos+1; i < maxPos; i++) {
} if (argType != restargType.parameterType(i))
throw newIllegalArgumentException("need homogeneous rest arguments", restargType);
private static MethodHandle THROW_UCS = null;
/*non-public*/ MethodHandle uninitializedCallSite() {
MethodHandle invoker = uninitializedCallSite;
if (invoker != null) return invoker;
if (targetType.parameterCount() > 0) {
MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount());
Invokers invokers0 = type0.invokers();
invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(),
0, targetType.parameterList());
assert(invoker.type().equals(targetType));
uninitializedCallSite = invoker;
return invoker;
} }
invoker = THROW_UCS; if (argType == Object.class) return Object[].class;
if (invoker == null) { return Array.newInstance(argType, 0).getClass();
try {
THROW_UCS = invoker = IMPL_LOOKUP
.findStatic(CallSite.class, "uninitializedCallSite",
MethodType.methodType(Empty.class));
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
}
invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType()));
invoker = invoker.dropArguments(targetType, 0, targetType.parameterCount());
assert(invoker.type().equals(targetType));
uninitializedCallSite = invoker;
return invoker;
} }
public String toString() { public String toString() {
...@@ -457,4 +409,16 @@ class Invokers { ...@@ -457,4 +409,16 @@ class Invokers {
} }
} }
private static class Lazy {
private static final MethodHandle MH_asSpreader;
static {
try {
MH_asSpreader = IMPL_LOOKUP.findVirtual(MethodHandle.class, "asSpreader",
MethodType.methodType(MethodHandle.class, Class.class, int.class));
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
}
}
} }
...@@ -1151,7 +1151,7 @@ class LambdaForm { ...@@ -1151,7 +1151,7 @@ class LambdaForm {
if (LambdaForm.signatureReturn(sig) == V_TYPE) if (LambdaForm.signatureReturn(sig) == V_TYPE)
srcType = srcType.changeReturnType(void.class); srcType = srcType.changeReturnType(void.class);
MethodTypeForm typeForm = srcType.form(); MethodTypeForm typeForm = srcType.form();
typeForm.namedFunctionInvoker = DirectMethodHandle.make(m); typeForm.setCachedMethodHandle(MethodTypeForm.MH_NF_INV, DirectMethodHandle.make(m));
} }
} }
} }
...@@ -1249,15 +1249,16 @@ class LambdaForm { ...@@ -1249,15 +1249,16 @@ class LambdaForm {
MethodType.methodType(Object.class, MethodHandle.class, Object[].class); MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
private static MethodHandle computeInvoker(MethodTypeForm typeForm) { private static MethodHandle computeInvoker(MethodTypeForm typeForm) {
MethodHandle mh = typeForm.namedFunctionInvoker; typeForm = typeForm.basicType().form(); // normalize to basic type
MethodHandle mh = typeForm.cachedMethodHandle(MethodTypeForm.MH_NF_INV);
if (mh != null) return mh; if (mh != null) return mh;
MemberName invoker = InvokerBytecodeGenerator.generateNamedFunctionInvoker(typeForm); // this could take a while MemberName invoker = InvokerBytecodeGenerator.generateNamedFunctionInvoker(typeForm); // this could take a while
mh = DirectMethodHandle.make(invoker); mh = DirectMethodHandle.make(invoker);
MethodHandle mh2 = typeForm.namedFunctionInvoker; MethodHandle mh2 = typeForm.cachedMethodHandle(MethodTypeForm.MH_NF_INV);
if (mh2 != null) return mh2; // benign race if (mh2 != null) return mh2; // benign race
if (!mh.type().equals(INVOKER_METHOD_TYPE)) if (!mh.type().equals(INVOKER_METHOD_TYPE))
throw newInternalError(mh.debugString()); throw newInternalError(mh.debugString());
return typeForm.namedFunctionInvoker = mh; return typeForm.setCachedMethodHandle(MethodTypeForm.MH_NF_INV, mh);
} }
@Hidden @Hidden
......
...@@ -624,15 +624,8 @@ public abstract class MethodHandle { ...@@ -624,15 +624,8 @@ public abstract class MethodHandle {
* @see MethodHandles#spreadInvoker * @see MethodHandles#spreadInvoker
*/ */
public Object invokeWithArguments(Object... arguments) throws Throwable { public Object invokeWithArguments(Object... arguments) throws Throwable {
int argc = arguments == null ? 0 : arguments.length; MethodType invocationType = MethodType.genericMethodType(arguments == null ? 0 : arguments.length);
@SuppressWarnings("LocalVariableHidesMemberVariable") return invocationType.invokers().spreadInvoker(0).invokeExact(asType(invocationType), arguments);
MethodType type = type();
if (type.parameterCount() != argc || isVarargsCollector()) {
// simulate invoke
return asType(MethodType.genericMethodType(argc)).invokeWithArguments(arguments);
}
MethodHandle invoker = type.invokers().varargsInvoker();
return invoker.invokeExact(this, arguments);
} }
/** /**
......
...@@ -1883,6 +1883,7 @@ return invoker; ...@@ -1883,6 +1883,7 @@ return invoker;
MethodHandle spreadInvoker(MethodType type, int leadingArgCount) { MethodHandle spreadInvoker(MethodType type, int leadingArgCount) {
if (leadingArgCount < 0 || leadingArgCount > type.parameterCount()) if (leadingArgCount < 0 || leadingArgCount > type.parameterCount())
throw newIllegalArgumentException("bad argument count", leadingArgCount); throw newIllegalArgumentException("bad argument count", leadingArgCount);
type = type.asSpreaderType(Object[].class, type.parameterCount() - leadingArgCount);
return type.invokers().spreadInvoker(leadingArgCount); return type.invokers().spreadInvoker(leadingArgCount);
} }
...@@ -1962,7 +1963,7 @@ return invoker; ...@@ -1962,7 +1963,7 @@ return invoker;
*/ */
static public static public
MethodHandle invoker(MethodType type) { MethodHandle invoker(MethodType type) {
return type.invokers().generalInvoker(); return type.invokers().genericInvoker();
} }
static /*non-public*/ static /*non-public*/
......
...@@ -466,6 +466,38 @@ class MethodType implements java.io.Serializable { ...@@ -466,6 +466,38 @@ class MethodType implements java.io.Serializable {
return dropParameterTypes(start, end).insertParameterTypes(start, ptypesToInsert); return dropParameterTypes(start, end).insertParameterTypes(start, ptypesToInsert);
} }
/** Replace the last arrayLength parameter types with the component type of arrayType.
* @param arrayType any array type
* @param arrayLength the number of parameter types to change
* @return the resulting type
*/
/*non-public*/ MethodType asSpreaderType(Class<?> arrayType, int arrayLength) {
assert(parameterCount() >= arrayLength);
int spreadPos = ptypes.length - arrayLength;
if (arrayLength == 0) return this; // nothing to change
if (arrayType == Object[].class) {
if (isGeneric()) return this; // nothing to change
if (spreadPos == 0) {
// no leading arguments to preserve; go generic
MethodType res = genericMethodType(arrayLength);
if (rtype != Object.class) {
res = res.changeReturnType(rtype);
}
return res;
}
}
Class<?> elemType = arrayType.getComponentType();
assert(elemType != null);
for (int i = spreadPos; i < ptypes.length; i++) {
if (ptypes[i] != elemType) {
Class<?>[] fixedPtypes = ptypes.clone();
Arrays.fill(fixedPtypes, i, ptypes.length, elemType);
return methodType(rtype, fixedPtypes);
}
}
return this; // arguments check out; no change
}
/** /**
* Finds or creates a method type with some parameter types omitted. * Finds or creates a method type with some parameter types omitted.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
...@@ -573,6 +605,10 @@ class MethodType implements java.io.Serializable { ...@@ -573,6 +605,10 @@ class MethodType implements java.io.Serializable {
return genericMethodType(parameterCount()); return genericMethodType(parameterCount());
} }
/*non-public*/ boolean isGeneric() {
return this == erase() && !hasPrimitives();
}
/** /**
* Converts all primitive types to their corresponding wrapper types. * Converts all primitive types to their corresponding wrapper types.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
......
...@@ -51,7 +51,13 @@ final class MethodTypeForm { ...@@ -51,7 +51,13 @@ final class MethodTypeForm {
final MethodType basicType; // the canonical erasure, with primitives simplified final MethodType basicType; // the canonical erasure, with primitives simplified
// Cached adapter information: // Cached adapter information:
@Stable MethodHandle namedFunctionInvoker; // cached helper for LF.NamedFunction @Stable final MethodHandle[] methodHandles;
// Indexes into methodHandles:
static final int
MH_BASIC_INV = 0, // cached instance of MH.invokeBasic
MH_NF_INV = 1, // cached helper for LF.NamedFunction
MH_UNINIT_CS = 2, // uninitialized call site
MH_LIMIT = 3;
// Cached lambda form information, for basic types only: // Cached lambda form information, for basic types only:
final @Stable LambdaForm[] lambdaForms; final @Stable LambdaForm[] lambdaForms;
...@@ -98,6 +104,18 @@ final class MethodTypeForm { ...@@ -98,6 +104,18 @@ final class MethodTypeForm {
return true; return true;
} }
public MethodHandle cachedMethodHandle(int which) {
assert(assertIsBasicType());
return methodHandles[which];
}
synchronized public MethodHandle setCachedMethodHandle(int which, MethodHandle mh) {
// Simulate a CAS, to avoid racy duplication of results.
MethodHandle prev = methodHandles[which];
if (prev != null) return prev;
return methodHandles[which] = mh;
}
public LambdaForm cachedLambdaForm(int which) { public LambdaForm cachedLambdaForm(int which) {
assert(assertIsBasicType()); assert(assertIsBasicType());
return lambdaForms[which]; return lambdaForms[which];
...@@ -169,6 +187,7 @@ final class MethodTypeForm { ...@@ -169,6 +187,7 @@ final class MethodTypeForm {
this.argCounts = that.argCounts; this.argCounts = that.argCounts;
this.argToSlotTable = that.argToSlotTable; this.argToSlotTable = that.argToSlotTable;
this.slotToArgTable = that.slotToArgTable; this.slotToArgTable = that.slotToArgTable;
this.methodHandles = null;
this.lambdaForms = null; this.lambdaForms = null;
return; return;
} }
...@@ -214,6 +233,7 @@ final class MethodTypeForm { ...@@ -214,6 +233,7 @@ final class MethodTypeForm {
// Initialize caches, but only for basic types // Initialize caches, but only for basic types
assert(basicType == erasedType); assert(basicType == erasedType);
this.lambdaForms = new LambdaForm[LF_LIMIT]; this.lambdaForms = new LambdaForm[LF_LIMIT];
this.methodHandles = new MethodHandle[MH_LIMIT];
} }
private static long pack(int a, int b, int c, int d) { private static long pack(int a, int b, int c, int d) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册