< prev index next >
src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java
Print this page
rev 15427 : 8164483: Generate field lambda forms at link time
Reviewed-by: TBD
*** 485,510 ****
@ForceInline
/*non-public*/ static Object checkCast(Object mh, Object obj) {
return ((DirectMethodHandle) mh).checkCast(obj);
}
Object checkCast(Object obj) {
return member.getReturnType().cast(obj);
}
// Caching machinery for field accessors:
! 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 final int
FT_LAST_WRAPPER = Wrapper.COUNT-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) {
--- 485,515 ----
@ForceInline
/*non-public*/ static Object checkCast(Object mh, Object obj) {
return ((DirectMethodHandle) mh).checkCast(obj);
}
+ @ForceInline
+ /*non-public*/ static Unsafe unsafe() {
+ return UNSAFE;
+ }
+
Object checkCast(Object obj) {
return member.getReturnType().cast(obj);
}
// Caching machinery for field accessors:
! 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.
! static final int
FT_LAST_WRAPPER = Wrapper.COUNT-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) {
*** 513,523 ****
+ ftypeKind);
}
@Stable
private static final LambdaForm[] ACCESSOR_FORMS
= new LambdaForm[afIndex(AF_LIMIT, false, 0)];
! private static int ftypeKind(Class<?> ftype) {
if (ftype.isPrimitive())
return Wrapper.forPrimitiveType(ftype).ordinal();
else if (VerifyType.isNullReferenceConversion(Object.class, ftype))
return FT_UNCHECKED_REF;
else
--- 518,528 ----
+ ftypeKind);
}
@Stable
private static final LambdaForm[] ACCESSOR_FORMS
= new LambdaForm[afIndex(AF_LIMIT, false, 0)];
! static int ftypeKind(Class<?> ftype) {
if (ftype.isPrimitive())
return Wrapper.forPrimitiveType(ftype).ordinal();
else if (VerifyType.isNullReferenceConversion(Object.class, ftype))
return FT_UNCHECKED_REF;
else
*** 564,601 ****
return lform;
}
private static final Wrapper[] ALL_WRAPPERS = Wrapper.values();
! private static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
boolean isGetter = (formOp & 1) == (AF_GETFIELD & 1);
boolean isStatic = (formOp >= AF_GETSTATIC);
boolean needsInit = (formOp >= AF_GETSTATIC_INIT);
boolean needsCast = (ftypeKind == FT_CHECKED_REF);
Wrapper fw = (needsCast ? Wrapper.OBJECT : ALL_WRAPPERS[ftypeKind]);
Class<?> ft = fw.primitiveType();
assert(ftypeKind(needsCast ? String.class : ft) == ftypeKind);
// getObject, putIntVolatile, etc.
! StringBuilder nameBuilder = new StringBuilder();
! if (isGetter) {
! nameBuilder.append("get");
! } else {
! nameBuilder.append("put");
! }
! nameBuilder.append(fw.primitiveSimpleName());
! nameBuilder.setCharAt(3, Character.toUpperCase(nameBuilder.charAt(3)));
! if (isVolatile) {
! nameBuilder.append("Volatile");
! }
MethodType linkerType;
if (isGetter)
linkerType = MethodType.methodType(ft, Object.class, long.class);
else
linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
! MemberName linker = new MemberName(Unsafe.class, nameBuilder.toString(), linkerType, REF_invokeVirtual);
try {
linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class);
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
--- 569,653 ----
return lform;
}
private static final Wrapper[] ALL_WRAPPERS = Wrapper.values();
! private static Kind getFieldKind(boolean isGetter, boolean isVolatile, Wrapper wrapper) {
! if (isGetter) {
! if (isVolatile) {
! switch (wrapper) {
! case BOOLEAN: return GET_BOOLEAN_VOLATILE;
! case BYTE: return GET_BYTE_VOLATILE;
! case SHORT: return GET_SHORT_VOLATILE;
! case CHAR: return GET_CHAR_VOLATILE;
! case INT: return GET_INT_VOLATILE;
! case LONG: return GET_LONG_VOLATILE;
! case FLOAT: return GET_FLOAT_VOLATILE;
! case DOUBLE: return GET_DOUBLE_VOLATILE;
! case OBJECT: return GET_OBJECT_VOLATILE;
! }
! } else {
! switch (wrapper) {
! case BOOLEAN: return GET_BOOLEAN;
! case BYTE: return GET_BYTE;
! case SHORT: return GET_SHORT;
! case CHAR: return GET_CHAR;
! case INT: return GET_INT;
! case LONG: return GET_LONG;
! case FLOAT: return GET_FLOAT;
! case DOUBLE: return GET_DOUBLE;
! case OBJECT: return GET_OBJECT;
! }
! }
! } else {
! if (isVolatile) {
! switch (wrapper) {
! case BOOLEAN: return PUT_BOOLEAN_VOLATILE;
! case BYTE: return PUT_BYTE_VOLATILE;
! case SHORT: return PUT_SHORT_VOLATILE;
! case CHAR: return PUT_CHAR_VOLATILE;
! case INT: return PUT_INT_VOLATILE;
! case LONG: return PUT_LONG_VOLATILE;
! case FLOAT: return PUT_FLOAT_VOLATILE;
! case DOUBLE: return PUT_DOUBLE_VOLATILE;
! case OBJECT: return PUT_OBJECT_VOLATILE;
! }
! } else {
! switch (wrapper) {
! case BOOLEAN: return PUT_BOOLEAN;
! case BYTE: return PUT_BYTE;
! case SHORT: return PUT_SHORT;
! case CHAR: return PUT_CHAR;
! case INT: return PUT_INT;
! case LONG: return PUT_LONG;
! case FLOAT: return PUT_FLOAT;
! case DOUBLE: return PUT_DOUBLE;
! case OBJECT: return PUT_OBJECT;
! }
! }
! }
! throw new AssertionError("Invalid arguments");
! }
!
! static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
boolean isGetter = (formOp & 1) == (AF_GETFIELD & 1);
boolean isStatic = (formOp >= AF_GETSTATIC);
boolean needsInit = (formOp >= AF_GETSTATIC_INIT);
boolean needsCast = (ftypeKind == FT_CHECKED_REF);
Wrapper fw = (needsCast ? Wrapper.OBJECT : ALL_WRAPPERS[ftypeKind]);
Class<?> ft = fw.primitiveType();
assert(ftypeKind(needsCast ? String.class : ft) == ftypeKind);
// getObject, putIntVolatile, etc.
! Kind kind = getFieldKind(isGetter, isVolatile, fw);
MethodType linkerType;
if (isGetter)
linkerType = MethodType.methodType(ft, Object.class, long.class);
else
linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
! MemberName linker = new MemberName(Unsafe.class, kind.methodName, linkerType, REF_invokeVirtual);
try {
linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class);
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
*** 618,627 ****
--- 670,680 ----
final int SET_VALUE = isGetter ? -1 : ARG_LIMIT - 1;
int nameCursor = ARG_LIMIT;
final int F_HOLDER = (isStatic ? nameCursor++ : -1); // static base if any
final int F_OFFSET = nameCursor++; // Either static offset or field offset.
final int OBJ_CHECK = (OBJ_BASE >= 0 ? nameCursor++ : -1);
+ final int U_HOLDER = nameCursor++; // UNSAFE holder
final int INIT_BAR = (needsInit ? nameCursor++ : -1);
final int PRE_CAST = (needsCast && !isGetter ? nameCursor++ : -1);
final int LINKER_CALL = nameCursor++;
final int POST_CAST = (needsCast && isGetter ? nameCursor++ : -1);
final int RESULT = nameCursor-1; // either the call or the cast
*** 630,640 ****
names[INIT_BAR] = new Name(NF_ensureInitialized, names[DMH_THIS]);
if (needsCast && !isGetter)
names[PRE_CAST] = new Name(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(NF_staticBase, names[DMH_THIS]);
outArgs[2] = names[F_OFFSET] = new Name(NF_staticOffset, names[DMH_THIS]);
} else {
outArgs[1] = names[OBJ_CHECK] = new Name(NF_checkBase, names[OBJ_BASE]);
--- 683,693 ----
names[INIT_BAR] = new Name(NF_ensureInitialized, names[DMH_THIS]);
if (needsCast && !isGetter)
names[PRE_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
Object[] outArgs = new Object[1 + linkerType.parameterCount()];
assert(outArgs.length == (isGetter ? 3 : 4));
! outArgs[0] = names[U_HOLDER] = new Name(NF_unsafe);
if (isStatic) {
outArgs[1] = names[F_HOLDER] = new Name(NF_staticBase, names[DMH_THIS]);
outArgs[2] = names[F_OFFSET] = new Name(NF_staticOffset, names[DMH_THIS]);
} else {
outArgs[1] = names[OBJ_CHECK] = new Name(NF_checkBase, names[OBJ_BASE]);
*** 648,665 ****
--- 701,724 ----
if (needsCast && isGetter)
names[POST_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
for (Name n : names) assert(n != null);
// add some detail to the lambdaForm debugname,
// significant only for debugging
+ StringBuilder nameBuilder = new StringBuilder(kind.methodName);
if (isStatic) {
nameBuilder.append("Static");
} else {
nameBuilder.append("Field");
}
if (needsCast) nameBuilder.append("Cast");
if (needsInit) nameBuilder.append("Init");
+ if (needsCast || needsInit) {
+ // can't use the pre-generated form when casting and/or initializing
return new LambdaForm(nameBuilder.toString(), ARG_LIMIT, names, RESULT);
+ } else {
+ return new LambdaForm(nameBuilder.toString(), ARG_LIMIT, names, RESULT, kind);
+ }
}
/**
* Pre-initialized NamedFunctions for bootstrapping purposes.
* Factored in an inner class to delay initialization until first usage.
*** 672,682 ****
NF_checkBase,
NF_staticBase,
NF_staticOffset,
NF_checkCast,
NF_allocateInstance,
! NF_constructorMethod;
static {
try {
NamedFunction nfs[] = {
NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("internalMemberName", Object.class)),
--- 731,742 ----
NF_checkBase,
NF_staticBase,
NF_staticOffset,
NF_checkCast,
NF_allocateInstance,
! NF_constructorMethod,
! NF_unsafe;
static {
try {
NamedFunction nfs[] = {
NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("internalMemberName", Object.class)),
*** 695,705 ****
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))
};
// Each nf must be statically invocable or we get tied up in our bootstraps.
assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
--- 755,767 ----
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)),
! NF_unsafe = new NamedFunction(DirectMethodHandle.class
! .getDeclaredMethod("unsafe"))
};
// Each nf must be statically invocable or we get tied up in our bootstraps.
assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
< prev index next >