< prev index next > src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java
Print this page
package java.lang.invoke;
import jdk.internal.misc.CDS;
import jdk.internal.misc.Unsafe;
+ import jdk.internal.value.ValueClass;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Stable;
import sun.invoke.util.ValueConversions;
import sun.invoke.util.VerifyAccess;
import sun.invoke.util.Wrapper;
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);
}
return UNSAFE.shouldBeInitialized(cls) || CDS.needsClassInitBarrier(cls);
}
private void ensureInitialized() {
! if (checkInitialized(member)) {
// The coast is clear. Delete the <clinit> barrier.
updateForm(new Function<>() {
public LambdaForm apply(LambdaForm oldForm) {
return (member.isField() ? preparedFieldLambdaForm(member)
: preparedLambdaForm(member));
}
});
}
}
! private static boolean checkInitialized(MemberName member) {
Class<?> defc = member.getDeclaringClass();
UNSAFE.ensureClassInitialized(defc);
// Once we get here either defc was fully initialized by another thread, or
// defc was already being initialized by the current thread. In the latter case
// the barrier must remain. We can detect this simply by checking if initialization
// is still needed.
! return !UNSAFE.shouldBeInitialized(defc);
}
/*non-public*/
static void ensureInitialized(Object mh) {
((DirectMethodHandle)mh).ensureInitialized();
}
return UNSAFE.shouldBeInitialized(cls) || CDS.needsClassInitBarrier(cls);
}
private void ensureInitialized() {
! if (checkInitialized()) {
// The coast is clear. Delete the <clinit> barrier.
updateForm(new Function<>() {
public LambdaForm apply(LambdaForm oldForm) {
return (member.isField() ? preparedFieldLambdaForm(member)
: preparedLambdaForm(member));
}
});
}
}
! private boolean checkInitialized() {
Class<?> defc = member.getDeclaringClass();
UNSAFE.ensureClassInitialized(defc);
// Once we get here either defc was fully initialized by another thread, or
// defc was already being initialized by the current thread. In the latter case
// the barrier must remain. We can detect this simply by checking if initialization
// is still needed.
! boolean initializingStill = UNSAFE.shouldBeInitialized(defc);
+ if (initializingStill && member.isStrict()) {
+ // while <clinit> is running, we track access to strict static fields
+ UNSAFE.notifyStrictStaticAccess(defc, staticOffset(this), member.isSetter());
+ }
+ return !initializingStill;
}
/*non-public*/
static void ensureInitialized(Object mh) {
((DirectMethodHandle)mh).ensureInitialized();
/** This subclass handles non-static field references. */
static final class Accessor extends DirectMethodHandle {
final Class<?> fieldType;
final int fieldOffset;
+ final int layout;
private Accessor(MethodType mtype, LambdaForm form, MemberName member,
boolean crackable, int fieldOffset) {
super(mtype, form, member, crackable);
this.fieldType = member.getFieldType();
this.fieldOffset = fieldOffset;
+ this.layout = member.getLayout();
}
@Override Object checkCast(Object obj) {
return fieldType.cast(obj);
}
/*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
+ static int fieldLayout(Object accessorObj) {
+ return ((Accessor) accessorObj).layout;
+ }
+
+ @ForceInline
+ /*non-public*/ static Class<?> staticFieldType(Object accessorObj) {
+ return ((StaticAccessor) accessorObj).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_UNCHECKED_REF = Wrapper.OBJECT.ordinal(),
! FT_CHECKED_REF = Wrapper.VOID.ordinal(),
! FT_LIMIT = Wrapper.COUNT;
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);
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
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_FIRST_REFERENCE = 8,
! // Any oop, same sig (Runnable?)
! FT_UNCHECKED_REF = FT_FIRST_REFERENCE,
+ // Oop with type checks (Number?)
+ FT_CHECKED_REF = FT_FIRST_REFERENCE + 1,
+ // Oop with null checks, (Runnable!)
+ FT_UNCHECKED_NR_REF = FT_FIRST_REFERENCE + 2,
+ // Oop with null and type checks, (Number!)
+ FT_CHECKED_NR_REF = FT_FIRST_REFERENCE + 3,
+ FT_FIRST_FLAT = FT_FIRST_REFERENCE + 4,
+ // nullable flat (must check type), (Integer?)
+ FT_NULLABLE_FLAT = FT_FIRST_FLAT,
+ // Null restricted flat (must check type), (Integer!)
+ FT_NR_FLAT = FT_FIRST_FLAT + 1,
+ FT_LIMIT = FT_FIRST_FLAT + 2;
+
+ static {
+ assert FT_FIRST_REFERENCE == Wrapper.OBJECT.ordinal();
+ }
+
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, boolean isFlat, boolean isNullRestricted) {
if (ftype.isPrimitive()) {
+ assert !isFlat && !isNullRestricted : ftype;
return Wrapper.forPrimitiveType(ftype).ordinal();
} else if (ftype.isInterface() || ftype.isAssignableFrom(Object.class)) {
+ assert !isFlat : ftype;
// retyping can be done without a cast
! return isNullRestricted ? FT_UNCHECKED_NR_REF : FT_UNCHECKED_REF;
! }
! if (isFlat) {
+ assert ValueClass.isConcreteValueClass(ftype) : ftype;
+ return isNullRestricted ? FT_NR_FLAT : FT_NULLABLE_FLAT;
}
+ return isNullRestricted ? FT_CHECKED_NR_REF : 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);
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, isFlat, isNullRestricted);
+ return preparedFieldLambdaForm(formOp, isVolatile, ftypeKind);
+ }
+
+ private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
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
}
private static final @Stable Wrapper[] ALL_WRAPPERS = Wrapper.values();
// Names in kind may overload but differ from their basic type
! private static Kind getFieldKind(boolean isVolatile, boolean needsInit, boolean needsCast, Wrapper wrapper) {
if (isVolatile) {
! if (needsInit) {
! return switch (wrapper) {
! case BYTE -> VOLATILE_FIELD_ACCESS_INIT_B;
! case CHAR -> VOLATILE_FIELD_ACCESS_INIT_C;
! case SHORT -> VOLATILE_FIELD_ACCESS_INIT_S;
! case BOOLEAN -> VOLATILE_FIELD_ACCESS_INIT_Z;
! default -> needsCast ? VOLATILE_FIELD_ACCESS_INIT_CAST : VOLATILE_FIELD_ACCESS_INIT;
! };
} else {
! return switch (wrapper) {
! case BYTE -> VOLATILE_FIELD_ACCESS_B;
! case CHAR -> VOLATILE_FIELD_ACCESS_C;
! case SHORT -> VOLATILE_FIELD_ACCESS_S;
! case BOOLEAN -> VOLATILE_FIELD_ACCESS_Z;
- default -> needsCast ? VOLATILE_FIELD_ACCESS_CAST : VOLATILE_FIELD_ACCESS;
- };
}
} else {
! if (needsInit) {
! return switch (wrapper) {
! case BYTE -> FIELD_ACCESS_INIT_B;
! case CHAR -> FIELD_ACCESS_INIT_C;
! case SHORT -> FIELD_ACCESS_INIT_S;
! case BOOLEAN -> FIELD_ACCESS_INIT_Z;
! default -> needsCast ? FIELD_ACCESS_INIT_CAST : FIELD_ACCESS_INIT;
! };
} else {
! return switch (wrapper) {
! case BYTE -> FIELD_ACCESS_B;
! case CHAR -> FIELD_ACCESS_C;
! case SHORT -> FIELD_ACCESS_S;
! case BOOLEAN -> FIELD_ACCESS_Z;
- default -> needsCast ? FIELD_ACCESS_CAST : FIELD_ACCESS;
- };
}
}
}
! private static String unsafeMethodName(boolean isGetter, boolean isVolatile, Wrapper wrapper) {
var name = switch (wrapper) {
case BOOLEAN -> "Boolean";
case BYTE -> "Byte";
case CHAR -> "Char";
case SHORT -> "Short";
case INT -> "Int";
case FLOAT -> "Float";
case LONG -> "Long";
case DOUBLE -> "Double";
case OBJECT -> "Reference";
! case VOID -> throw new InternalError();
};
var sb = new StringBuilder(3 + name.length() + (isVolatile ? 8 : 0))
.append(isGetter ? "get" : "put")
.append(name);
if (isVolatile) {
}
private static final @Stable Wrapper[] ALL_WRAPPERS = Wrapper.values();
// Names in kind may overload but differ from their basic type
! private static Kind getFieldKind(boolean isGetter,
+ boolean isVolatile,
+ boolean needsInit,
+ boolean needsCast,
+ boolean isFlat,
+ boolean isNullRestricted,
+ Wrapper wrapper) {
+ if (!wrapper.isOther()) {
+ // primitives
+ assert !isFlat && !isNullRestricted && !needsCast;
+ return switch (wrapper) {
+ case BYTE -> isVolatile
+ ? (needsInit ? VOLATILE_FIELD_ACCESS_INIT_B : VOLATILE_FIELD_ACCESS_B)
+ : (needsInit ? FIELD_ACCESS_INIT_B : FIELD_ACCESS_B);
+ case CHAR -> isVolatile
+ ? (needsInit ? VOLATILE_FIELD_ACCESS_INIT_C : VOLATILE_FIELD_ACCESS_C)
+ : (needsInit ? FIELD_ACCESS_INIT_C : FIELD_ACCESS_C);
+ case SHORT -> isVolatile
+ ? (needsInit ? VOLATILE_FIELD_ACCESS_INIT_S : VOLATILE_FIELD_ACCESS_S)
+ : (needsInit ? FIELD_ACCESS_INIT_S : FIELD_ACCESS_S);
+ case BOOLEAN -> isVolatile
+ ? (needsInit ? VOLATILE_FIELD_ACCESS_INIT_Z : VOLATILE_FIELD_ACCESS_Z)
+ : (needsInit ? FIELD_ACCESS_INIT_Z : FIELD_ACCESS_Z);
+ // basic types
+ default -> isVolatile
+ ? (needsInit ? VOLATILE_FIELD_ACCESS_INIT : VOLATILE_FIELD_ACCESS)
+ : (needsInit ? FIELD_ACCESS_INIT : FIELD_ACCESS);
+ };
+ }
+
+ assert !(isGetter && isNullRestricted);
if (isVolatile) {
! if (isFlat) {
! assert !needsInit && needsCast;
! return isNullRestricted ? VOLATILE_PUT_NULL_RESTRICTED_FLAT_VALUE : VOLATILE_FIELD_ACCESS_FLAT;
! } else if (needsCast) {
! if (needsInit) {
! return isNullRestricted ? VOLATILE_PUT_NULL_RESTRICTED_REFERENCE_CAST_INIT : VOLATILE_FIELD_ACCESS_INIT_CAST;
! } else {
! return isNullRestricted ? VOLATILE_PUT_NULL_RESTRICTED_REFERENCE_CAST : VOLATILE_FIELD_ACCESS_CAST;
+ }
} else {
! if (needsInit) {
! return isNullRestricted ? VOLATILE_PUT_NULL_RESTRICTED_REFERENCE_INIT : VOLATILE_FIELD_ACCESS_INIT;
! } else {
! return isNullRestricted ? VOLATILE_PUT_NULL_RESTRICTED_REFERENCE : VOLATILE_FIELD_ACCESS;
! }
}
} else {
! if (isFlat) {
! assert !needsInit && needsCast;
! return isNullRestricted ? PUT_NULL_RESTRICTED_FLAT_VALUE : FIELD_ACCESS_FLAT;
! } else if (needsCast) {
! if (needsInit) {
! return isNullRestricted ? PUT_NULL_RESTRICTED_REFERENCE_CAST_INIT : FIELD_ACCESS_INIT_CAST;
! } else {
! return isNullRestricted ? PUT_NULL_RESTRICTED_REFERENCE_CAST : FIELD_ACCESS_CAST;
+ }
} else {
! if (needsInit) {
! return isNullRestricted ? PUT_NULL_RESTRICTED_REFERENCE_INIT : FIELD_ACCESS_INIT;
! } else {
! return isNullRestricted ? PUT_NULL_RESTRICTED_REFERENCE : FIELD_ACCESS;
! }
}
}
}
! private static String unsafeMethodName(boolean isGetter,
+ boolean isVolatile,
+ Wrapper wrapper) {
var name = switch (wrapper) {
case BOOLEAN -> "Boolean";
case BYTE -> "Byte";
case CHAR -> "Char";
case SHORT -> "Short";
case INT -> "Int";
case FLOAT -> "Float";
case LONG -> "Long";
case DOUBLE -> "Double";
case OBJECT -> "Reference";
! case VOID -> "FlatValue";
};
var sb = new StringBuilder(3 + name.length() + (isVolatile ? 8 : 0))
.append(isGetter ? "get" : "put")
.append(name);
if (isVolatile) {
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.
String unsafeMethodName = unsafeMethodName(isGetter, isVolatile, fw);
! // isGetter and isStatic is reflected in field type; basic type clash for subwords
! Kind kind = getFieldKind(isVolatile, needsInit, needsCast, 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, unsafeMethodName, linkerType, REF_invokeVirtual);
try {
linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, LM_TRUSTED,
NoSuchMethodException.class);
} catch (ReflectiveOperationException ex) {
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 isFlat = (ftypeKind >= FT_FIRST_FLAT);
! boolean isNullRestricted = (ftypeKind == FT_NR_FLAT || ftypeKind == FT_CHECKED_NR_REF || ftypeKind == FT_UNCHECKED_NR_REF);
! boolean needsCast = (isFlat || ftypeKind == FT_CHECKED_REF || ftypeKind == FT_CHECKED_NR_REF);
!
+ if (isGetter && isNullRestricted) {
+ int newKind = switch (ftypeKind) {
+ case FT_NR_FLAT -> FT_NULLABLE_FLAT;
+ case FT_CHECKED_NR_REF -> FT_CHECKED_REF;
+ case FT_UNCHECKED_NR_REF -> FT_UNCHECKED_REF;
+ default -> throw new InternalError();
+ };
+ return preparedFieldLambdaForm(formOp, isVolatile, newKind);
+ }
+
+ if (isFlat && isStatic)
+ throw new InternalError("Static flat not supported yet");
+
+ // primitives, reference, and void for flat
+ Wrapper fw = ftypeKind < FT_FIRST_REFERENCE ? ALL_WRAPPERS[ftypeKind] :
+ isFlat ? Wrapper.VOID : Wrapper.OBJECT;
// getObject, putIntVolatile, etc.
String unsafeMethodName = unsafeMethodName(isGetter, isVolatile, fw);
! // isGetter and isStatic is reflected in field type;
! // flat, NR distinguished
+ // basic type clash for subwords
+ Kind kind = getFieldKind(isGetter, isVolatile, needsInit, needsCast, isFlat, isNullRestricted, fw);
+ Class<?> ft = ftypeKind < FT_FIRST_REFERENCE ? fw.primitiveType() : Object.class;
MethodType linkerType;
! if (isGetter) {
! linkerType = isFlat
! ? MethodType.methodType(ft, Object.class, long.class, int.class, Class.class)
! : MethodType.methodType(ft, Object.class, long.class);
+ } else {
+ linkerType = isFlat
+ ? MethodType.methodType(void.class, Object.class, long.class, int.class, Class.class, ft)
+ : MethodType.methodType(void.class, Object.class, long.class, ft);
+ }
MemberName linker = new MemberName(Unsafe.class, unsafeMethodName, 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]);
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 LAYOUT = (isFlat ? nameCursor++ : -1); // field must be instance
+ 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 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 (!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 ? 2 : 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[LAYOUT] = new Name(getFunction(NF_fieldLayout), names[DMH_THIS]);
+ 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 (needsCast && isGetter)
names[POST_CAST] = new Name(getFunction(NF_checkCast), names[DMH_THIS], names[LINKER_CALL]);
if (isStatic) {
nameBuilder.append("Static");
} else {
nameBuilder.append("Field");
}
+ if (isNullRestricted) {
+ nameBuilder.append("NullRestricted");
+ }
if (needsCast) {
nameBuilder.append("Cast");
}
if (needsInit) {
nameBuilder.append("Init");
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_fieldLayout = 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 INT_OBJ_TYPE = MethodType.methodType(int.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_nullCheck:
+ return getNamedFunction("nullCheck", OBJ_OBJ_TYPE);
+ case NF_fieldLayout:
+ return getNamedFunction("fieldLayout", INT_OBJ_TYPE);
default:
throw newInternalError("Unknown function: " + func);
}
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
< prev index next >