< prev index next >
src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java
Print this page
rev 13050 : 8142334: Improve lazy initialization of java.lang.invoke
Reviewed-by: psandoz, vlivanov, mhaupt
@@ -222,16 +222,16 @@
final int LINKER_CALL = nameCursor++;
Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
assert(names.length == nameCursor);
if (doesAlloc) {
// names = { argx,y,z,... new C, init method }
- names[NEW_OBJ] = new Name(Lazy.NF_allocateInstance, names[DMH_THIS]);
- names[GET_MEMBER] = new Name(Lazy.NF_constructorMethod, names[DMH_THIS]);
+ names[NEW_OBJ] = new Name(getConstantFunction(NF_allocateInstance), names[DMH_THIS]);
+ names[GET_MEMBER] = new Name(getConstantFunction(NF_constructorMethod), names[DMH_THIS]);
} else if (needsInit) {
- names[GET_MEMBER] = new Name(Lazy.NF_internalMemberNameEnsureInit, names[DMH_THIS]);
+ names[GET_MEMBER] = new Name(getConstantFunction(NF_internalMemberNameEnsureInit), names[DMH_THIS]);
} else {
- names[GET_MEMBER] = new Name(Lazy.NF_internalMemberName, names[DMH_THIS]);
+ names[GET_MEMBER] = new Name(getConstantFunction(NF_internalMemberName), names[DMH_THIS]);
}
assert(findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]);
Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
assert(outArgs[outArgs.length-1] == names[GET_MEMBER]); // look, shifted args!
int result = LAST_RESULT;
@@ -248,13 +248,13 @@
lform.compileToBytecode();
return lform;
}
static Object findDirectMethodHandle(Name name) {
- if (name.function == Lazy.NF_internalMemberName ||
- name.function == Lazy.NF_internalMemberNameEnsureInit ||
- name.function == Lazy.NF_constructorMethod) {
+ if (Objects.equals(name.function, getConstantFunction(NF_internalMemberName)) ||
+ Objects.equals(name.function, getConstantFunction(NF_internalMemberNameEnsureInit)) ||
+ Objects.equals(name.function, getConstantFunction(NF_constructorMethod))) {
assert(name.arguments.length == 1);
return name.arguments[0];
}
return null;
}
@@ -489,25 +489,26 @@
Object checkCast(Object obj) {
return member.getReturnType().cast(obj);
}
// Caching machinery for field accessors:
- private static byte
+ private static final byte
AF_GETFIELD = 0,
AF_PUTFIELD = 1,
AF_GETSTATIC = 2,
AF_PUTSTATIC = 3,
AF_GETSTATIC_INIT = 4,
AF_PUTSTATIC_INIT = 5,
AF_LIMIT = 6;
// Enumerate the different field kinds using Wrapper,
// with an extra case added for checked references.
- private static int
+ private static final int
FT_LAST_WRAPPER = Wrapper.values().length-1,
FT_UNCHECKED_REF = Wrapper.OBJECT.ordinal(),
FT_CHECKED_REF = FT_LAST_WRAPPER+1,
FT_LIMIT = FT_LAST_WRAPPER+2;
+
private static int afIndex(byte formOp, boolean isVolatile, int ftypeKind) {
return ((formOp * FT_LIMIT * 2)
+ (isVolatile ? FT_LIMIT : 0)
+ ftypeKind);
}
@@ -611,84 +612,113 @@
final int LINKER_CALL = nameCursor++;
final int POST_CAST = (needsCast && isGetter ? nameCursor++ : -1);
final int RESULT = nameCursor-1; // either the call or the cast
Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
if (needsInit)
- names[INIT_BAR] = new Name(Lazy.NF_ensureInitialized, names[DMH_THIS]);
+ names[INIT_BAR] = new Name(getConstantFunction(NF_ensureInitialized), names[DMH_THIS]);
if (needsCast && !isGetter)
- names[PRE_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
+ names[PRE_CAST] = new Name(getConstantFunction(NF_checkCast), names[DMH_THIS], names[SET_VALUE]);
Object[] outArgs = new Object[1 + linkerType.parameterCount()];
assert(outArgs.length == (isGetter ? 3 : 4));
outArgs[0] = UNSAFE;
if (isStatic) {
- outArgs[1] = names[F_HOLDER] = new Name(Lazy.NF_staticBase, names[DMH_THIS]);
- outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_staticOffset, names[DMH_THIS]);
+ outArgs[1] = names[F_HOLDER] = new Name(getConstantFunction(NF_staticBase), names[DMH_THIS]);
+ outArgs[2] = names[F_OFFSET] = new Name(getConstantFunction(NF_staticOffset), names[DMH_THIS]);
} else {
- outArgs[1] = names[OBJ_CHECK] = new Name(Lazy.NF_checkBase, names[OBJ_BASE]);
- outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_fieldOffset, names[DMH_THIS]);
+ outArgs[1] = names[OBJ_CHECK] = new Name(getConstantFunction(NF_checkBase), names[OBJ_BASE]);
+ outArgs[2] = names[F_OFFSET] = new Name(getConstantFunction(NF_fieldOffset), names[DMH_THIS]);
}
if (!isGetter) {
outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
}
for (Object a : outArgs) assert(a != null);
names[LINKER_CALL] = new Name(linker, outArgs);
if (needsCast && isGetter)
- names[POST_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
+ names[POST_CAST] = new Name(getConstantFunction(NF_checkCast), names[DMH_THIS], names[LINKER_CALL]);
for (Name n : names) assert(n != null);
String fieldOrStatic = (isStatic ? "Static" : "Field");
String lambdaName = (linkerName + fieldOrStatic); // significant only for debugging
if (needsCast) lambdaName += "Cast";
if (needsInit) lambdaName += "Init";
return new LambdaForm(lambdaName, ARG_LIMIT, names, RESULT);
}
+ private static NamedFunction getConstantFunction(int idx) {
+ NamedFunction function = FUNCTIONS[idx];
+ if (function != null) {
+ return function;
+ }
+ return setCachedFunction(idx, makeConstantFunction(idx));
+ }
+
+ private static synchronized NamedFunction setCachedFunction(int idx, final NamedFunction function) {
+ // Simulate a CAS, to avoid racy duplication of results.
+ NamedFunction prev = FUNCTIONS[idx];
+ if (prev != null) {
+ return prev;
+ }
+ function.resolve();
+ UNSAFE.storeFence();
+ FUNCTIONS[idx] = function;
+ return function;
+ }
+
+ // Indexes into constant functions:
+ private static final int
+ NF_internalMemberName = 0,
+ NF_internalMemberNameEnsureInit = 1,
+ NF_ensureInitialized = 2,
+ NF_fieldOffset = 3,
+ NF_checkBase = 4,
+ NF_staticBase = 5,
+ NF_staticOffset = 6,
+ NF_checkCast = 7,
+ NF_allocateInstance = 8,
+ NF_constructorMethod = 9,
+ NF_LIMIT = 10;
+
/**
- * Pre-initialized NamedFunctions for bootstrapping purposes.
- * Factored in an inner class to delay initialization until first usage.
+ * Statically initialized NamedFunctions for bootstrapping purposes.
+ * Delay initialization until first usage.
*/
- private static class Lazy {
- static final NamedFunction
- NF_internalMemberName,
- NF_internalMemberNameEnsureInit,
- NF_ensureInitialized,
- NF_fieldOffset,
- NF_checkBase,
- NF_staticBase,
- NF_staticOffset,
- NF_checkCast,
- NF_allocateInstance,
- NF_constructorMethod;
- static {
+ private static final @Stable NamedFunction[] FUNCTIONS = new NamedFunction[NF_LIMIT];
+
+ private static NamedFunction makeConstantFunction(int idx) {
try {
- NamedFunction nfs[] = {
- NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("internalMemberName", Object.class)),
- NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
- NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("ensureInitialized", Object.class)),
- NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("fieldOffset", Object.class)),
- NF_checkBase = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("checkBase", Object.class)),
- NF_staticBase = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("staticBase", Object.class)),
- NF_staticOffset = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("staticOffset", Object.class)),
- NF_checkCast = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("checkCast", Object.class, Object.class)),
- NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("allocateInstance", Object.class)),
- NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("constructorMethod", Object.class))
- };
- for (NamedFunction nf : nfs) {
- // Each nf must be statically invocable or we get tied up in our bootstraps.
- assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
- nf.resolve();
+ switch (idx) {
+ case NF_internalMemberName:
+ return new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("internalMemberName", Object.class));
+ case NF_internalMemberNameEnsureInit:
+ return new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("internalMemberNameEnsureInit", Object.class));
+ case NF_ensureInitialized:
+ return new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("ensureInitialized", Object.class));
+ case NF_fieldOffset:
+ return new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("fieldOffset", Object.class));
+ case NF_checkBase:
+ return new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("checkBase", Object.class));
+ case NF_staticBase:
+ return new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("staticBase", Object.class));
+ case NF_staticOffset:
+ return new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("staticOffset", Object.class));
+ case NF_checkCast:
+ return new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("checkCast", Object.class, Object.class));
+ case NF_allocateInstance:
+ return new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("allocateInstance", Object.class));
+ case NF_constructorMethod:
+ return new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("constructorMethod", Object.class));
}
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
- }
+ throw newInternalError("Unknown function index: " + idx);
}
}
< prev index next >