8298590: Refactor LambdaForm constructors

Reviewed-by: redestad
This commit is contained in:
Jorn Vernee 2023-01-02 12:06:26 +00:00
parent d812022890
commit 0532045edb
8 changed files with 88 additions and 69 deletions

View file

@ -159,7 +159,7 @@ abstract sealed class DelegatingMethodHandle extends MethodHandle
targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH
names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs); 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) { if (!customized) {
form = mtype.form().setCachedLambdaForm(whichCache, form); form = mtype.form().setCachedLambdaForm(whichCache, form);
} }

View file

@ -297,7 +297,7 @@ sealed class DirectMethodHandle extends MethodHandle {
result = NEW_OBJ; result = NEW_OBJ;
} }
names[LINKER_CALL] = new Name(linker, outArgs); 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. // This is a tricky bit of code. Don't send it through the LF interpreter.
lform.compileToBytecode(); lform.compileToBytecode();
@ -814,9 +814,9 @@ sealed class DirectMethodHandle extends MethodHandle {
LambdaForm form; LambdaForm form;
if (needsCast || needsInit) { if (needsCast || needsInit) {
// can't use the pre-generated form when casting and/or initializing // 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 { } else {
form = new LambdaForm(ARG_LIMIT, names, RESULT, kind); form = LambdaForm.create(ARG_LIMIT, names, RESULT, kind);
} }
if (LambdaForm.debugNames()) { if (LambdaForm.debugNames()) {

View file

@ -351,9 +351,9 @@ class Invokers {
} }
names[LINKER_CALL] = new Name(outCallType, outArgs); names[LINKER_CALL] = new Name(outCallType, outArgs);
if (customized) { if (customized) {
lform = new LambdaForm(INARG_LIMIT, names); lform = LambdaForm.create(INARG_LIMIT, names);
} else { } else {
lform = new LambdaForm(INARG_LIMIT, names, kind); lform = LambdaForm.create(INARG_LIMIT, names, kind);
} }
if (isLinker) if (isLinker)
lform.compileToBytecode(); // JVM needs a real methodOop lform.compileToBytecode(); // JVM needs a real methodOop
@ -415,7 +415,7 @@ class Invokers {
MethodType outCallType = mtype.insertParameterTypes(0, VarHandle.class) MethodType outCallType = mtype.insertParameterTypes(0, VarHandle.class)
.basicType(); .basicType();
names[LINKER_CALL] = new Name(outCallType, outArgs); 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()) { if (LambdaForm.debugNames()) {
String name = "VarHandle_invoke_MT_" + shortenSignature(basicTypeSignature(mtype)); String name = "VarHandle_invoke_MT_" + shortenSignature(basicTypeSignature(mtype));
LambdaForm.associateWithDebugName(lform, name); LambdaForm.associateWithDebugName(lform, name);
@ -477,7 +477,7 @@ class Invokers {
.basicType(); .basicType();
names[LINKER_CALL] = new Name(outCallType, outArgs); names[LINKER_CALL] = new Name(outCallType, outArgs);
Kind kind = isExact ? VARHANDLE_EXACT_INVOKER : VARHANDLE_INVOKER; 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()) { if (LambdaForm.debugNames()) {
String name = (isExact ? "VarHandle_exactInvoker_" : "VarHandle_invoker_") + shortenSignature(basicTypeSignature(mtype)); String name = (isExact ? "VarHandle_exactInvoker_" : "VarHandle_invoker_") + shortenSignature(basicTypeSignature(mtype));
LambdaForm.associateWithDebugName(lform, name); LambdaForm.associateWithDebugName(lform, name);
@ -604,7 +604,7 @@ class Invokers {
System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT); System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
outArgs[PREPEND_MH] = names[CALL_MH]; outArgs[PREPEND_MH] = names[CALL_MH];
names[LINKER_CALL] = new Name(mtype, outArgs); 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)); (skipCallSite ? LINK_TO_TARGET_METHOD : LINK_TO_CALL_SITE));
lform.compileToBytecode(); // JVM needs a real methodOop lform.compileToBytecode(); // JVM needs a real methodOop
lform = mtype.form().setCachedLambdaForm(which, lform); lform = mtype.form().setCachedLambdaForm(which, lform);

View file

@ -330,55 +330,69 @@ class LambdaForm {
} }
} }
LambdaForm(int arity, Name[] names, int result) { // private version that doesn't do checks or defensive copies
this(arity, names, result, /*forceInline=*/true, /*customized=*/null, Kind.GENERIC); private LambdaForm(int arity, int result, boolean forceInline, MethodHandle customized, Name[] names, Kind kind) {
}
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));
this.arity = arity; this.arity = arity;
this.result = fixResult(result, names); this.result = result;
this.names = names.clone();
this.forceInline = forceInline; this.forceInline = forceInline;
this.customized = customized; this.customized = customized;
this.names = names;
this.kind = kind; this.kind = kind;
int maxOutArity = normalize(); this.vmentry = null;
if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) { this.isCompiled = false;
// 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);
} }
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. // 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. // It is used as a template for managing the invocation of similar forms that are non-empty.
// Called only from getPreparedForm. // Called only from getPreparedForm.
this.arity = mt.parameterCount(); int arity = mt.parameterCount();
this.result = (mt.returnType() == void.class || mt.returnType() == Void.class) ? -1 : arity; int result = (mt.returnType() == void.class || mt.returnType() == Void.class) ? VOID_RESULT : arity;
this.names = buildEmptyNames(arity, mt, result == -1); Name[] names = buildEmptyNames(arity, mt, result == VOID_RESULT);
this.forceInline = true; boolean canInterpret = normalizeNames(arity, names);
this.customized = null; LambdaForm form = new LambdaForm(arity, result, DEFAULT_FORCE_INLINE, DEFAULT_CUSTOMIZED, names, Kind.ZERO);
this.kind = Kind.ZERO; assert(form.nameRefsAreLegal() && form.isEmpty() && isValidSignature(form.basicTypeSignature()));
assert(nameRefsAreLegal()); if (!canInterpret) {
assert(isEmpty()); form.compileToBytecode();
String sig = null; }
assert(isValidSignature(sig = basicTypeSignature())); return form;
assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
} }
private static Name[] buildEmptyNames(int arity, MethodType mt, boolean isVoid) { private static Name[] buildEmptyNames(int arity, MethodType mt, boolean isVoid) {
@ -387,6 +401,7 @@ class LambdaForm {
Name zero = new Name(constantZero(basicType(mt.returnType()))); Name zero = new Name(constantZero(basicType(mt.returnType())));
names[arity] = zero.newIndex(arity); names[arity] = zero.newIndex(arity);
} }
assert(namesOK(arity, names));
return names; return names;
} }
@ -457,7 +472,7 @@ class LambdaForm {
if (customized == mh) { if (customized == mh) {
return this; 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 (COMPILE_THRESHOLD >= 0 && isCompiled) {
// If shared LambdaForm has been compiled, compile customized version as well. // If shared LambdaForm has been compiled, compile customized version as well.
customForm.compileToBytecode(); customForm.compileToBytecode();
@ -481,9 +496,9 @@ class LambdaForm {
} }
/** Renumber and/or replace params so that they are interned and canonically numbered. /** 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; Name[] oldNames = null;
int maxOutArity = 0; int maxOutArity = 0;
int changesStart = 0; int changesStart = 0;
@ -508,7 +523,6 @@ class LambdaForm {
names[i] = fixed.newIndex(i); names[i] = fixed.newIndex(i);
} }
} }
assert(nameRefsAreLegal());
int maxInterned = Math.min(arity, INTERNED_ARGUMENT_LIMIT); int maxInterned = Math.min(arity, INTERNED_ARGUMENT_LIMIT);
boolean needIntern = false; boolean needIntern = false;
for (int i = 0; i < maxInterned; i++) { for (int i = 0; i < maxInterned; i++) {
@ -523,8 +537,14 @@ class LambdaForm {
names[i].internArguments(); 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); LambdaForm prep = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INTERPRET);
if (prep == null) { if (prep == null) {
assert (isValidSignature(basicTypeSignature())); assert (isValidSignature(basicTypeSignature()));
prep = new LambdaForm(mtype); prep = LambdaForm.createBlankForType(mtype);
prep.vmentry = InvokerBytecodeGenerator.generateLambdaFormInterpreterEntryPoint(mtype); prep.vmentry = InvokerBytecodeGenerator.generateLambdaFormInterpreterEntryPoint(mtype);
prep = mtype.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, prep); 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 // bootstrap dependency on this method in case we're interpreting LFs
if (isVoid) { if (isVoid) {
Name[] idNames = new Name[] { argument(0, L_TYPE) }; 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(); idForm.compileToBytecode();
idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm)); idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm));
@ -1756,14 +1776,14 @@ class LambdaForm {
zeFun = idFun; zeFun = idFun;
} else { } else {
Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) }; 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(); idForm.compileToBytecode();
idFun = new NamedFunction(idMem, MethodHandleImpl.makeIntrinsic(SimpleMethodHandle.make(idMem.getInvocationType(), idForm), idFun = new NamedFunction(idMem, MethodHandleImpl.makeIntrinsic(SimpleMethodHandle.make(idMem.getInvocationType(), idForm),
MethodHandleImpl.Intrinsic.IDENTITY)); MethodHandleImpl.Intrinsic.IDENTITY));
Object zeValue = Wrapper.forBasicType(btChar).zero(); Object zeValue = Wrapper.forBasicType(btChar).zero();
Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) }; 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(); zeForm.compileToBytecode();
zeFun = new NamedFunction(zeMem, MethodHandleImpl.makeIntrinsic(SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm), zeFun = new NamedFunction(zeMem, MethodHandleImpl.makeIntrinsic(SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm),
MethodHandleImpl.Intrinsic.ZERO)); MethodHandleImpl.Intrinsic.ZERO));

View file

@ -59,7 +59,7 @@ final class LambdaFormBuffer {
private LambdaForm lambdaForm() { private LambdaForm lambdaForm() {
assert(!inTrans()); // need endEdit call to tidy things up 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) { Name name(int i) {

View file

@ -29,7 +29,6 @@ import sun.invoke.util.Wrapper;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap; 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); return putInCache(key, form);
} }

View file

@ -836,7 +836,7 @@ abstract class MethodHandleImpl {
invokeArgs[0] = names[SELECT_ALT]; invokeArgs[0] = names[SELECT_ALT];
names[CALL_TARGET] = new Name(basicType, invokeArgs); 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); 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]}; Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]};
names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs); 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); return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWC, lform);
} }
@ -1798,7 +1798,7 @@ abstract class MethodHandleImpl {
names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs); names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs);
lform = basicType.form().setCachedLambdaForm(MethodTypeForm.LF_LOOP, 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 // 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]}; Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_FINALLY]};
names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs); 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); return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_TF, lform);
} }
@ -2127,7 +2127,7 @@ abstract class MethodHandleImpl {
names[CALL_NEW_ARRAY], storeIndex, names[argCursor]); 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) { if (isSharedLambdaForm) {
lform = basicType.form().setCachedLambdaForm(MethodTypeForm.LF_COLLECTOR, lform); lform = basicType.form().setCachedLambdaForm(MethodTypeForm.LF_COLLECTOR, lform);
} }
@ -2252,7 +2252,7 @@ abstract class MethodHandleImpl {
names[UNBOXED_RESULT] = new Name(invokeBasic, unboxArgs); 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); LambdaForm prev = TableSwitchCacheKey.CACHE.putIfAbsent(key, lform);
return prev != null ? prev : lform; return prev != null ? prev : lform;
} }

View file

@ -117,7 +117,7 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError;
outArgs[outArgs.length - 1] = names[GET_NEP]; outArgs[outArgs.length - 1] = names[GET_NEP];
names[LINKER_CALL] = new LambdaForm.Name(linker, outArgs); 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. // This is a tricky bit of code. Don't send it through the LF interpreter.
lform.compileToBytecode(); lform.compileToBytecode();
return lform; return lform;