diff --git a/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java index d3986a38dab78..1513da901f4c5 100644 --- a/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java @@ -159,7 +159,7 @@ static LambdaForm makeReinvokerForm(MethodHandle target, targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs); } - form = new LambdaForm(ARG_LIMIT, names, forceInline, kind); + form = LambdaForm.of(ARG_LIMIT, names, forceInline, kind); if (!customized) { form = mtype.form().setCachedLambdaForm(whichCache, form); } diff --git a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java index 2a557fd96756e..2dd1aabc7e9cb 100644 --- a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java @@ -297,7 +297,7 @@ static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) { result = NEW_OBJ; } names[LINKER_CALL] = new Name(linker, outArgs); - LambdaForm lform = new LambdaForm(ARG_LIMIT, names, result, kind); + LambdaForm lform = LambdaForm.of(ARG_LIMIT, names, result, kind); // This is a tricky bit of code. Don't send it through the LF interpreter. lform.skipInterpreter(); @@ -814,9 +814,9 @@ static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, i LambdaForm form; if (needsCast || needsInit) { // can't use the pre-generated form when casting and/or initializing - form = new LambdaForm(ARG_LIMIT, names, RESULT); + form = LambdaForm.of(ARG_LIMIT, names, RESULT); } else { - form = new LambdaForm(ARG_LIMIT, names, RESULT, kind); + form = LambdaForm.of(ARG_LIMIT, names, RESULT, kind); } if (LambdaForm.debugNames()) { diff --git a/src/java.base/share/classes/java/lang/invoke/Invokers.java b/src/java.base/share/classes/java/lang/invoke/Invokers.java index 8410b97a7b846..f3e4cff047f63 100644 --- a/src/java.base/share/classes/java/lang/invoke/Invokers.java +++ b/src/java.base/share/classes/java/lang/invoke/Invokers.java @@ -351,9 +351,9 @@ static LambdaForm invokeHandleForm(MethodType mtype, boolean customized, int whi } names[LINKER_CALL] = new Name(outCallType, outArgs); if (customized) { - lform = new LambdaForm(INARG_LIMIT, names); + lform = LambdaForm.of(INARG_LIMIT, names); } else { - lform = new LambdaForm(INARG_LIMIT, names, kind); + lform = LambdaForm.of(INARG_LIMIT, names, kind); } if (isLinker) { lform.forceCompileToBytecode(); // JVM needs a real methodOop @@ -416,7 +416,7 @@ private static LambdaForm varHandleMethodGenericLinkerHandleForm(MethodType mtyp MethodType outCallType = mtype.insertParameterTypes(0, VarHandle.class) .basicType(); names[LINKER_CALL] = new Name(outCallType, outArgs); - lform = new LambdaForm(ARG_LIMIT + 1, names, VARHANDLE_LINKER); + lform = LambdaForm.of(ARG_LIMIT + 1, names, VARHANDLE_LINKER); if (LambdaForm.debugNames()) { String name = "VarHandle_invoke_MT_" + shortenSignature(basicTypeSignature(mtype)); LambdaForm.associateWithDebugName(lform, name); @@ -478,7 +478,7 @@ private static LambdaForm varHandleMethodInvokerHandleForm(MethodType mtype, boo .basicType(); names[LINKER_CALL] = new Name(outCallType, outArgs); Kind kind = isExact ? VARHANDLE_EXACT_INVOKER : VARHANDLE_INVOKER; - lform = new LambdaForm(ARG_LIMIT, names, kind); + lform = LambdaForm.of(ARG_LIMIT, names, kind); if (LambdaForm.debugNames()) { String name = (isExact ? "VarHandle_exactInvoker_" : "VarHandle_invoker_") + shortenSignature(basicTypeSignature(mtype)); LambdaForm.associateWithDebugName(lform, name); @@ -605,7 +605,7 @@ static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) { System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT); outArgs[PREPEND_MH] = names[CALL_MH]; names[LINKER_CALL] = new Name(mtype, outArgs); - lform = new LambdaForm(INARG_LIMIT, names, + lform = LambdaForm.of(INARG_LIMIT, names, (skipCallSite ? LINK_TO_TARGET_METHOD : LINK_TO_CALL_SITE)); lform.forceCompileToBytecode(); // JVM needs a real methodOop lform = mtype.form().setCachedLambdaForm(which, lform); diff --git a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java index b5a276c72f587..9e87a7b2adcbb 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java @@ -333,62 +333,79 @@ private Kind(String defaultLambdaName, String methodName) { } } - LambdaForm(int arity, Name[] names, int result) { - this(arity, names, result, /*forceInline=*/true, /*customized=*/null, Kind.GENERIC); - } - LambdaForm(int arity, Name[] names, int result, Kind kind) { - this(arity, names, result, /*forceInline=*/true, /*customized=*/null, kind); - } - LambdaForm(int arity, Name[] names, int result, boolean forceInline, MethodHandle customized, Kind kind) { - this(arity, result, forceInline, customized, kind, names.clone()); - assert(namesOK(arity, names)); - } - - // Final, private version that doesn't check or clone names - LambdaForm(int arity, int result, boolean forceInline, MethodHandle customized, Kind kind, Name[] names) { + // private version that doesn't do checks or defensive copies, and simply initializes all fields + private LambdaForm(int arity, int result, boolean forceInline, MethodHandle customized, Name[] names, Kind kind, + boolean skipInterpreter) { this.arity = arity; - this.result = fixResult(result, names); - this.names = names; + this.result = result; this.forceInline = forceInline; this.customized = customized; + this.names = names; this.kind = kind; - int maxOutArity = normalize(); - if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) { - // Cannot use LF interpreter on very high arity expressions. - assert(maxOutArity <= MethodType.MAX_JVM_ARITY); - this.skipInterpreter = true; - } else { - this.skipInterpreter = false; - } + this.vmentry = null; + this.isCompiled = false; + this.skipInterpreter = skipInterpreter; + this.isResolved = false; + } + + // root factory. pre/post processing and checks + private static LambdaForm of(int arity, Name[] names, int result, boolean forceInline, MethodHandle customized, Kind kind) { + names = names.clone(); + assert(namesOK(arity, names)); + result = fixResult(result, names); + + boolean canInterpret = normalizeNames(arity, names); + LambdaForm form = new LambdaForm(arity, result, forceInline, customized, names, kind, !canInterpret); + assert(form.nameRefsAreLegal()); + return form; + } + + private static final int DEFAULT_RESULT = LAST_RESULT; + private static final boolean DEFAULT_FORCE_INLINE = true; + private static final MethodHandle DEFAULT_CUSTOMIZED = null; + private static final Kind DEFAULT_KIND = Kind.GENERIC; + + // derived factories with defaults + static LambdaForm of(int arity, Name[] names, int result) { + return of(arity, names, result, DEFAULT_FORCE_INLINE, DEFAULT_CUSTOMIZED, DEFAULT_KIND); + } + static LambdaForm of(int arity, Name[] names, int result, Kind kind) { + return of(arity, names, result, DEFAULT_FORCE_INLINE, DEFAULT_CUSTOMIZED, kind); } - LambdaForm(int arity, Name[] names) { - this(arity, names, LAST_RESULT, /*forceInline=*/true, /*customized=*/null, Kind.GENERIC); + static LambdaForm of(int arity, Name[] names) { + return of(arity, names, DEFAULT_RESULT, DEFAULT_FORCE_INLINE, DEFAULT_CUSTOMIZED, DEFAULT_KIND); } - LambdaForm(int arity, Name[] names, Kind kind) { - this(arity, names, LAST_RESULT, /*forceInline=*/true, /*customized=*/null, kind); + static LambdaForm of(int arity, Name[] names, Kind kind) { + return of(arity, names, DEFAULT_RESULT, DEFAULT_FORCE_INLINE, DEFAULT_CUSTOMIZED, kind); } - LambdaForm(int arity, Name[] names, boolean forceInline, Kind kind) { - this(arity, names, LAST_RESULT, forceInline, /*customized=*/null, kind); + static LambdaForm of(int arity, Name[] names, boolean forceInline, Kind kind) { + return of(arity, names, DEFAULT_RESULT, forceInline, DEFAULT_CUSTOMIZED, kind); } + // specialized factories private static LambdaForm createBlankForType(MethodType mt) { // 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. // Called only from getPreparedForm. int arity = mt.parameterCount(); - int result = (mt.returnType() == void.class || mt.returnType() == Void.class) ? -1 : arity; - LambdaForm form = new LambdaForm(arity, result, /* forceInline */ true, - null, Kind.ZERO, buildEmptyNames(arity, mt, result == -1)); + int result = (mt.returnType() == void.class || mt.returnType() == Void.class) ? VOID_RESULT : arity; + Name[] names = buildEmptyNames(arity, mt, result == VOID_RESULT); + boolean canInterpret = normalizeNames(arity, names); + LambdaForm form = new LambdaForm(arity, result, DEFAULT_FORCE_INLINE, DEFAULT_CUSTOMIZED, + names, Kind.ZERO, !canInterpret); assert(form.nameRefsAreLegal() && form.isEmpty() && isValidSignature(form.basicTypeSignature())); return form; } - static final Name[] EMPTY_NAMES = new Name[0]; + private static final Name[] EMPTY_NAMES = new Name[0]; static LambdaForm createWrapperForResolver(MemberName mn) { // Make a blank lambda form wrapping an existing vmentry. // This is used for the LambdaFormResolver case where the resolved member name is all // we care about but we need a LF wrapper for caching and pre-generation hooks. - LambdaForm form = new LambdaForm(0, -1, /*forceInline*/ true, null, Kind.RESOLVER, EMPTY_NAMES); + boolean forceInline = false; // don't try to inline resolvers + boolean skipInterpreter = false; // empty form should be interpretable + LambdaForm form = new LambdaForm(0, VOID_RESULT, forceInline, DEFAULT_CUSTOMIZED, + EMPTY_NAMES, Kind.RESOLVER, skipInterpreter); form.vmentry = mn; return form; } @@ -470,7 +487,7 @@ LambdaForm customize(MethodHandle mh) { if (customized == mh) { return this; } - LambdaForm customForm = new LambdaForm(arity, names, result, forceInline, mh, kind); + LambdaForm customForm = LambdaForm.of(arity, names, result, forceInline, mh, kind); if (COMPILE_THRESHOLD >= 0 && isCompiled) { // If shared LambdaForm has been compiled, compile customized version as well. customForm.skipInterpreter(); @@ -494,9 +511,9 @@ LambdaForm uncustomize() { } /** Renumber and/or replace params so that they are interned and canonically numbered. - * @return maximum argument list length among the names (since we have to pass over them anyway) + * @return true if we can interpret */ - private int normalize() { + private static boolean normalizeNames(int arity, Name[] names) { Name[] oldNames = null; int maxOutArity = 0; int changesStart = 0; @@ -521,7 +538,6 @@ private int normalize() { names[i] = fixed.newIndex(i); } } - assert(nameRefsAreLegal()); int maxInterned = Math.min(arity, INTERNED_ARGUMENT_LIMIT); boolean needIntern = false; for (int i = 0; i < maxInterned; i++) { @@ -536,8 +552,14 @@ private int normalize() { names[i].internArguments(); } } - assert(nameRefsAreLegal()); - return maxOutArity; + + // return true if we can interpret + if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) { + // Cannot use LF interpreter on very high arity expressions. + assert(maxOutArity <= MethodType.MAX_JVM_ARITY); + return false; + } + return true; } /** @@ -1847,7 +1869,7 @@ private static void createFormsFor(BasicType type) { // bootstrap dependency on this method in case we're interpreting LFs if (isVoid) { Name[] idNames = new Name[] { argument(0, L_TYPE) }; - idForm = new LambdaForm(1, idNames, VOID_RESULT, Kind.IDENTITY); + idForm = LambdaForm.of(1, idNames, VOID_RESULT, Kind.IDENTITY); idForm.skipInterpreter(); idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm)); @@ -1855,14 +1877,14 @@ private static void createFormsFor(BasicType type) { zeFun = idFun; } else { Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) }; - idForm = new LambdaForm(2, idNames, 1, Kind.IDENTITY); + idForm = LambdaForm.of(2, idNames, 1, Kind.IDENTITY); idForm.skipInterpreter(); idFun = new NamedFunction(idMem, MethodHandleImpl.makeIntrinsic(SimpleMethodHandle.make(idMem.getInvocationType(), idForm), MethodHandleImpl.Intrinsic.IDENTITY)); Object zeValue = Wrapper.forBasicType(btChar).zero(); Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) }; - zeForm = new LambdaForm(1, zeNames, 1, Kind.ZERO); + zeForm = LambdaForm.of(1, zeNames, 1, Kind.ZERO); zeForm.skipInterpreter(); zeFun = new NamedFunction(zeMem, MethodHandleImpl.makeIntrinsic(SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm), MethodHandleImpl.Intrinsic.ZERO)); diff --git a/src/java.base/share/classes/java/lang/invoke/LambdaFormBuffer.java b/src/java.base/share/classes/java/lang/invoke/LambdaFormBuffer.java index ee848589ea9cb..5df1b86865cc4 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaFormBuffer.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaFormBuffer.java @@ -59,7 +59,7 @@ final class LambdaFormBuffer { private LambdaForm lambdaForm() { assert(!inTrans()); // need endEdit call to tidy things up - return new LambdaForm(arity, nameArray(), resultIndex()); + return LambdaForm.of(arity, nameArray(), resultIndex()); } Name name(int i) { diff --git a/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java b/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java index f59037a656cde..1696ca061020a 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java @@ -1146,7 +1146,7 @@ LambdaForm permuteArgumentsForm(int skip, int[] reorder) { } } - form = new LambdaForm(arity2, names2, result2); + form = LambdaForm.of(arity2, names2, result2); return putInCache(key, form); } diff --git a/src/java.base/share/classes/java/lang/invoke/LambdaFormResolvers.java b/src/java.base/share/classes/java/lang/invoke/LambdaFormResolvers.java index b0c59920aa6c2..1f1213046d5c6 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaFormResolvers.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaFormResolvers.java @@ -77,7 +77,7 @@ static LambdaForm makeResolverForm(MethodType basicType) { assert InvokerBytecodeGenerator.isStaticallyInvocable(invokeBasic); names[INVOKE] = new Name(new NamedFunction(invokeBasic), args); - LambdaForm lform = new LambdaForm(basicType.parameterCount(), names, INVOKE, LambdaForm.Kind.RESOLVER); + LambdaForm lform = LambdaForm.of(basicType.parameterCount(), names, INVOKE, LambdaForm.Kind.RESOLVER); lform.forceCompileToBytecode(); // no cycles, compile this now return lform; } diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index 6a5033f72534a..31bd1e757d95c 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -836,7 +836,7 @@ static LambdaForm makeGuardWithTestForm(MethodType basicType) { invokeArgs[0] = names[SELECT_ALT]; names[CALL_TARGET] = new Name(basicType, invokeArgs); - lform = new LambdaForm(lambdaType.parameterCount(), names, /*forceInline=*/true, Kind.GUARD); + lform = LambdaForm.of(lambdaType.parameterCount(), names, /*forceInline=*/true, Kind.GUARD); return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform); } @@ -912,7 +912,7 @@ private static LambdaForm makeGuardWithCatchForm(MethodType basicType) { Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]}; names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs); - lform = new LambdaForm(lambdaType.parameterCount(), names, Kind.GUARD_WITH_CATCH); + lform = LambdaForm.of(lambdaType.parameterCount(), names, Kind.GUARD_WITH_CATCH); return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWC, lform); } @@ -1798,7 +1798,7 @@ private static LambdaForm makeLoopForm(MethodType basicType, BasicType[] localVa names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs); lform = basicType.form().setCachedLambdaForm(MethodTypeForm.LF_LOOP, - new LambdaForm(lambdaType.parameterCount(), names, Kind.LOOP)); + LambdaForm.of(lambdaType.parameterCount(), names, Kind.LOOP)); } // BOXED_ARGS is the index into the names array where the loop idiom starts @@ -2032,7 +2032,7 @@ private static LambdaForm makeTryFinallyForm(MethodType basicType) { Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_FINALLY]}; names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs); - lform = new LambdaForm(lambdaType.parameterCount(), names, Kind.TRY_FINALLY); + lform = LambdaForm.of(lambdaType.parameterCount(), names, Kind.TRY_FINALLY); return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_TF, lform); } @@ -2127,7 +2127,7 @@ private static LambdaForm makeCollectorForm(MethodType basicType, Class array names[CALL_NEW_ARRAY], storeIndex, names[argCursor]); } - LambdaForm lform = new LambdaForm(lambdaType.parameterCount(), names, CALL_NEW_ARRAY, Kind.COLLECTOR); + LambdaForm lform = LambdaForm.of(lambdaType.parameterCount(), names, CALL_NEW_ARRAY, Kind.COLLECTOR); if (isSharedLambdaForm) { lform = basicType.form().setCachedLambdaForm(MethodTypeForm.LF_COLLECTOR, lform); } @@ -2252,7 +2252,7 @@ private static LambdaForm makeTableSwitchForm(MethodType basicType, BoundMethodH names[UNBOXED_RESULT] = new Name(invokeBasic, unboxArgs); } - lform = new LambdaForm(lambdaType.parameterCount(), names, Kind.TABLE_SWITCH); + lform = LambdaForm.of(lambdaType.parameterCount(), names, Kind.TABLE_SWITCH); LambdaForm prev = TableSwitchCacheKey.CACHE.putIfAbsent(key, lform); return prev != null ? prev : lform; } diff --git a/src/java.base/share/classes/java/lang/invoke/NativeMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/NativeMethodHandle.java index 5247031498953..83dfd0f0122e5 100644 --- a/src/java.base/share/classes/java/lang/invoke/NativeMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/NativeMethodHandle.java @@ -117,7 +117,7 @@ private static LambdaForm makePreparedLambdaForm(MethodType mtype) { outArgs[outArgs.length - 1] = names[GET_NEP]; names[LINKER_CALL] = new LambdaForm.Name(linker, outArgs); - LambdaForm lform = new LambdaForm(ARG_LIMIT, names, LAST_RESULT); + LambdaForm lform = LambdaForm.of(ARG_LIMIT, names, LAST_RESULT); lform.skipInterpreter(); return lform; }