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 d3986a38dab..44bca025b8b 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 @@ abstract sealed class DelegatingMethodHandle extends MethodHandle 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.create(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 00a187205dc..7373b4d846e 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 @@ sealed class DirectMethodHandle extends MethodHandle { result = NEW_OBJ; } names[LINKER_CALL] = new Name(linker, outArgs); - LambdaForm lform = new LambdaForm(ARG_LIMIT, names, result, kind); + LambdaForm lform = LambdaForm.create(ARG_LIMIT, names, result, kind); // This is a tricky bit of code. Don't send it through the LF interpreter. lform.compileToBytecode(); @@ -814,9 +814,9 @@ sealed class DirectMethodHandle extends MethodHandle { 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.create(ARG_LIMIT, names, RESULT); } else { - form = new LambdaForm(ARG_LIMIT, names, RESULT, kind); + form = LambdaForm.create(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 1629cf59524..bcfdac98486 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 @@ class Invokers { } names[LINKER_CALL] = new Name(outCallType, outArgs); if (customized) { - lform = new LambdaForm(INARG_LIMIT, names); + lform = LambdaForm.create(INARG_LIMIT, names); } else { - lform = new LambdaForm(INARG_LIMIT, names, kind); + lform = LambdaForm.create(INARG_LIMIT, names, kind); } if (isLinker) lform.compileToBytecode(); // JVM needs a real methodOop @@ -415,7 +415,7 @@ class Invokers { 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.create(ARG_LIMIT + 1, names, VARHANDLE_LINKER); if (LambdaForm.debugNames()) { String name = "VarHandle_invoke_MT_" + shortenSignature(basicTypeSignature(mtype)); LambdaForm.associateWithDebugName(lform, name); @@ -477,7 +477,7 @@ class Invokers { .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.create(ARG_LIMIT, names, kind); if (LambdaForm.debugNames()) { String name = (isExact ? "VarHandle_exactInvoker_" : "VarHandle_invoker_") + shortenSignature(basicTypeSignature(mtype)); LambdaForm.associateWithDebugName(lform, name); @@ -604,7 +604,7 @@ class Invokers { 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.create(INARG_LIMIT, names, (skipCallSite ? LINK_TO_TARGET_METHOD : LINK_TO_CALL_SITE)); lform.compileToBytecode(); // 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 b8592ced555..1e150654e12 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java @@ -330,55 +330,69 @@ class LambdaForm { } } - 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) { - this(arity, names, result, forceInline, customized, Kind.GENERIC); - } - LambdaForm(int arity, Name[] names, int result, boolean forceInline, MethodHandle customized, Kind kind) { - assert(namesOK(arity, names)); + // private version that doesn't do checks or defensive copies + private LambdaForm(int arity, int result, boolean forceInline, MethodHandle customized, Name[] names, Kind kind) { this.arity = arity; - this.result = fixResult(result, names); - this.names = names.clone(); + 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); - compileToBytecode(); - } - } - LambdaForm(int arity, Name[] names) { - this(arity, names, LAST_RESULT, /*forceInline=*/true, /*customized=*/null, Kind.GENERIC); - } - LambdaForm(int arity, Name[] names, Kind kind) { - this(arity, names, LAST_RESULT, /*forceInline=*/true, /*customized=*/null, kind); - } - LambdaForm(int arity, Name[] names, boolean forceInline, Kind kind) { - this(arity, names, LAST_RESULT, forceInline, /*customized=*/null, kind); + this.vmentry = null; + this.isCompiled = false; } - private LambdaForm(MethodType mt) { + // root factory pre/post processing and calls simple cosntructor + private static LambdaForm create(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); + assert(form.nameRefsAreLegal()); + if (!canInterpret) { + form.compileToBytecode(); + } + return form; + } + + // derived factories with defaults + 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; + + static LambdaForm create(int arity, Name[] names, int result) { + return create(arity, names, result, DEFAULT_FORCE_INLINE, DEFAULT_CUSTOMIZED, DEFAULT_KIND); + } + static LambdaForm create(int arity, Name[] names, int result, Kind kind) { + return create(arity, names, result, DEFAULT_FORCE_INLINE, DEFAULT_CUSTOMIZED, kind); + } + static LambdaForm create(int arity, Name[] names) { + return create(arity, names, DEFAULT_RESULT, DEFAULT_FORCE_INLINE, DEFAULT_CUSTOMIZED, DEFAULT_KIND); + } + static LambdaForm create(int arity, Name[] names, Kind kind) { + return create(arity, names, DEFAULT_RESULT, DEFAULT_FORCE_INLINE, DEFAULT_CUSTOMIZED, kind); + } + static LambdaForm create(int arity, Name[] names, boolean forceInline, Kind kind) { + return create(arity, names, DEFAULT_RESULT, forceInline, DEFAULT_CUSTOMIZED, kind); + } + + 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. - this.arity = mt.parameterCount(); - this.result = (mt.returnType() == void.class || mt.returnType() == Void.class) ? -1 : arity; - this.names = buildEmptyNames(arity, mt, result == -1); - this.forceInline = true; - this.customized = null; - this.kind = Kind.ZERO; - assert(nameRefsAreLegal()); - assert(isEmpty()); - String sig = null; - assert(isValidSignature(sig = basicTypeSignature())); - assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature(); + int arity = mt.parameterCount(); + 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); + assert(form.nameRefsAreLegal() && form.isEmpty() && isValidSignature(form.basicTypeSignature())); + if (!canInterpret) { + form.compileToBytecode(); + } + return form; } private static Name[] buildEmptyNames(int arity, MethodType mt, boolean isVoid) { @@ -387,6 +401,7 @@ class LambdaForm { Name zero = new Name(constantZero(basicType(mt.returnType()))); names[arity] = zero.newIndex(arity); } + assert(namesOK(arity, names)); return names; } @@ -457,7 +472,7 @@ class LambdaForm { if (customized == mh) { return this; } - LambdaForm customForm = new LambdaForm(arity, names, result, forceInline, mh, kind); + LambdaForm customForm = LambdaForm.create(arity, names, result, forceInline, mh, kind); if (COMPILE_THRESHOLD >= 0 && isCompiled) { // If shared LambdaForm has been compiled, compile customized version as well. customForm.compileToBytecode(); @@ -481,9 +496,9 @@ class LambdaForm { } /** 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; @@ -508,7 +523,6 @@ class LambdaForm { 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++) { @@ -523,8 +537,14 @@ class LambdaForm { 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; } /** @@ -804,7 +824,7 @@ class LambdaForm { LambdaForm prep = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INTERPRET); if (prep == null) { assert (isValidSignature(basicTypeSignature())); - prep = new LambdaForm(mtype); + prep = LambdaForm.createBlankForType(mtype); prep.vmentry = InvokerBytecodeGenerator.generateLambdaFormInterpreterEntryPoint(mtype); prep = mtype.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, prep); } @@ -1748,7 +1768,7 @@ class LambdaForm { // 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.create(1, idNames, VOID_RESULT, Kind.IDENTITY); idForm.compileToBytecode(); idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm)); @@ -1756,14 +1776,14 @@ class LambdaForm { zeFun = idFun; } else { Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) }; - idForm = new LambdaForm(2, idNames, 1, Kind.IDENTITY); + idForm = LambdaForm.create(2, idNames, 1, Kind.IDENTITY); idForm.compileToBytecode(); 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.create(1, zeNames, 1, Kind.ZERO); zeForm.compileToBytecode(); 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 ee848589ea9..e249d6205ce 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.create(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 f59037a656c..cad6b9b5e40 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java @@ -29,7 +29,6 @@ import sun.invoke.util.Wrapper; import java.lang.ref.SoftReference; import java.util.Arrays; -import java.util.Collections; import java.util.Comparator; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; @@ -1146,7 +1145,7 @@ class LambdaFormEditor { } } - form = new LambdaForm(arity2, names2, result2); + form = LambdaForm.create(arity2, names2, result2); return putInCache(key, form); } 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 ba579e28f15..fc565d74180 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 @@ abstract class MethodHandleImpl { invokeArgs[0] = names[SELECT_ALT]; names[CALL_TARGET] = new Name(basicType, invokeArgs); - lform = new LambdaForm(lambdaType.parameterCount(), names, /*forceInline=*/true, Kind.GUARD); + lform = LambdaForm.create(lambdaType.parameterCount(), names, /*forceInline=*/true, Kind.GUARD); return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform); } @@ -912,7 +912,7 @@ abstract class MethodHandleImpl { 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.create(lambdaType.parameterCount(), names, Kind.GUARD_WITH_CATCH); return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWC, lform); } @@ -1798,7 +1798,7 @@ abstract class MethodHandleImpl { names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs); lform = basicType.form().setCachedLambdaForm(MethodTypeForm.LF_LOOP, - new LambdaForm(lambdaType.parameterCount(), names, Kind.LOOP)); + LambdaForm.create(lambdaType.parameterCount(), names, Kind.LOOP)); } // BOXED_ARGS is the index into the names array where the loop idiom starts @@ -2032,7 +2032,7 @@ abstract class MethodHandleImpl { 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.create(lambdaType.parameterCount(), names, Kind.TRY_FINALLY); return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_TF, lform); } @@ -2127,7 +2127,7 @@ abstract class MethodHandleImpl { names[CALL_NEW_ARRAY], storeIndex, names[argCursor]); } - LambdaForm lform = new LambdaForm(lambdaType.parameterCount(), names, CALL_NEW_ARRAY, Kind.COLLECTOR); + LambdaForm lform = LambdaForm.create(lambdaType.parameterCount(), names, CALL_NEW_ARRAY, Kind.COLLECTOR); if (isSharedLambdaForm) { lform = basicType.form().setCachedLambdaForm(MethodTypeForm.LF_COLLECTOR, lform); } @@ -2252,7 +2252,7 @@ abstract class MethodHandleImpl { names[UNBOXED_RESULT] = new Name(invokeBasic, unboxArgs); } - lform = new LambdaForm(lambdaType.parameterCount(), names, Kind.TABLE_SWITCH); + lform = LambdaForm.create(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 4b7cf8d7ef3..f7e5abbc073 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 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError; 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.create(ARG_LIMIT, names, LAST_RESULT); // This is a tricky bit of code. Don't send it through the LF interpreter. lform.compileToBytecode(); return lform;