8244413: Avoid rebinds in MethodHandle.viewAsType
Reviewed-by: mchung, jrose
This commit is contained in:
parent
463e377053
commit
72704aaba1
@ -61,6 +61,20 @@ abstract class DelegatingMethodHandle extends MethodHandle {
|
||||
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 @@ import static java.lang.invoke.MethodTypeForm.*;
|
||||
*/
|
||||
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 @@ class DirectMethodHandle extends MethodHandle {
|
||||
}
|
||||
|
||||
this.member = member;
|
||||
this.crackable = crackable;
|
||||
}
|
||||
|
||||
// Factory methods:
|
||||
@ -92,18 +94,18 @@ class DirectMethodHandle extends MethodHandle {
|
||||
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 {
|
||||
@ -111,11 +113,11 @@ class DirectMethodHandle extends MethodHandle {
|
||||
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 @@ class DirectMethodHandle extends MethodHandle {
|
||||
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 @@ class DirectMethodHandle extends MethodHandle {
|
||||
@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 @@ class DirectMethodHandle extends MethodHandle {
|
||||
/** 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 @@ class DirectMethodHandle extends MethodHandle {
|
||||
}
|
||||
@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 @@ class DirectMethodHandle extends MethodHandle {
|
||||
/** 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 @@ class DirectMethodHandle extends MethodHandle {
|
||||
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 @@ class DirectMethodHandle extends MethodHandle {
|
||||
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 @@ class DirectMethodHandle extends MethodHandle {
|
||||
}
|
||||
@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 @@ class DirectMethodHandle extends MethodHandle {
|
||||
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 @@ class DirectMethodHandle extends MethodHandle {
|
||||
}
|
||||
@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 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
|
||||
/*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 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
|
||||
} 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 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
|
||||
return false; // DMH.Special returns true
|
||||
}
|
||||
|
||||
/*non-public*/
|
||||
boolean isCrackable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*non-public*/
|
||||
Object internalValues() {
|
||||
return null;
|
||||
|
@ -3282,11 +3282,10 @@ return mh1;
|
||||
* @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));
|
||||
|
Loading…
x
Reference in New Issue
Block a user