# HG changeset patch # User vlivanov # Date 1410362389 -14400 # Node ID 1586df597397f68949c565fa25e53a7656058262 # Parent e6bc14fae1cff125d62a11e552d940cdb59ce4f5 8050173: Add j.l.i.MethodHandle.copyWith(MethodType, LambdaForm) Reviewed-by: vlivanov, psandoz Contributed-by: john.r.rose@oracle.com diff -r e6bc14fae1cf -r 1586df597397 jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java Wed Sep 10 19:19:48 2014 +0400 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java Wed Sep 10 19:19:49 2014 +0400 @@ -242,7 +242,7 @@ 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 -r e6bc14fae1cf -r 1586df597397 jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Wed Sep 10 19:19:48 2014 +0400 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Wed Sep 10 19:19:49 2014 +0400 @@ -127,16 +127,18 @@ } @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(); } //// Implementation methods. @Override - MethodHandle viewAsType(MethodType newType) { - return new DirectMethodHandle(newType, form, member); - } - @Override @ForceInline MemberName internalMemberName() { return member; @@ -364,8 +366,8 @@ 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 @@ 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 @@ 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 @@ 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 -r e6bc14fae1cf -r 1586df597397 jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java Wed Sep 10 19:19:48 2014 +0400 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java Wed Sep 10 19:19:49 2014 +0400 @@ -1315,9 +1315,27 @@ } /*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 @@ -1373,6 +1391,9 @@ //// 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. MethodType type2 = type(); diff -r e6bc14fae1cf -r 1586df597397 jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Sep 10 19:19:48 2014 +0400 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Sep 10 19:19:49 2014 +0400 @@ -84,7 +84,7 @@ 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 @@ } @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 @@ 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 @@ 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 -r e6bc14fae1cf -r 1586df597397 jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Sep 10 19:19:48 2014 +0400 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Sep 10 19:19:49 2014 +0400 @@ -1579,7 +1579,7 @@ 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 @@ 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 @@ 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 @@ // 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 -r e6bc14fae1cf -r 1586df597397 jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java Wed Sep 10 19:19:48 2014 +0400 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java Wed Sep 10 19:19:49 2014 +0400 @@ -773,16 +773,27 @@ 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 -r e6bc14fae1cf -r 1586df597397 jdk/src/java.base/share/classes/java/lang/invoke/SimpleMethodHandle.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/SimpleMethodHandle.java Wed Sep 10 19:19:48 2014 +0400 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/SimpleMethodHandle.java Wed Sep 10 19:19:49 2014 +0400 @@ -37,4 +37,9 @@ /*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); + } }