Skip to content
Permalink
Browse files
8244413: Avoid rebinds in MethodHandle.viewAsType
Reviewed-by: mchung, jrose
  • Loading branch information
cl4es committed May 6, 2020
1 parent 463e377 commit 72704aaba1dd27a77cf9595cf18962737ced4a87
@@ -61,6 +61,20 @@ MemberName internalMemberName() {
return getTarget().internalMemberName();
}

@Override
boolean isCrackable() {
MemberName member = internalMemberName();
return member != null &&
(member.isResolved() ||
member.isMethodHandleInvoke() ||
member.isVarHandleMethodInvoke());
}

@Override
MethodHandle viewAsType(MethodType newType, boolean strict) {
return getTarget().viewAsType(newType, strict);
}

@Override
boolean isInvokeSpecial() {
return getTarget().isInvokeSpecial();
@@ -51,9 +51,10 @@
*/
class DirectMethodHandle extends MethodHandle {
final MemberName member;
final boolean crackable;

// Constructors and factory methods in this class *must* be package scoped or private.
private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member, boolean crackable) {
super(mtype, form);
if (!member.isResolved()) throw new InternalError();

@@ -70,6 +71,7 @@ private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member)
}

this.member = member;
this.crackable = crackable;
}

// Factory methods:
@@ -92,30 +94,30 @@ static DirectMethodHandle make(byte refKind, Class<?> refc, MemberName member, C
throw new InternalError("callerClass must not be null for REF_invokeSpecial");
}
LambdaForm lform = preparedLambdaForm(member, callerClass.isInterface());
return new Special(mtype, lform, member, callerClass);
return new Special(mtype, lform, member, true, callerClass);
}
case REF_invokeInterface: {
// for interfaces we always need the receiver typecheck,
// so we always pass 'true' to ensure we adapt if needed
// to include the REF_invokeSpecial case
LambdaForm lform = preparedLambdaForm(member, true);
return new Interface(mtype, lform, member, refc);
return new Interface(mtype, lform, member, true, refc);
}
default: {
LambdaForm lform = preparedLambdaForm(member);
return new DirectMethodHandle(mtype, lform, member);
return new DirectMethodHandle(mtype, lform, member, true);
}
}
} 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);
return new StaticAccessor(mtype, lform, member, true, base, offset);
} else {
long offset = MethodHandleNatives.objectFieldOffset(member);
assert(offset == (int)offset);
return new Accessor(mtype, lform, member, (int)offset);
return new Accessor(mtype, lform, member, true, (int)offset);
}
}
}
@@ -139,7 +141,7 @@ private static DirectMethodHandle makeAllocator(MemberName ctor) {
LambdaForm lform = preparedLambdaForm(ctor);
MemberName init = ctor.asSpecial();
assert(init.getMethodType().returnType() == void.class);
return new Constructor(mtype, lform, ctor, init, instanceClass);
return new Constructor(mtype, lform, ctor, true, init, instanceClass);
}

@Override
@@ -150,7 +152,22 @@ BoundMethodHandle rebind() {
@Override
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
assert(this.getClass() == DirectMethodHandle.class); // must override in subclasses
return new DirectMethodHandle(mt, lf, member);
return new DirectMethodHandle(mt, lf, member, crackable);
}

@Override
MethodHandle viewAsType(MethodType newType, boolean strict) {
// No actual conversions, just a new view of the same method.
// However, we must not expose a DMH that is crackable into a
// MethodHandleInfo, so we return a cloned, uncrackable DMH
assert(viewAsTypeChecks(newType, strict));
assert(this.getClass() == DirectMethodHandle.class); // must override in subclasses
return new DirectMethodHandle(newType, form, member, false);
}

@Override
boolean isCrackable() {
return crackable;
}

