提交 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 {
*/
/*package-private*/
CallSite(MethodType type) {
target = type.invokers().uninitializedCallSite();
target = makeUninitializedCallSite(type);
}
/**
......@@ -217,21 +217,34 @@ public class CallSite {
}
private static final MethodHandle GET_TARGET;
private static final MethodHandle THROW_UCS;
static {
try {
GET_TARGET = IMPL_LOOKUP.
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) {
throw newInternalError(e);
}
}
/** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
/*package-private*/
static Empty uninitializedCallSite() {
private static Object uninitializedCallSite(Object... ignore) {
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:
private static final long TARGET_OFFSET;
static {
......
......@@ -25,8 +25,9 @@
package java.lang.invoke;
import java.lang.reflect.Array;
import java.util.Arrays;
import sun.invoke.empty.Empty;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
......@@ -40,52 +41,63 @@ class Invokers {
// exact type (sans leading taget MH) for the outgoing call
private final MethodType targetType;
// FIXME: Get rid of the invokers that are not useful.
// exact invoker for the outgoing call
private /*lazy*/ MethodHandle exactInvoker;
private /*lazy*/ MethodHandle basicInvoker; // invokeBasic (unchecked exact)
// erased (partially untyped but with primitives) invoker for the outgoing call
// FIXME: get rid of
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;
// Cached adapter information:
private final @Stable MethodHandle[] invokers = new MethodHandle[INV_LIMIT];
// Indexes into invokers:
static final int
INV_EXACT = 0, // MethodHandles.exactInvoker
INV_GENERIC = 1, // MethodHandles.invoker (generic invocation)
INV_BASIC = 2, // MethodHandles.basicInvoker
INV_LIMIT = 3;
/** Compute and cache information common to all collecting adapters
* that implement members of the erasure-family of the given erased type.
*/
/*non-public*/ Invokers(MethodType targetType) {
this.targetType = targetType;
this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
}
/*non-public*/ MethodHandle exactInvoker() {
MethodHandle invoker = exactInvoker;
MethodHandle invoker = cachedInvoker(INV_EXACT);
if (invoker != null) return invoker;
invoker = makeExactOrGeneralInvoker(true);
exactInvoker = invoker;
return invoker;
return setCachedInvoker(INV_EXACT, invoker);
}
/*non-public*/ MethodHandle generalInvoker() {
MethodHandle invoker = generalInvoker;
/*non-public*/ MethodHandle genericInvoker() {
MethodHandle invoker = cachedInvoker(INV_GENERIC);
if (invoker != null) return invoker;
invoker = makeExactOrGeneralInvoker(false);
generalInvoker = invoker;
return invoker;
return setCachedInvoker(INV_GENERIC, 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) {
......@@ -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>.
/*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
assert(basicType == basicType.basicType());
......@@ -145,87 +142,42 @@ class Invokers {
return true;
}
// FIXME: get rid of
/*non-public*/ MethodHandle erasedInvoker() {
MethodHandle xinvoker = exactInvoker();
MethodHandle invoker = erasedInvoker;
if (invoker != null) return invoker;
MethodType erasedType = targetType.erase();
invoker = xinvoker.asType(erasedType.invokerType());
erasedInvoker = invoker;
return invoker;
}
/**
* Find or create an invoker which passes unchanged a given number of arguments
* and spreads the rest from a trailing array argument.
* The invoker target type is the post-spread type {@code (TYPEOF(uarg*), TYPEOF(sarg*))=>RT}.
* All the {@code sarg}s must have a common type {@code C}. (If there are none, {@code Object} is assumed.}
* @param leadingArgCount the number of unchanged (non-spread) arguments
* @return {@code invoker.invokeExact(mh, uarg*, C[]{sarg*}) := (RT)mh.invoke(uarg*, sarg*)}
*/
/*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
MethodHandle vaInvoker = spreadInvokers[leadingArgCount];
if (vaInvoker != null) return vaInvoker;
int spreadArgCount = targetType.parameterCount() - leadingArgCount;
MethodType spreadInvokerType = targetType
.replaceParameterTypes(leadingArgCount, targetType.parameterCount(), Object[].class);
if (targetType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) {
// Factor sinvoker.invoke(mh, a) into ginvoker.asSpreader().invoke(mh, a)
// 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);
MethodType postSpreadType = targetType;
Class<?> argArrayType = impliedRestargType(postSpreadType, leadingArgCount);
if (postSpreadType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) {
return genericInvoker().asSpreader(argArrayType, spreadArgCount);
}
assert(vaInvoker.type().equals(spreadInvokerType.invokerType()));
maybeCompileToBytecode(vaInvoker);
spreadInvokers[leadingArgCount] = vaInvoker;
return vaInvoker;
// Cannot build a generic 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)
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() {
MethodHandle vaInvoker = varargsInvoker;
if (vaInvoker != null) return vaInvoker;
vaInvoker = spreadInvoker(0).asType(MethodType.genericMethodType(0, true).invokerType());
varargsInvoker = vaInvoker;
return vaInvoker;
}
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;
private static Class<?> impliedRestargType(MethodType restargType, int fromPos) {
if (restargType.isGeneric()) return Object[].class; // can be nothing else
int maxPos = restargType.parameterCount();
if (fromPos >= maxPos) return Object[].class; // reasonable default
Class<?> argType = restargType.parameterType(fromPos);
for (int i = fromPos+1; i < maxPos; i++) {
if (argType != restargType.parameterType(i))
throw newIllegalArgumentException("need homogeneous rest arguments", restargType);
}
invoker = THROW_UCS;
if (invoker == null) {
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;
if (argType == Object.class) return Object[].class;
return Array.newInstance(argType, 0).getClass();
}
public String toString() {
......@@ -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 {
if (LambdaForm.signatureReturn(sig) == V_TYPE)
srcType = srcType.changeReturnType(void.class);
MethodTypeForm typeForm = srcType.form();
typeForm.namedFunctionInvoker = DirectMethodHandle.make(m);
typeForm.setCachedMethodHandle(MethodTypeForm.MH_NF_INV, DirectMethodHandle.make(m));
}
}
}
......@@ -1249,15 +1249,16 @@ class LambdaForm {
MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
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;
MemberName invoker = InvokerBytecodeGenerator.generateNamedFunctionInvoker(typeForm); // this could take a while
mh = DirectMethodHandle.make(invoker);
MethodHandle mh2 = typeForm.namedFunctionInvoker;
MethodHandle mh2 = typeForm.cachedMethodHandle(MethodTypeForm.MH_NF_INV);
if (mh2 != null) return mh2; // benign race
if (!mh.type().equals(INVOKER_METHOD_TYPE))
throw newInternalError(mh.debugString());
return typeForm.namedFunctionInvoker = mh;
return typeForm.setCachedMethodHandle(MethodTypeForm.MH_NF_INV, mh);
}
@Hidden
......
......@@ -624,15 +624,8 @@ public abstract class MethodHandle {
* @see MethodHandles#spreadInvoker
*/
public Object invokeWithArguments(Object... arguments) throws Throwable {
int argc = arguments == null ? 0 : arguments.length;
@SuppressWarnings("LocalVariableHidesMemberVariable")
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);
MethodType invocationType = MethodType.genericMethodType(arguments == null ? 0 : arguments.length);
return invocationType.invokers().spreadInvoker(0).invokeExact(asType(invocationType), arguments);
}
/**
......
......@@ -1883,6 +1883,7 @@ return invoker;
MethodHandle spreadInvoker(MethodType type, int leadingArgCount) {
if (leadingArgCount < 0 || leadingArgCount > type.parameterCount())
throw newIllegalArgumentException("bad argument count", leadingArgCount);
type = type.asSpreaderType(Object[].class, type.parameterCount() - leadingArgCount);
return type.invokers().spreadInvoker(leadingArgCount);
}
......@@ -1962,7 +1963,7 @@ return invoker;
*/
static public
MethodHandle invoker(MethodType type) {
return type.invokers().generalInvoker();
return type.invokers().genericInvoker();
}
static /*non-public*/
......
......@@ -466,6 +466,38 @@ class MethodType implements java.io.Serializable {
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.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
......@@ -573,6 +605,10 @@ class MethodType implements java.io.Serializable {
return genericMethodType(parameterCount());
}
/*non-public*/ boolean isGeneric() {
return this == erase() && !hasPrimitives();
}
/**
* Converts all primitive types to their corresponding wrapper types.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
......
......@@ -51,7 +51,13 @@ final class MethodTypeForm {
final MethodType basicType; // the canonical erasure, with primitives simplified
// 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:
final @Stable LambdaForm[] lambdaForms;
......@@ -98,6 +104,18 @@ final class MethodTypeForm {
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) {
assert(assertIsBasicType());
return lambdaForms[which];
......@@ -169,6 +187,7 @@ final class MethodTypeForm {
this.argCounts = that.argCounts;
this.argToSlotTable = that.argToSlotTable;
this.slotToArgTable = that.slotToArgTable;
this.methodHandles = null;
this.lambdaForms = null;
return;
}
......@@ -214,6 +233,7 @@ final class MethodTypeForm {
// Initialize caches, but only for basic types
assert(basicType == erasedType);
this.lambdaForms = new LambdaForm[LF_LIMIT];
this.methodHandles = new MethodHandle[MH_LIMIT];
}
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.
先完成此消息的编辑!
想要评论请 注册