< prev index next >
src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java
Print this page
*** 102,116 ****
} else {
LambdaForm lform = preparedFieldLambdaForm(member);
if (member.isStatic()) {
long offset = MethodHandleNatives.staticFieldOffset(member);
Object base = MethodHandleNatives.staticFieldBase(member);
! return new StaticAccessor(mtype, lform, member, base, offset);
} else {
long offset = MethodHandleNatives.objectFieldOffset(member);
assert(offset == (int)offset);
! return new Accessor(mtype, lform, member, (int)offset);
}
}
}
static DirectMethodHandle make(Class<?> refc, MemberName member) {
byte refKind = member.getReferenceKind();
--- 102,119 ----
} else {
LambdaForm lform = preparedFieldLambdaForm(member);
if (member.isStatic()) {
long offset = MethodHandleNatives.staticFieldOffset(member);
Object base = MethodHandleNatives.staticFieldBase(member);
! return member.isFlattenable() ? new StaticValueAccessor(mtype, lform, member, base, offset)
! : new StaticAccessor(mtype, lform, member, base, offset);
} else {
long offset = MethodHandleNatives.objectFieldOffset(member);
assert(offset == (int)offset);
! return member.isFlattenable() ? new ValueAccessor(mtype, lform, member, (int)offset)
! : new Accessor(mtype, lform, member, (int)offset);
!
}
}
}
static DirectMethodHandle make(Class<?> refc, MemberName member) {
byte refKind = member.getReferenceKind();
*** 488,497 ****
--- 491,515 ----
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new Accessor(mt, lf, member, fieldOffset);
}
}
+ static class ValueAccessor extends Accessor {
+ private ValueAccessor(MethodType mtype, LambdaForm form, MemberName member,
+ int fieldOffset) {
+ super(mtype, form, member, fieldOffset);
+ }
+
+ @Override Object checkCast(Object obj) {
+ return fieldType.cast(Objects.requireNonNull(obj));
+ }
+ @Override
+ MethodHandle copyWith(MethodType mt, LambdaForm lf) {
+ return new ValueAccessor(mt, lf, member, fieldOffset);
+ }
+ }
+
@ForceInline
/*non-public*/ static long fieldOffset(Object accessorObj) {
// Note: We return a long because that is what Unsafe.getObject likes.
// We store a plain int because it is more compact.
return ((Accessor)accessorObj).fieldOffset;
*** 509,521 ****
return Objects.requireNonNull(obj);
}
/** This subclass handles static field references. */
static class StaticAccessor extends DirectMethodHandle {
! private final Class<?> fieldType;
! private final Object staticBase;
! private final long staticOffset;
private StaticAccessor(MethodType mtype, LambdaForm form, MemberName member,
Object staticBase, long staticOffset) {
super(mtype, form, member);
this.fieldType = member.getFieldType();
--- 527,539 ----
return Objects.requireNonNull(obj);
}
/** This subclass handles static field references. */
static class StaticAccessor extends DirectMethodHandle {
! final Class<?> fieldType;
! final Object staticBase;
! final long staticOffset;
private StaticAccessor(MethodType mtype, LambdaForm form, MemberName member,
Object staticBase, long staticOffset) {
super(mtype, form, member);
this.fieldType = member.getFieldType();
*** 530,539 ****
--- 548,573 ----
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new StaticAccessor(mt, lf, member, staticBase, staticOffset);
}
}
+ static class StaticValueAccessor extends StaticAccessor {
+ private StaticValueAccessor(MethodType mtype, LambdaForm form, MemberName member,
+ Object staticBase, long staticOffset) {
+ super(mtype, form, member, staticBase, staticOffset);
+ }
+
+ @Override Object checkCast(Object obj) {
+ return fieldType.cast(Objects.requireNonNull(obj));
+ }
+ @Override
+ MethodHandle copyWith(MethodType mt, LambdaForm lf) {
+ return new StaticValueAccessor(mt, lf, member, staticBase, staticOffset);
+ }
+ }
+
+
@ForceInline
/*non-public*/ static Object nullCheck(Object obj) {
return Objects.requireNonNull(obj);
}
*** 574,615 ****
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 isFlattened, boolean isVolatile, int ftypeKind) {
return ((formOp * FT_LIMIT * 2)
- + (isFlattened ? FT_LIMIT : 0)
+ (isVolatile ? FT_LIMIT : 0)
+ ftypeKind);
}
@Stable
private static final LambdaForm[] ACCESSOR_FORMS
! = new LambdaForm[afIndex(AF_LIMIT, false,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
! 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();
boolean isFlattened = m.isFlattened();
byte formOp;
switch (m.getReferenceKind()) {
case REF_getField: formOp = AF_GETFIELD; break;
case REF_putField: formOp = AF_PUTFIELD; break;
--- 608,652 ----
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, // flattened and non-flattened
! FT_LIMIT = FT_LAST_WRAPPER+4;
! private static int afIndex(byte formOp, boolean isVolatile, boolean isFlattened, int ftypeKind) {
return ((formOp * FT_LIMIT * 2)
+ (isVolatile ? FT_LIMIT : 0)
+ + (isFlattened ? 1 : 0)
+ ftypeKind);
}
@Stable
private static final LambdaForm[] ACCESSOR_FORMS
! = new LambdaForm[afIndex(AF_LIMIT, false, false, 0)];
! static int ftypeKind(Class<?> ftype, boolean isNullable) {
if (ftype.isPrimitive())
return Wrapper.forPrimitiveType(ftype).ordinal();
! else if (VerifyType.isNullReferenceConversion(Object.class, ftype)) {
return FT_UNCHECKED_REF;
! } else
! // null check for value type in addition to check cast
! return isNullable ? FT_CHECKED_REF : FT_CHECKED_VALUE;
}
/**
* 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();
+ boolean isNullable = m.isNullable();
boolean isFlattened = m.isFlattened();
byte formOp;
switch (m.getReferenceKind()) {
case REF_getField: formOp = AF_GETFIELD; break;
case REF_putField: formOp = AF_PUTFIELD; break;
*** 617,652 ****
case REF_putStatic: formOp = AF_PUTSTATIC; break;
default: throw new InternalError(m.toString());
}
if (shouldBeInitialized(m)) {
// precompute the barrier-free version:
! preparedFieldLambdaForm(formOp, isFlattened, isVolatile, ftype);
assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
(AF_PUTSTATIC_INIT - AF_PUTSTATIC));
formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
}
! LambdaForm lform = preparedFieldLambdaForm(formOp, isFlattened, 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 isFlattened, boolean isVolatile, Class<?> ftype) {
! int ftypeKind = ftypeKind(ftype);
! int afIndex = afIndex(formOp, isFlattened, isVolatile, ftypeKind);
LambdaForm lform = ACCESSOR_FORMS[afIndex];
if (lform != null) return lform;
! lform = makePreparedFieldLambdaForm(formOp, isFlattened, 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 isFlattened, boolean isVolatile, Wrapper wrapper) {
if (isGetter) {
if (isVolatile) {
switch (wrapper) {
case BOOLEAN: return GET_BOOLEAN_VOLATILE;
case BYTE: return GET_BYTE_VOLATILE;
--- 654,690 ----
case REF_putStatic: formOp = AF_PUTSTATIC; break;
default: throw new InternalError(m.toString());
}
if (shouldBeInitialized(m)) {
// precompute the barrier-free version:
! preparedFieldLambdaForm(formOp, isVolatile, isFlattened, isNullable, ftype);
assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
(AF_PUTSTATIC_INIT - AF_PUTSTATIC));
formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
}
! LambdaForm lform = preparedFieldLambdaForm(formOp, isVolatile, isFlattened, isNullable, 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 isFlattened, boolean isNullable, Class<?> ftype) {
! int ftypeKind = ftypeKind(ftype, isNullable);
! assert(isNullable ? (ftypeKind < FT_CHECKED_VALUE) : (ftypeKind == FT_CHECKED_VALUE));
! int afIndex = afIndex(formOp, isVolatile, isFlattened, ftypeKind);
LambdaForm lform = ACCESSOR_FORMS[afIndex];
if (lform != null) return lform;
! lform = makePreparedFieldLambdaForm(formOp, isVolatile, isFlattened, 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 isFlattened, Wrapper wrapper) {
if (isGetter) {
if (isVolatile) {
switch (wrapper) {
case BOOLEAN: return GET_BOOLEAN_VOLATILE;
case BYTE: return GET_BYTE_VOLATILE;
*** 654,664 ****
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;
--- 692,702 ----
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 isFlattened ? GET_VALUE_VOLATILE : GET_REFERENCE_VOLATILE;
}
} else {
switch (wrapper) {
case BOOLEAN: return GET_BOOLEAN;
case BYTE: return GET_BYTE;
*** 680,690 ****
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;
--- 718,728 ----
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 isFlattened ? PUT_VALUE_VOLATILE : PUT_REFERENCE_VOLATILE;
}
} else {
switch (wrapper) {
case BOOLEAN: return PUT_BOOLEAN;
case BYTE: return PUT_BYTE;
*** 699,719 ****
}
}
throw new AssertionError("Invalid arguments");
}
! static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isFlattened, 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, isFlattened, isVolatile, fw);
MethodType linkerType;
if (isFlattened) {
linkerType = isGetter ? MethodType.methodType(ft, Object.class, long.class, Class.class)
: MethodType.methodType(void.class, Object.class, long.class, Class.class, ft);
--- 737,757 ----
}
}
throw new AssertionError("Invalid arguments");
}
! static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, boolean isFlattened, 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 != FT_CHECKED_VALUE) == ftypeKind);
// getObject, putIntVolatile, etc.
! Kind kind = getFieldKind(isGetter, isVolatile, isFlattened, fw);
MethodType linkerType;
if (isFlattened) {
linkerType = isGetter ? MethodType.methodType(ft, Object.class, long.class, Class.class)
: MethodType.methodType(void.class, Object.class, long.class, Class.class, ft);
< prev index next >