@Override
@@ -406,8 +423,8 @@ static void ensureInitialized(Object mh) {
/** This subclass represents invokespecial instructions. */
static class Special extends DirectMethodHandle {
private final Class<?> caller;
private Special(MethodType mtype, LambdaForm form, MemberName member, Class<?> caller) {
super(mtype, form, member);
private Special(MethodType mtype, LambdaForm form, MemberName member, boolean crackable, Class<?> caller) {
super(mtype, form, member, crackable);
this.caller = caller;
}
@Override
@@ -416,7 +433,12 @@ boolean isInvokeSpecial() {
}
@Override
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new Special(mt, lf, member, caller);
return new Special(mt, lf, member, crackable, caller);
}
@Override
MethodHandle viewAsType(MethodType newType, boolean strict) {
assert(viewAsTypeChecks(newType, strict));
return new Special(newType, form, member, false, caller);
}
Object checkReceiver(Object recv) {
if (!caller.isInstance(recv)) {
@@ -431,14 +453,19 @@ Object checkReceiver(Object recv) {
/** This subclass represents invokeinterface instructions. */
static class Interface extends DirectMethodHandle {
private final Class<?> refc;
private Interface(MethodType mtype, LambdaForm form, MemberName member, Class<?> refc) {
super(mtype, form, member);
assert refc.isInterface() : refc;
private Interface(MethodType mtype, LambdaForm form, MemberName member, boolean crackable, Class<?> refc) {
super(mtype, form, member, crackable);
assert(refc.isInterface()) : refc;
this.refc = refc;
}
@Override
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new Interface(mt, lf, member, refc);
return new Interface(mt, lf, member, crackable, refc);
}
@Override
MethodHandle viewAsType(MethodType newType, boolean strict) {
assert(viewAsTypeChecks(newType, strict));
return new Interface(newType, form, member, false, refc);
}
@Override
Object checkReceiver(Object recv) {
@@ -456,22 +483,26 @@ Object checkReceiver(Object recv) {
throw new InternalError("Should only be invoked on a subclass");
}


/** This subclass handles constructor references. */
static class Constructor extends DirectMethodHandle {
final MemberName initMethod;
final Class<?> instanceClass;

private Constructor(MethodType mtype, LambdaForm form, MemberName constructor,
MemberName initMethod, Class<?> instanceClass) {
super(mtype, form, constructor);
boolean crackable, MemberName initMethod, Class<?> instanceClass) {
super(mtype, form, constructor, crackable);
this.initMethod = initMethod;
this.instanceClass = instanceClass;
assert(initMethod.isResolved());
}
@Override
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new Constructor(mt, lf, member, initMethod, instanceClass);
return new Constructor(mt, lf, member, crackable, initMethod, instanceClass);
}
@Override
MethodHandle viewAsType(MethodType newType, boolean strict) {
assert(viewAsTypeChecks(newType, strict));
return new Constructor(newType, form, member, false, initMethod, instanceClass);
}
}

@@ -492,8 +523,8 @@ static Object allocateInstance(Object mh) throws InstantiationException {
final Class<?> fieldType;
final int fieldOffset;
private Accessor(MethodType mtype, LambdaForm form, MemberName member,
int fieldOffset) {
super(mtype, form, member);
boolean crackable, int fieldOffset) {
super(mtype, form, member, crackable);
this.fieldType = member.getFieldType();
this.fieldOffset = fieldOffset;
}
@@ -503,7 +534,12 @@ private Accessor(MethodType mtype, LambdaForm form, MemberName member,
}
@Override
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new Accessor(mt, lf, member, fieldOffset);
return new Accessor(mt, lf, member, crackable, fieldOffset);
}
@Override
MethodHandle viewAsType(MethodType newType, boolean strict) {
assert(viewAsTypeChecks(newType, strict));
return new Accessor(newType, form, member, false, fieldOffset);
}
}

@@ -535,8 +571,8 @@ static Object checkBase(Object obj) {
private final long staticOffset;

private StaticAccessor(MethodType mtype, LambdaForm form, MemberName member,
Object staticBase, long staticOffset) {
super(mtype, form, member);
boolean crackable, Object staticBase, long staticOffset) {
super(mtype, form, member, crackable);
this.fieldType = member.getFieldType();
this.staticBase = staticBase;
this.staticOffset = staticOffset;
@@ -547,7 +583,12 @@ private StaticAccessor(MethodType mtype, LambdaForm form, MemberName member,
}
@Override
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new StaticAccessor(mt, lf, member, staticBase, staticOffset);
return new StaticAccessor(mt, lf, member, crackable, staticBase, staticOffset);
}
@Override
MethodHandle viewAsType(MethodType newType, boolean strict) {
assert(viewAsTypeChecks(newType, strict));
return new StaticAccessor(newType, form, member, false, staticBase, staticOffset);
}
}

@@ -1640,12 +1640,9 @@ MethodHandle setVarargs(MemberName member) throws IllegalAccessException {
/*non-public*/
MethodHandle viewAsType(MethodType newType, boolean strict) {
// No actual conversions, just a new view of the same method.
// Note that this operation must not produce a DirectMethodHandle,
// because retyped DMHs, like any transformed MHs,
// cannot be cracked into MethodHandleInfo.
assert viewAsTypeChecks(newType, strict);
BoundMethodHandle mh = rebind();
return mh.copyWith(newType, mh.form);
// Overridden in DMH, which has special rules
assert(viewAsTypeChecks(newType, strict));
return copyWith(newType, form);
}

/*non-public*/
@@ -1693,7 +1690,7 @@ MethodHandle withInternalMemberName(MemberName member, boolean isInvokeSpecial)
} else {
// The following case is rare. Mask the internalMemberName by wrapping the MH in a BMH.
MethodHandle result = rebind();
assert (result.internalMemberName() == null);
assert(result.internalMemberName() == null);
return result;
}
}
@@ -1703,6 +1700,11 @@ boolean isInvokeSpecial() {
return false; // DMH.Special returns true
}

/*non-public*/
boolean isCrackable() {
return false;
}

/*non-public*/
Object internalValues() {
return null;
@@ -3282,11 +3282,10 @@ public VarHandle unreflectVarHandle(Field f) throws IllegalAccessException {
* @since 1.8
*/
public MethodHandleInfo revealDirect(MethodHandle target) {
MemberName member = target.internalMemberName();
if (member == null || (!member.isResolved() &&
!member.isMethodHandleInvoke() &&
!member.isVarHandleMethodInvoke()))
if (!target.isCrackable()) {
throw newIllegalArgumentException("not a direct method handle");
}
MemberName member = target.internalMemberName();
Class<?> defc = member.getDeclaringClass();
byte refKind = member.getReferenceKind();
assert(MethodHandleNatives.refKindIsValid(refKind));

0 comments on commit 72704aa

Please sign in to comment.