# HG changeset patch # User redestad # Date 1588673486 -7200 # Tue May 05 12:11:26 2020 +0200 # Node ID 6f710011253854d55cb026bb8292128946a9af4d # Parent 1b7ad1f98a93884b31889d983a1d659f5976426b imported patch viewAs diff --git a/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java --- a/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java @@ -62,6 +62,21 @@ } @Override + boolean isCrackable() { + MemberName member = internalMemberName(); + return member != null && + (member.isResolved() || + member.isMethodHandleInvoke() || + member.isVarHandleMethodInvoke()); + } + + @Override + /*non-public*/ + MethodHandle viewAsType(MethodType newType, boolean strict) { + return getTarget().viewAsType(newType, strict); + } + + @Override boolean isInvokeSpecial() { return getTarget().isInvokeSpecial(); } diff --git a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java --- a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java @@ -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 @@ } this.member = member; + this.crackable = crackable; } // Factory methods: @@ -92,18 +94,18 @@ 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 @@ 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 @@ 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,8 +152,24 @@ @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); } + /*non-public*/ + @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); + } + /*non-public*/ + @Override + boolean isCrackable() { + return crackable; + } + @Override String internalProperties() { @@ -406,8 +424,8 @@ /** 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 +434,12 @@ } @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 +454,19 @@ /** 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); + 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) { @@ -463,15 +491,20 @@ 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 +525,8 @@ 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 +536,12 @@ } @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 +573,8 @@ 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 +585,12 @@ } @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); } } diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java --- a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -1640,12 +1640,9 @@ /*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. + // Overridden in DMH, which has special rules assert viewAsTypeChecks(newType, strict); - BoundMethodHandle mh = rebind(); - return mh.copyWith(newType, mh.form); + return copyWith(newType, form); } /*non-public*/ @@ -1704,6 +1701,11 @@ } /*non-public*/ + boolean isCrackable() { + return false; + } + + /*non-public*/ Object internalValues() { return null; } diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -3282,11 +3282,10 @@ * @since 1.8 */ public MethodHandleInfo revealDirect(MethodHandle target) { + if (!target.isCrackable()) { + throw newIllegalArgumentException("not a direct method handle"); + } MemberName member = target.internalMemberName(); - if (member == null || (!member.isResolved() && - !member.isMethodHandleInvoke() && - !member.isVarHandleMethodInvoke())) - throw newIllegalArgumentException("not a direct method handle"); Class defc = member.getDeclaringClass(); byte refKind = member.getReferenceKind(); assert(MethodHandleNatives.refKindIsValid(refKind));