< prev index next >

src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java

Print this page
rev 13064 : 8142334: Improve lazy initialization of java.lang.invoke
Reviewed-by: psandoz, vlivanov, mhaupt

*** 217,227 **** for (int i = 0; i < convSpecs.length-1; i++) { Object convSpec = convSpecs[i]; if (convSpec == null) continue; MethodHandle fn; if (convSpec instanceof Class) { ! fn = Lazy.MH_cast.bindTo(convSpec); } else { fn = (MethodHandle) convSpec; } Class<?> newType = basicSrcType.parameterType(i); if (--convCount == 0) --- 217,227 ---- for (int i = 0; i < convSpecs.length-1; i++) { Object convSpec = convSpecs[i]; if (convSpec == null) continue; MethodHandle fn; if (convSpec instanceof Class) { ! fn = getConstantHandle(MH_cast).bindTo(convSpec); } else { fn = (MethodHandle) convSpec; } Class<?> newType = basicSrcType.parameterType(i); if (--convCount == 0)
*** 237,247 **** MethodHandle fn; if (convSpec instanceof Class) { if (convSpec == void.class) fn = null; else ! fn = Lazy.MH_cast.bindTo(convSpec); } else { fn = (MethodHandle) convSpec; } Class<?> newType = basicSrcType.returnType(); assert(--convCount == 0); --- 237,247 ---- MethodHandle fn; if (convSpec instanceof Class) { if (convSpec == void.class) fn = null; else ! fn = getConstantHandle(MH_cast).bindTo(convSpec); } else { fn = (MethodHandle) convSpec; } Class<?> newType = basicSrcType.returnType(); assert(--convCount == 0);
*** 300,310 **** } Name conv; if (convSpec instanceof Class) { Class<?> convClass = (Class<?>) convSpec; ! conv = new Name(Lazy.MH_cast, convClass, names[INARG_BASE + i]); } else { MethodHandle fn = (MethodHandle) convSpec; conv = new Name(fn, names[INARG_BASE + i]); } assert(names[nameCursor] == null); --- 300,310 ---- } Name conv; if (convSpec instanceof Class) { Class<?> convClass = (Class<?>) convSpec; ! conv = new Name(getConstantHandle(MH_cast), convClass, names[INARG_BASE + i]); } else { MethodHandle fn = (MethodHandle) convSpec; conv = new Name(fn, names[INARG_BASE + i]); } assert(names[nameCursor] == null);
*** 324,334 **** Name conv; if (convSpec == void.class) { conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType()))); } else if (convSpec instanceof Class) { Class<?> convClass = (Class<?>) convSpec; ! conv = new Name(Lazy.MH_cast, convClass, names[OUT_CALL]); } else { MethodHandle fn = (MethodHandle) convSpec; if (fn.type().parameterCount() == 0) conv = new Name(fn); // don't pass retval to void conversion else --- 324,334 ---- Name conv; if (convSpec == void.class) { conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType()))); } else if (convSpec instanceof Class) { Class<?> convClass = (Class<?>) convSpec; ! conv = new Name(getConstantHandle(MH_cast), convClass, names[OUT_CALL]); } else { MethodHandle fn = (MethodHandle) convSpec; if (fn.type().parameterCount() == 0) conv = new Name(fn); // don't pass retval to void conversion else
*** 527,537 **** Class<?> src = lambdaType.parameterType(i); if (i == spreadArgPos) { // Spread the array. MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType); Name array = names[argIndex]; ! names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount); for (int j = 0; j < spreadArgCount; i++, j++) { indexes[i] = nameCursor; names[nameCursor++] = new Name(aload, array, j); } } else if (i < indexes.length) { --- 527,537 ---- Class<?> src = lambdaType.parameterType(i); if (i == spreadArgPos) { // Spread the array. MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType); Name array = names[argIndex]; ! names[nameCursor++] = new Name(NF_checkSpreadArgument, array, spreadArgCount); for (int j = 0; j < spreadArgCount; i++, j++) { indexes[i] = nameCursor; names[nameCursor++] = new Name(aload, array, j); } } else if (i < indexes.length) {
*** 564,633 **** } // fall through to error: throw newIllegalArgumentException("array is not of length "+n); } - /** - * Pre-initialized NamedFunctions for bootstrapping purposes. - * Factored in an inner class to delay initialization until first usage. - */ - static class Lazy { - private static final Class<?> MHI = MethodHandleImpl.class; - private static final Class<?> CLS = Class.class; - - private static final MethodHandle[] ARRAYS; - private static final MethodHandle[] FILL_ARRAYS; - - static final NamedFunction NF_checkSpreadArgument; - static final NamedFunction NF_guardWithCatch; - static final NamedFunction NF_throwException; - static final NamedFunction NF_profileBoolean; - - static final MethodHandle MH_cast; - static final MethodHandle MH_selectAlternative; - static final MethodHandle MH_copyAsPrimitiveArray; - static final MethodHandle MH_fillNewTypedArray; - static final MethodHandle MH_fillNewArray; - static final MethodHandle MH_arrayIdentity; - - static { - ARRAYS = makeArrays(); - FILL_ARRAYS = makeFillArrays(); - - try { - NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class)); - 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_cast = IMPL_LOOKUP.findVirtual(CLS, "cast", - MethodType.methodType(Object.class, Object.class)); - MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray", - MethodType.methodType(Object.class, Wrapper.class, Object[].class)); - MH_arrayIdentity = IMPL_LOOKUP.findStatic(MHI, "identity", - MethodType.methodType(Object[].class, Object[].class)); - MH_fillNewArray = IMPL_LOOKUP.findStatic(MHI, "fillNewArray", - MethodType.methodType(Object[].class, Integer.class, Object[].class)); - MH_fillNewTypedArray = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray", - MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class)); - - MH_selectAlternative = makeIntrinsic( - IMPL_LOOKUP.findStatic(MHI, "selectAlternative", - MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)), - Intrinsic.SELECT_ALTERNATIVE); - } catch (ReflectiveOperationException ex) { - throw newInternalError(ex); - } - } - } - /** Factory method: Collect or filter selected argument(s). */ static MethodHandle makeCollectArguments(MethodHandle target, MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) { MethodType targetType = target.type(); // (a..., c, [b...])=>r MethodType collectorType = collector.type(); // (b...)=>c --- 564,573 ----
*** 909,922 **** 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[TEST], names[GET_TARGET], names[GET_FALLBACK]); // call target or fallback invokeArgs[0] = names[SELECT_ALT]; names[CALL_TARGET] = new Name(basicType, invokeArgs); --- 849,862 ---- invokeArgs[0] = names[GET_TEST]; names[CALL_TEST] = new Name(testType, invokeArgs); // profile branch if (PROFILE != -1) { ! names[PROFILE] = new Name(NF_profileBoolean, names[CALL_TEST], names[GET_COUNTERS]); } // call selectAlternative ! names[SELECT_ALT] = new Name(getConstantHandle(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);
*** 987,997 **** System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE); names[BOXED_ARGS] = new Name(makeIntrinsic(invokeBasic, Intrinsic.GUARD_WITH_CATCH), args); // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L); Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]}; ! names[TRY_CATCH] = new Name(Lazy.NF_guardWithCatch, gwcArgs); // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L); MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class)); Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]}; names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs); --- 927,937 ---- System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE); names[BOXED_ARGS] = new Name(makeIntrinsic(invokeBasic, Intrinsic.GUARD_WITH_CATCH), args); // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L); Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]}; ! names[TRY_CATCH] = new Name(NF_guardWithCatch, gwcArgs); // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L); MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class)); Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]}; names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs);
*** 1071,1081 **** if (arity > 1) { MethodHandle mh = throwException(type.dropParameterTypes(1, arity)); mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity)); return mh; } ! return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, false, true); } static <T extends Throwable> Empty throwException(T t) throws T { throw t; } static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2]; --- 1011,1021 ---- if (arity > 1) { MethodHandle mh = throwException(type.dropParameterTypes(1, arity)); mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity)); return mh; } ! return makePairwiseConvert(NF_throwException.resolvedHandle(), type, false, true); } static <T extends Throwable> Empty throwException(T t) throws T { throw t; } static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
*** 1419,1447 **** Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } private static final int ARRAYS_COUNT = 11; ! ! private static MethodHandle[] makeArrays() { ! MethodHandle[] mhs = new MethodHandle[MAX_ARITY + 1]; ! for (int i = 0; i < ARRAYS_COUNT; i++) { ! MethodHandle mh = findCollector("array", i, Object[].class); ! mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); ! mhs[i] = mh; ! } ! assert(assertArrayMethodCount(mhs)); ! return mhs; ! } ! ! private static boolean assertArrayMethodCount(MethodHandle[] mhs) { ! assert(findCollector("array", ARRAYS_COUNT, Object[].class) == null); ! for (int i = 0; i < ARRAYS_COUNT; i++) { ! assert(mhs[i] != null); ! } ! return true; ! } // filling versions of the above: // using Integer len instead of int len and no varargs to avoid bootstrapping problems private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) { Object[] a = new Object[len]; --- 1359,1369 ---- Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } private static final int ARRAYS_COUNT = 11; ! private static final @Stable MethodHandle[] ARRAYS = new MethodHandle[MAX_ARITY + 1]; // filling versions of the above: // using Integer len instead of int len and no varargs to avoid bootstrapping problems private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) { Object[] a = new Object[len];
*** 1486,1513 **** Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; } private static final int FILL_ARRAYS_COUNT = 11; // current number of fillArray methods ! private static MethodHandle[] makeFillArrays() { ! MethodHandle[] mhs = new MethodHandle[FILL_ARRAYS_COUNT]; ! mhs[0] = null; // there is no empty fill; at least a0 is required ! for (int i = 1; i < FILL_ARRAYS_COUNT; i++) { ! MethodHandle mh = findCollector("fillArray", i, Object[].class, Integer.class, Object[].class); ! mhs[i] = mh; ! } ! assert(assertFillArrayMethodCount(mhs)); ! return mhs; ! } ! ! private static boolean assertFillArrayMethodCount(MethodHandle[] mhs) { ! assert(findCollector("fillArray", FILL_ARRAYS_COUNT, Object[].class, Integer.class, Object[].class) == null); ! for (int i = 1; i < FILL_ARRAYS_COUNT; i++) { ! assert(mhs[i] != null); } ! return true; } private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) { Object a = w.makeArray(boxes.length); w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length); --- 1408,1428 ---- Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; } private static final int FILL_ARRAYS_COUNT = 11; // current number of fillArray methods + private static final @Stable MethodHandle[] FILL_ARRAYS = new MethodHandle[FILL_ARRAYS_COUNT]; ! private static MethodHandle getFillArray(int count) { ! assert (count > 0 && count < FILL_ARRAYS_COUNT); ! MethodHandle mh = FILL_ARRAYS[count]; ! if (mh != null) { ! return mh; } ! mh = findCollector("fillArray", count, Object[].class, Integer.class, Object[].class); ! FILL_ARRAYS[count] = mh; ! return mh; } private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) { Object a = w.makeArray(boxes.length); w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length);
*** 1516,1539 **** /** Return a method handle that takes the indicated number of Object * arguments and returns an Object array of them, as if for varargs. */ static MethodHandle varargsArray(int nargs) { ! MethodHandle mh = Lazy.ARRAYS[nargs]; ! if (mh != null) return mh; ! mh = buildVarargsArray(Lazy.MH_fillNewArray, Lazy.MH_arrayIdentity, nargs); assert(assertCorrectArity(mh, nargs)); mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); ! return Lazy.ARRAYS[nargs] = mh; } private static boolean assertCorrectArity(MethodHandle mh, int arity) { assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh; return true; } ! // Array identity function (used as Lazy.MH_arrayIdentity). static <T> T[] identity(T[] x) { return x; } private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) { --- 1431,1461 ---- /** Return a method handle that takes the indicated number of Object * arguments and returns an Object array of them, as if for varargs. */ static MethodHandle varargsArray(int nargs) { ! MethodHandle mh = ARRAYS[nargs]; ! if (mh != null) { ! return mh; ! } ! if (nargs < ARRAYS_COUNT) { ! mh = findCollector("array", nargs, Object[].class); ! } else { ! mh = buildVarargsArray(getConstantHandle(MH_fillNewArray), ! getConstantHandle(MH_arrayIdentity), nargs); ! } assert(assertCorrectArity(mh, nargs)); mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); ! return ARRAYS[nargs] = mh; } private static boolean assertCorrectArity(MethodHandle mh, int arity) { assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh; return true; } ! // Array identity function (used as getConstantHandle(MH_arrayIdentity)). static <T> T[] identity(T[] x) { return x; } private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) {
*** 1545,1568 **** MethodHandle leftCollector = newArray.bindTo(nargs); leftCollector = leftCollector.asCollector(Object[].class, leftLen); MethodHandle mh = finisher; if (rightLen > 0) { MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen); ! if (mh == Lazy.MH_arrayIdentity) mh = rightFiller; else mh = MethodHandles.collectArguments(mh, 0, rightFiller); } ! if (mh == Lazy.MH_arrayIdentity) mh = leftCollector; else mh = MethodHandles.collectArguments(mh, 0, leftCollector); return mh; } private static final int LEFT_ARGS = FILL_ARRAYS_COUNT - 1; ! private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1]; /** fill_array_to_right(N).invoke(a, argL..arg[N-1]) * fills a[L]..a[N-1] with corresponding arguments, * and then returns a. The value L is a global constant (LEFT_ARGS). */ private static MethodHandle fillToRight(int nargs) { --- 1467,1490 ---- MethodHandle leftCollector = newArray.bindTo(nargs); leftCollector = leftCollector.asCollector(Object[].class, leftLen); MethodHandle mh = finisher; if (rightLen > 0) { MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen); ! if (mh.equals(getConstantHandle(MH_arrayIdentity))) mh = rightFiller; else mh = MethodHandles.collectArguments(mh, 0, rightFiller); } ! if (mh.equals(getConstantHandle(MH_arrayIdentity))) mh = leftCollector; else mh = MethodHandles.collectArguments(mh, 0, leftCollector); return mh; } private static final int LEFT_ARGS = FILL_ARRAYS_COUNT - 1; ! private static final @Stable MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1]; /** fill_array_to_right(N).invoke(a, argL..arg[N-1]) * fills a[L]..a[N-1] with corresponding arguments, * and then returns a. The value L is a global constant (LEFT_ARGS). */ private static MethodHandle fillToRight(int nargs) {
*** 1572,1582 **** assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1)); return FILL_ARRAY_TO_RIGHT[nargs] = filler; } private static MethodHandle buildFiller(int nargs) { if (nargs <= LEFT_ARGS) ! return Lazy.MH_arrayIdentity; // no args to fill; return the array unchanged // we need room for both mh and a in mh.invoke(a, arg*[nargs]) final int CHUNK = LEFT_ARGS; int rightLen = nargs % CHUNK; int midLen = nargs - rightLen; if (rightLen == 0) { --- 1494,1504 ---- assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1)); return FILL_ARRAY_TO_RIGHT[nargs] = filler; } private static MethodHandle buildFiller(int nargs) { if (nargs <= LEFT_ARGS) ! return getConstantHandle(MH_arrayIdentity); // no args to fill; return the array unchanged // we need room for both mh and a in mh.invoke(a, arg*[nargs]) final int CHUNK = LEFT_ARGS; int rightLen = nargs % CHUNK; int midLen = nargs - rightLen; if (rightLen == 0) {
*** 1588,1598 **** } } if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS); assert(rightLen > 0); MethodHandle midFill = fillToRight(midLen); // recursive fill ! MethodHandle rightFill = Lazy.FILL_ARRAYS[rightLen].bindTo(midLen); // [midLen..nargs-1] assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS); assert(rightFill.type().parameterCount() == 1 + rightLen); // Combine the two fills: // right(mid(a, x10..x19), x20..x23) --- 1510,1520 ---- } } if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS); assert(rightLen > 0); MethodHandle midFill = fillToRight(midLen); // recursive fill ! MethodHandle rightFill = getFillArray(rightLen).bindTo(midLen); // [midLen..nargs-1] assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS); assert(rightFill.type().parameterCount() == 1 + rightLen); // Combine the two fills: // right(mid(a, x10..x19), x20..x23)
*** 1639,1656 **** if (mh != null) return mh; if (nargs == 0) { Object example = java.lang.reflect.Array.newInstance(arrayType.getComponentType(), 0); mh = MethodHandles.constant(arrayType, example); } else if (elemType.isPrimitive()) { ! MethodHandle builder = Lazy.MH_fillNewArray; MethodHandle producer = buildArrayProducer(arrayType); mh = buildVarargsArray(builder, producer, nargs); } else { Class<? extends Object[]> objArrayType = arrayType.asSubclass(Object[].class); Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType); ! MethodHandle builder = Lazy.MH_fillNewTypedArray.bindTo(example); ! MethodHandle producer = Lazy.MH_arrayIdentity; // must be weakly typed mh = buildVarargsArray(builder, producer, nargs); } mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType))); mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); assert(assertCorrectArity(mh, nargs)); --- 1561,1578 ---- if (mh != null) return mh; if (nargs == 0) { Object example = java.lang.reflect.Array.newInstance(arrayType.getComponentType(), 0); mh = MethodHandles.constant(arrayType, example); } else if (elemType.isPrimitive()) { ! MethodHandle builder = getConstantHandle(MH_fillNewArray); MethodHandle producer = buildArrayProducer(arrayType); mh = buildVarargsArray(builder, producer, nargs); } else { Class<? extends Object[]> objArrayType = arrayType.asSubclass(Object[].class); Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType); ! MethodHandle builder = getConstantHandle(MH_fillNewTypedArray).bindTo(example); ! MethodHandle producer = getConstantHandle(MH_arrayIdentity); // must be weakly typed mh = buildVarargsArray(builder, producer, nargs); } mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType))); mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); assert(assertCorrectArity(mh, nargs));
*** 1660,1676 **** } private static MethodHandle buildArrayProducer(Class<?> arrayType) { Class<?> elemType = arrayType.getComponentType(); 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); } } } --- 1582,1685 ---- } private static MethodHandle buildArrayProducer(Class<?> arrayType) { Class<?> elemType = arrayType.getComponentType(); assert(elemType.isPrimitive()); ! return getConstantHandle(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); } } + + // Local constant functions: + /*non-public*/ static final NamedFunction + NF_checkSpreadArgument, + NF_guardWithCatch, + NF_throwException, + NF_profileBoolean; + + static { + try { + NamedFunction nfs[] = { + NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class + .getDeclaredMethod("checkSpreadArgument", Object.class, int.class)), + NF_guardWithCatch = new NamedFunction(MethodHandleImpl.class + .getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class, + MethodHandle.class, Object[].class)), + NF_throwException = new NamedFunction(MethodHandleImpl.class + .getDeclaredMethod("throwException", Throwable.class)), + NF_profileBoolean = new NamedFunction(MethodHandleImpl.class + .getDeclaredMethod("profileBoolean", boolean.class, int[].class)) + }; + // Each nf must be statically invocable or we get tied up in our bootstraps. + assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs)); + } catch (ReflectiveOperationException ex) { + throw newInternalError(ex); + } + } + + // Indexes into constant method handles: + private static final int + MH_cast = 0, + MH_selectAlternative = 1, + MH_copyAsPrimitiveArray = 2, + MH_fillNewTypedArray = 3, + MH_fillNewArray = 4, + MH_arrayIdentity = 5, + MH_LIMIT = 6; + + private static MethodHandle getConstantHandle(int idx) { + MethodHandle handle = HANDLES[idx]; + if (handle != null) { + return handle; + } + return setCachedHandle(idx, makeConstantHandle(idx)); + } + + private static synchronized MethodHandle setCachedHandle(int idx, final MethodHandle method) { + // Simulate a CAS, to avoid racy duplication of results. + MethodHandle prev = HANDLES[idx]; + if (prev != null) { + return prev; + } + HANDLES[idx] = method; + return method; + } + + // Local constant method handles: + private static final @Stable MethodHandle[] HANDLES = new MethodHandle[MH_LIMIT]; + + private static MethodHandle makeConstantHandle(int idx) { + try { + switch (idx) { + case MH_cast: + return IMPL_LOOKUP.findVirtual(Class.class, "cast", + MethodType.methodType(Object.class, Object.class)); + case MH_copyAsPrimitiveArray: + return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "copyAsPrimitiveArray", + MethodType.methodType(Object.class, Wrapper.class, Object[].class)); + case MH_arrayIdentity: + return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "identity", + MethodType.methodType(Object[].class, Object[].class)); + case MH_fillNewArray: + return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "fillNewArray", + MethodType.methodType(Object[].class, Integer.class, Object[].class)); + case MH_fillNewTypedArray: + return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "fillNewTypedArray", + MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class)); + case MH_selectAlternative: + return makeIntrinsic(IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative", + MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)), + Intrinsic.SELECT_ALTERNATIVE); + } + } catch (ReflectiveOperationException ex) { + throw newInternalError(ex); + } + throw newInternalError("Unknown function index: " + idx); + } }
< prev index next >