diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java b/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java index 10e52e30435..10ac1c0716e 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java @@ -242,7 +242,7 @@ public class CallSite { invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_UNINIT_CS, invoker); } // unchecked view is OK since no values will be received or returned - return invoker.viewAsType(targetType); + return invoker.viewAsType(targetType, false); } // unsafe stuff: diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java index d688a304682..a76e80d8155 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java @@ -126,6 +126,12 @@ class DirectMethodHandle extends MethodHandle { return new Constructor(mtype, lform, ctor, init, instanceClass); } + @Override + MethodHandle copyWith(MethodType mt, LambdaForm lf) { + assert(this.getClass() == DirectMethodHandle.class); // must override in subclasses + return new DirectMethodHandle(mt, lf, member); + } + @Override String internalProperties() { return "\n& DMH.MN="+internalMemberName(); @@ -133,10 +139,6 @@ class DirectMethodHandle extends MethodHandle { //// Implementation methods. @Override - MethodHandle viewAsType(MethodType newType) { - return new DirectMethodHandle(newType, form, member); - } - @Override @ForceInline MemberName internalMemberName() { return member; @@ -364,8 +366,8 @@ class DirectMethodHandle extends MethodHandle { return true; } @Override - MethodHandle viewAsType(MethodType newType) { - return new Special(newType, form, member); + MethodHandle copyWith(MethodType mt, LambdaForm lf) { + return new Special(mt, lf, member); } } @@ -382,8 +384,8 @@ class DirectMethodHandle extends MethodHandle { assert(initMethod.isResolved()); } @Override - MethodHandle viewAsType(MethodType newType) { - return new Constructor(newType, form, member, initMethod, instanceClass); + MethodHandle copyWith(MethodType mt, LambdaForm lf) { + return new Constructor(mt, lf, member, initMethod, instanceClass); } } @@ -412,8 +414,8 @@ class DirectMethodHandle extends MethodHandle { return fieldType.cast(obj); } @Override - MethodHandle viewAsType(MethodType newType) { - return new Accessor(newType, form, member, fieldOffset); + MethodHandle copyWith(MethodType mt, LambdaForm lf) { + return new Accessor(mt, lf, member, fieldOffset); } } @@ -455,8 +457,8 @@ class DirectMethodHandle extends MethodHandle { return fieldType.cast(obj); } @Override - MethodHandle viewAsType(MethodType newType) { - return new StaticAccessor(newType, form, member, staticBase, staticOffset); + MethodHandle copyWith(MethodType mt, LambdaForm lf) { + return new StaticAccessor(mt, lf, member, staticBase, staticOffset); } } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java index a81a8ea6ed3..0514fbc016e 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -1315,9 +1315,27 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); } /*non-public*/ - MethodHandle viewAsType(MethodType newType) { + MethodHandle viewAsType(MethodType newType, boolean strict) { // No actual conversions, just a new view of the same method. - return MethodHandleImpl.makePairwiseConvert(this, newType, 0); + // 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(); + assert(!((MethodHandle)mh instanceof DirectMethodHandle)); + return mh.copyWith(newType, mh.form); + } + + /*non-public*/ + boolean viewAsTypeChecks(MethodType newType, boolean strict) { + if (strict) { + assert(type().isViewableAs(newType, true)) + : Arrays.asList(this, newType); + } else { + assert(type().basicType().isViewableAs(newType.basicType(), true)) + : Arrays.asList(this, newType); + } + return true; } // Decoding @@ -1372,6 +1390,9 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); //// Sub-classes can override these default implementations. //// All these methods assume arguments are already validated. + /*non-public*/ + abstract MethodHandle copyWith(MethodType mt, LambdaForm lf); + /*non-public*/ BoundMethodHandle rebind() { // Bind 'this' into a new invoker, of the known class BMH. diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index a1faff4b020..d4e9aef93a1 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -84,7 +84,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; assert((isSetter ? mh.type().parameterType(2) : mh.type().returnType()) == Object.class); assert(isSetter || correctType.parameterType(0).getComponentType() == correctType.returnType()); // safe to view non-strictly, because element type follows from array type - mh = mh.viewAsType(correctType); + mh = mh.viewAsType(correctType, false); } // Atomically update accessor cache. synchronized(cache) { @@ -406,18 +406,21 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; } @Override - MethodHandle setVarargs(MemberName member) { - if (member.isVarargs()) return this; - return asFixedArity(); + boolean viewAsTypeChecks(MethodType newType, boolean strict) { + super.viewAsTypeChecks(newType, true); + if (strict) return true; + // extra assertion for non-strict checks: + assert (type().lastParameterType().getComponentType() + .isAssignableFrom( + newType.lastParameterType().getComponentType())) + : Arrays.asList(this, newType); + return true; } @Override - MethodHandle viewAsType(MethodType newType) { - if (newType.lastParameterType() != type().lastParameterType()) - throw new InternalError(); - MethodHandle newTarget = asFixedArity().viewAsType(newType); - // put back the varargs bit: - return new AsVarargsCollector(newTarget, newType, arrayType); + MethodHandle setVarargs(MemberName member) { + if (member.isVarargs()) return this; + return asFixedArity(); } @Override @@ -434,6 +437,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; boolean isInvokeSpecial() { return asFixedArity().isInvokeSpecial(); } + + @Override + MethodHandle copyWith(MethodType mt, LambdaForm lf) { + throw newIllegalArgumentException("do not use this"); + } } /** Factory method: Spread selected argument. */ @@ -996,9 +1004,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; boolean isInvokeSpecial() { return target.isInvokeSpecial(); } + @Override - MethodHandle viewAsType(MethodType newType) { - return new WrappedMember(target, newType, member, callerClass); + MethodHandle copyWith(MethodType mt, LambdaForm lf) { + throw newIllegalArgumentException("do not use this"); } } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 6a30a22eced..67b324b7d2a 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -1579,7 +1579,7 @@ return mh1; return false; return true; } - private MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class caller) throws IllegalAccessException { + private MethodHandle restrictReceiver(MemberName method, DirectMethodHandle mh, Class caller) throws IllegalAccessException { assert(!method.isStatic()); // receiver type of mh is too wide; narrow to caller if (!method.getDeclaringClass().isAssignableFrom(caller)) { @@ -1588,7 +1588,9 @@ return mh1; MethodType rawType = mh.type(); if (rawType.parameterType(0) == caller) return mh; MethodType narrowType = rawType.changeParameterType(0, caller); - return mh.viewAsType(narrowType); + assert(!mh.isVarargsCollector()); // viewAsType will lose varargs-ness + assert(mh.viewAsTypeChecks(narrowType, true)); + return mh.copyWith(narrowType, mh.form); } /** Check access and get the requested method. */ @@ -1650,15 +1652,17 @@ return mh1; checkMethod(refKind, refc, method); } - MethodHandle mh = DirectMethodHandle.make(refKind, refc, method); - mh = maybeBindCaller(method, mh, callerClass); - mh = mh.setVarargs(method); + DirectMethodHandle dmh = DirectMethodHandle.make(refKind, refc, method); + MethodHandle mh = dmh; // Optionally narrow the receiver argument to refc using restrictReceiver. if (doRestrict && (refKind == REF_invokeSpecial || (MethodHandleNatives.refKindHasReceiver(refKind) && - restrictProtectedReceiver(method)))) - mh = restrictReceiver(method, mh, lookupClass()); + restrictProtectedReceiver(method)))) { + mh = restrictReceiver(method, dmh, lookupClass()); + } + mh = maybeBindCaller(method, mh, callerClass); + mh = mh.setVarargs(method); return mh; } private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh, @@ -1690,12 +1694,12 @@ return mh1; // Optionally check with the security manager; this isn't needed for unreflect* calls. if (checkSecurity) checkSecurityManager(refc, field); - MethodHandle mh = DirectMethodHandle.make(refc, field); + DirectMethodHandle dmh = DirectMethodHandle.make(refc, field); boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) && restrictProtectedReceiver(field)); if (doRestrict) - mh = restrictReceiver(field, mh, lookupClass()); - return mh; + return restrictReceiver(field, dmh, lookupClass()); + return dmh; } /** Check access and get the requested constructor. */ private MethodHandle getDirectConstructor(Class refc, MemberName ctor) throws IllegalAccessException { diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java index 16b7aeca631..b2877fbb25d 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java @@ -773,16 +773,27 @@ class MethodType implements java.io.Serializable { return sj.toString(); } - + /** True if the old return type can always be viewed (w/o casting) under new return type, + * and the new parameters can be viewed (w/o casting) under the old parameter types. + */ /*non-public*/ - boolean isViewableAs(MethodType newType) { - if (!VerifyType.isNullConversion(returnType(), newType.returnType(), true)) + boolean isViewableAs(MethodType newType, boolean keepInterfaces) { + if (!VerifyType.isNullConversion(returnType(), newType.returnType(), keepInterfaces)) return false; + return parametersAreViewableAs(newType, keepInterfaces); + } + /** True if the new parameters can be viewed (w/o casting) under the old parameter types. */ + /*non-public*/ + boolean parametersAreViewableAs(MethodType newType, boolean keepInterfaces) { + if (form == newType.form && form.erasedType == this) + return true; // my reference parameters are all Object + if (ptypes == newType.ptypes) + return true; int argc = parameterCount(); if (argc != newType.parameterCount()) return false; for (int i = 0; i < argc; i++) { - if (!VerifyType.isNullConversion(newType.parameterType(i), parameterType(i), true)) + if (!VerifyType.isNullConversion(newType.parameterType(i), parameterType(i), keepInterfaces)) return false; } return true; diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/SimpleMethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/SimpleMethodHandle.java index 0dd0b7f1880..9b36a7eac03 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/SimpleMethodHandle.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/SimpleMethodHandle.java @@ -37,4 +37,9 @@ final class SimpleMethodHandle extends MethodHandle { /*non-public*/ static SimpleMethodHandle make(MethodType type, LambdaForm form) { return new SimpleMethodHandle(type, form); } + + @Override + /*non-public*/ SimpleMethodHandle copyWith(MethodType mt, LambdaForm lf) { + return make(mt, lf); + } }