< prev index next > src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java
Print this page
if (member.isConstructor())
return makeAllocator(member.getDeclaringClass(), member);
return make(member.getDeclaringClass(), member);
}
static DirectMethodHandle makeAllocator(Class<?> instanceClass, MemberName ctor) {
! assert(ctor.isConstructor() && ctor.getName().equals("<init>"));
ctor = ctor.asConstructor();
! assert(ctor.isConstructor() && ctor.getReferenceKind() == REF_newInvokeSpecial) : ctor;
MethodType mtype = ctor.getMethodType().changeReturnType(instanceClass);
LambdaForm lform = preparedLambdaForm(ctor);
MemberName init = ctor.asSpecial();
assert(init.getMethodType().returnType() == void.class);
return new Constructor(mtype, lform, ctor, true, init, instanceClass);
if (member.isConstructor())
return makeAllocator(member.getDeclaringClass(), member);
return make(member.getDeclaringClass(), member);
}
static DirectMethodHandle makeAllocator(Class<?> instanceClass, MemberName ctor) {
! assert(ctor.isConstructor()) : ctor;
ctor = ctor.asConstructor();
! assert(ctor.getReferenceKind() == REF_newInvokeSpecial) : ctor;
MethodType mtype = ctor.getMethodType().changeReturnType(instanceClass);
LambdaForm lform = preparedLambdaForm(ctor);
MemberName init = ctor.asSpecial();
assert(init.getMethodType().returnType() == void.class);
return new Constructor(mtype, lform, ctor, true, init, instanceClass);
/*non-public*/
static Object checkCast(Object mh, Object obj) {
return ((DirectMethodHandle) mh).checkCast(obj);
}
+ @ForceInline
+ /*non-public*/ static Class<?> fieldType(Object accessorObj) {
+ return ((Accessor) accessorObj).fieldType;
+ }
+
+ @ForceInline
+ /*non-public*/ static Class<?> staticFieldType(Object accessorObj) {
+ return ((StaticAccessor) accessorObj).fieldType;
+ }
+
+ @ForceInline
+ /*non-public*/ static Object zeroInstanceIfNull(Class<?> fieldType, Object obj) {
+ return obj != null ? obj : UNSAFE.uninitializedDefaultValue(fieldType);
+ }
+
Object checkCast(Object obj) {
return member.getMethodType().returnType().cast(obj);
}
// Caching machinery for field accessors:
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) {
return ((formOp * FT_LIMIT * 2)
+ (isVolatile ? FT_LIMIT : 0)
+ 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 (ftype.isInterface() || ftype.isAssignableFrom(Object.class)) {
// retyping can be done without a cast
return FT_UNCHECKED_REF;
} else {
! return FT_CHECKED_REF;
}
}
/**
* Create a LF which can access the given field.
* Cache and share this structure among all fields with
* the same basicType and refKind.
*/
private static LambdaForm preparedFieldLambdaForm(MemberName m) {
Class<?> ftype = m.getFieldType();
- boolean isVolatile = m.isVolatile();
byte formOp = switch (m.getReferenceKind()) {
case REF_getField -> AF_GETFIELD;
case REF_putField -> AF_PUTFIELD;
case REF_getStatic -> AF_GETSTATIC;
case REF_putStatic -> AF_PUTSTATIC;
default -> throw new InternalError(m.toString());
};
if (shouldBeInitialized(m)) {
// precompute the barrier-free version:
! preparedFieldLambdaForm(formOp, isVolatile, ftype);
assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
(AF_PUTSTATIC_INIT - AF_PUTSTATIC));
formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
}
! LambdaForm lform = preparedFieldLambdaForm(formOp, isVolatile, ftype);
maybeCompile(lform, m);
assert(lform.methodType().dropParameterTypes(0, 1)
.equals(m.getInvocationType().basicType()))
: Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
return lform;
}
! private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile, Class<?> ftype) {
int ftypeKind = ftypeKind(ftype);
! int afIndex = afIndex(formOp, isVolatile, ftypeKind);
LambdaForm lform = ACCESSOR_FORMS[afIndex];
if (lform != null) return lform;
! lform = makePreparedFieldLambdaForm(formOp, isVolatile, ftypeKind);
ACCESSOR_FORMS[afIndex] = lform; // don't bother with a CAS
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;
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 and value field access
static final int
! FT_LAST_WRAPPER = Wrapper.COUNT-1,
! FT_UNCHECKED_REF = Wrapper.OBJECT.ordinal(),
! FT_CHECKED_REF = FT_LAST_WRAPPER+1,
! FT_CHECKED_VALUE = FT_LAST_WRAPPER+2, // flat vs non-flat x null value vs null-restricted value
! FT_LIMIT = FT_LAST_WRAPPER+6;
+ private static int afIndex(byte formOp, boolean isVolatile, boolean isFlat, boolean isNullRestricted, int ftypeKind) {
return ((formOp * FT_LIMIT * 2)
+ (isVolatile ? FT_LIMIT : 0)
+ + (isFlat ? 1 : 0)
+ + (isNullRestricted ? 1 : 0)
+ ftypeKind);
}
@Stable
private static final LambdaForm[] ACCESSOR_FORMS
! = new LambdaForm[afIndex(AF_LIMIT, false, false, false, 0)];
static int ftypeKind(Class<?> ftype) {
if (ftype.isPrimitive()) {
return Wrapper.forPrimitiveType(ftype).ordinal();
} else if (ftype.isInterface() || ftype.isAssignableFrom(Object.class)) {
// retyping can be done without a cast
return FT_UNCHECKED_REF;
} else {
! return ftype.isValue() ? FT_CHECKED_VALUE : FT_CHECKED_REF;
}
}
/**
* Create a LF which can access the given field.
* Cache and share this structure among all fields with
* the same basicType and refKind.
*/
private static LambdaForm preparedFieldLambdaForm(MemberName m) {
Class<?> ftype = m.getFieldType();
byte formOp = switch (m.getReferenceKind()) {
case REF_getField -> AF_GETFIELD;
case REF_putField -> AF_PUTFIELD;
case REF_getStatic -> AF_GETSTATIC;
case REF_putStatic -> AF_PUTSTATIC;
default -> throw new InternalError(m.toString());
};
if (shouldBeInitialized(m)) {
// precompute the barrier-free version:
! preparedFieldLambdaForm(formOp, m.isVolatile(), m.isFlat(), m.isNullRestricted(), ftype);
assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
(AF_PUTSTATIC_INIT - AF_PUTSTATIC));
formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
}
! LambdaForm lform = preparedFieldLambdaForm(formOp, m.isVolatile(), m.isFlat(), m.isNullRestricted(), ftype);
maybeCompile(lform, m);
assert(lform.methodType().dropParameterTypes(0, 1)
.equals(m.getInvocationType().basicType()))
: Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
return lform;
}
!
+ private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile,
+ boolean isFlat, boolean isNullRestricted, Class<?> ftype) {
int ftypeKind = ftypeKind(ftype);
! int afIndex = afIndex(formOp, isVolatile, isFlat, isNullRestricted, ftypeKind);
LambdaForm lform = ACCESSOR_FORMS[afIndex];
if (lform != null) return lform;
! lform = makePreparedFieldLambdaForm(formOp, isVolatile,isFlat, isNullRestricted, ftypeKind);
ACCESSOR_FORMS[afIndex] = lform; // don't bother with a CAS
return lform;
}
private static final Wrapper[] ALL_WRAPPERS = Wrapper.values();
! private static Kind getFieldKind(boolean isGetter, boolean isVolatile, boolean isFlat, Wrapper wrapper) {
if (isGetter) {
if (isVolatile) {
switch (wrapper) {
case BOOLEAN: return GET_BOOLEAN_VOLATILE;
case BYTE: return GET_BYTE_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_REFERENCE_VOLATILE;
}
} else {
switch (wrapper) {
case BOOLEAN: return GET_BOOLEAN;
case BYTE: return GET_BYTE;
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 isFlat ? GET_VALUE_VOLATILE : GET_REFERENCE_VOLATILE;
}
} else {
switch (wrapper) {
case BOOLEAN: return GET_BOOLEAN;
case BYTE: return GET_BYTE;
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_REFERENCE;
}
}
} else {
if (isVolatile) {
switch (wrapper) {
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 isFlat ? GET_VALUE : GET_REFERENCE;
}
}
} else {
if (isVolatile) {
switch (wrapper) {
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_REFERENCE_VOLATILE;
}
} else {
switch (wrapper) {
case BOOLEAN: return PUT_BOOLEAN;
case BYTE: return PUT_BYTE;
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 isFlat ? PUT_VALUE_VOLATILE : PUT_REFERENCE_VOLATILE;
}
} else {
switch (wrapper) {
case BOOLEAN: return PUT_BOOLEAN;
case BYTE: return PUT_BYTE;
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_REFERENCE;
}
}
}
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, LM_TRUSTED,
NoSuchMethodException.class);
} catch (ReflectiveOperationException ex) {
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 isFlat ? PUT_VALUE : PUT_REFERENCE;
}
}
}
throw new AssertionError("Invalid arguments");
}
! /** invoked by GenerateJLIClassesHelper */
+ static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftype) {
+ return makePreparedFieldLambdaForm(formOp, isVolatile, false, false, ftype);
+ }
+
+ private static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile,
+ boolean isFlat, boolean isNullRestricted, 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 || ftypeKind == FT_CHECKED_VALUE);
Wrapper fw = (needsCast ? Wrapper.OBJECT : ALL_WRAPPERS[ftypeKind]);
Class<?> ft = fw.primitiveType();
! assert(needsCast ? true : ftypeKind(ft) == ftypeKind);
// getObject, putIntVolatile, etc.
! Kind kind = getFieldKind(isGetter, isVolatile, isFlat, fw);
MethodType linkerType;
! if (isGetter) {
! linkerType = isFlat
! ? MethodType.methodType(ft, Object.class, long.class, Class.class)
! : MethodType.methodType(ft, Object.class, long.class);
+ } else {
+ linkerType = isFlat
+ ? MethodType.methodType(void.class, Object.class, long.class, Class.class, ft)
+ : 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, LM_TRUSTED,
NoSuchMethodException.class);
} catch (ReflectiveOperationException ex) {
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
Name[] names = invokeArguments(nameCursor - ARG_LIMIT, mtype);
if (needsInit)
names[INIT_BAR] = new Name(getFunction(NF_ensureInitialized), names[DMH_THIS]);
! if (needsCast && !isGetter)
! names[PRE_CAST] = new Name(getFunction(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(getFunction(NF_UNSAFE));
if (isStatic) {
outArgs[1] = names[F_HOLDER] = new Name(getFunction(NF_staticBase), names[DMH_THIS]);
outArgs[2] = names[F_OFFSET] = new Name(getFunction(NF_staticOffset), names[DMH_THIS]);
} else {
outArgs[1] = names[OBJ_CHECK] = new Name(getFunction(NF_checkBase), names[OBJ_BASE]);
outArgs[2] = names[F_OFFSET] = new Name(getFunction(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(getFunction(NF_checkCast), names[DMH_THIS], names[LINKER_CALL]);
for (Name n : names) assert(n != null);
LambdaForm form;
if (needsCast || needsInit) {
// can't use the pre-generated form when casting and/or initializing
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 VALUE_TYPE = (isFlat ? nameCursor++ : -1);
+ final int NULL_CHECK = (isNullRestricted && !isGetter ? nameCursor++ : -1);
final int PRE_CAST = (needsCast && !isGetter ? nameCursor++ : -1);
final int LINKER_CALL = nameCursor++;
+ final int FIELD_TYPE = (isNullRestricted && isGetter ? nameCursor++ : -1);
+ final int ZERO_INSTANCE = (isNullRestricted && isGetter ? nameCursor++ : -1);
final int POST_CAST = (needsCast && isGetter ? nameCursor++ : -1);
! final int RESULT = nameCursor-1; // either the call, zero instance, or the cast
Name[] names = invokeArguments(nameCursor - ARG_LIMIT, mtype);
if (needsInit)
names[INIT_BAR] = new Name(getFunction(NF_ensureInitialized), names[DMH_THIS]);
! if (!isGetter) {
! if (isNullRestricted)
+ names[NULL_CHECK] = new Name(getFunction(NF_nullCheck), names[SET_VALUE]);
+ if (needsCast)
+ names[PRE_CAST] = new Name(getFunction(NF_checkCast), names[DMH_THIS], names[SET_VALUE]);
+ }
Object[] outArgs = new Object[1 + linkerType.parameterCount()];
! assert (outArgs.length == (isGetter ? 3 : 4) + (isFlat ? 1 : 0));
outArgs[0] = names[U_HOLDER] = new Name(getFunction(NF_UNSAFE));
if (isStatic) {
outArgs[1] = names[F_HOLDER] = new Name(getFunction(NF_staticBase), names[DMH_THIS]);
outArgs[2] = names[F_OFFSET] = new Name(getFunction(NF_staticOffset), names[DMH_THIS]);
} else {
outArgs[1] = names[OBJ_CHECK] = new Name(getFunction(NF_checkBase), names[OBJ_BASE]);
outArgs[2] = names[F_OFFSET] = new Name(getFunction(NF_fieldOffset), names[DMH_THIS]);
}
+ int x = 3;
+ if (isFlat) {
+ outArgs[x++] = names[VALUE_TYPE] = isStatic ? new Name(getFunction(NF_staticFieldType), names[DMH_THIS])
+ : new Name(getFunction(NF_fieldType), names[DMH_THIS]);
+ }
if (!isGetter) {
! outArgs[x] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
}
for (Object a : outArgs) assert(a != null);
names[LINKER_CALL] = new Name(linker, outArgs);
! if (isGetter) {
! int argIndex = LINKER_CALL;
+ if (isNullRestricted) {
+ names[FIELD_TYPE] = isStatic ? new Name(getFunction(NF_staticFieldType), names[DMH_THIS])
+ : new Name(getFunction(NF_fieldType), names[DMH_THIS]);
+ names[ZERO_INSTANCE] = new Name(getFunction(NF_zeroInstance), names[FIELD_TYPE], names[LINKER_CALL]);
+ argIndex = ZERO_INSTANCE;
+ }
+ if (needsCast)
+ names[POST_CAST] = new Name(getFunction(NF_checkCast), names[DMH_THIS], names[argIndex]);
+ }
for (Name n : names) assert(n != null);
LambdaForm form;
if (needsCast || needsInit) {
// can't use the pre-generated form when casting and/or initializing
NF_checkCast = 7,
NF_allocateInstance = 8,
NF_constructorMethod = 9,
NF_UNSAFE = 10,
NF_checkReceiver = 11,
! NF_LIMIT = 12;
private static final @Stable NamedFunction[] NFS = new NamedFunction[NF_LIMIT];
private static NamedFunction getFunction(byte func) {
NamedFunction nf = NFS[func];
NF_checkCast = 7,
NF_allocateInstance = 8,
NF_constructorMethod = 9,
NF_UNSAFE = 10,
NF_checkReceiver = 11,
! NF_fieldType = 12,
+ NF_staticFieldType = 13,
+ NF_zeroInstance = 14,
+ NF_nullCheck = 15,
+ NF_LIMIT = 16;
private static final @Stable NamedFunction[] NFS = new NamedFunction[NF_LIMIT];
private static NamedFunction getFunction(byte func) {
NamedFunction nf = NFS[func];
nf = NFS[func] = createFunction(func);
assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf));
return nf;
}
+ private static final MethodType CLS_OBJ_TYPE = MethodType.methodType(Class.class, Object.class);
+
private static final MethodType OBJ_OBJ_TYPE = MethodType.methodType(Object.class, Object.class);
private static final MethodType LONG_OBJ_TYPE = MethodType.methodType(long.class, Object.class);
private static NamedFunction createFunction(byte func) {
member = new MemberName(DirectMethodHandle.class, "checkReceiver", OBJ_OBJ_TYPE, REF_invokeVirtual);
return new NamedFunction(
MemberName.getFactory().resolveOrFail(REF_invokeVirtual, member,
DirectMethodHandle.class, LM_TRUSTED,
NoSuchMethodException.class));
+ case NF_fieldType:
+ return getNamedFunction("fieldType", CLS_OBJ_TYPE);
+ case NF_staticFieldType:
+ return getNamedFunction("staticFieldType", CLS_OBJ_TYPE);
+ case NF_zeroInstance:
+ return getNamedFunction("zeroInstanceIfNull", MethodType.methodType(Object.class, Class.class, Object.class));
+ case NF_nullCheck:
+ return getNamedFunction("nullCheck", OBJ_OBJ_TYPE);
default:
throw newInternalError("Unknown function: " + func);
}
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
< prev index next >