Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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()) {
Expand Down
10 changes: 5 additions & 5 deletions src/java.base/share/classes/java/lang/invoke/Invokers.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
108 changes: 65 additions & 43 deletions src/java.base/share/classes/java/lang/invoke/LambdaForm.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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();
Expand All @@ -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;
Expand All @@ -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++) {
Expand All @@ -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;
}

/**
Expand Down Expand Up @@ -1847,22 +1869,22 @@ 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));

zeForm = idForm;
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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down