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
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);
}

View file

@ -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()) {

View file

@ -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);

View file

@ -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));

View file

@ -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) {

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;