8050053: Improve caching of different invokers
Reviewed-by: vlivanov, psandoz
This commit is contained in:
parent
da56d3f6d1
commit
6a177f43fb
@ -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 target 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1882,6 +1882,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);
|
||||
}
|
||||
|
||||
@ -1961,7 +1962,7 @@ return invoker;
|
||||
*/
|
||||
static public
|
||||
MethodHandle invoker(MethodType type) {
|
||||
return type.invokers().generalInvoker();
|
||||
return type.invokers().genericInvoker();
|
||||
}
|
||||
|
||||
static /*non-public*/
|
||||
|
@ -467,6 +467,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}.
|
||||
@ -574,6 +606,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) {
|
||||
|
Loading…
Reference in New Issue
Block a user