8050173: Add j.l.i.MethodHandle.copyWith(MethodType, LambdaForm)

Reviewed-by: vlivanov, psandoz
This commit is contained in:
John Rose 2014-09-10 19:19:49 +04:00 committed by Vladimir Ivanov
parent 2f4b5e8534
commit 71bae4addc
7 changed files with 93 additions and 41 deletions

View File

@ -242,7 +242,7 @@ public class CallSite {
invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_UNINIT_CS, invoker); invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_UNINIT_CS, invoker);
} }
// unchecked view is OK since no values will be received or returned // unchecked view is OK since no values will be received or returned
return invoker.viewAsType(targetType); return invoker.viewAsType(targetType, false);
} }
// unsafe stuff: // unsafe stuff:

View File

@ -126,6 +126,12 @@ class DirectMethodHandle extends MethodHandle {
return new Constructor(mtype, lform, ctor, init, instanceClass); 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 @Override
String internalProperties() { String internalProperties() {
return "\n& DMH.MN="+internalMemberName(); return "\n& DMH.MN="+internalMemberName();
@ -133,10 +139,6 @@ class DirectMethodHandle extends MethodHandle {
//// Implementation methods. //// Implementation methods.
@Override @Override
MethodHandle viewAsType(MethodType newType) {
return new DirectMethodHandle(newType, form, member);
}
@Override
@ForceInline @ForceInline
MemberName internalMemberName() { MemberName internalMemberName() {
return member; return member;
@ -364,8 +366,8 @@ class DirectMethodHandle extends MethodHandle {
return true; return true;
} }
@Override @Override
MethodHandle viewAsType(MethodType newType) { MethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new Special(newType, form, member); return new Special(mt, lf, member);
} }
} }
@ -382,8 +384,8 @@ class DirectMethodHandle extends MethodHandle {
assert(initMethod.isResolved()); assert(initMethod.isResolved());
} }
@Override @Override
MethodHandle viewAsType(MethodType newType) { MethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new Constructor(newType, form, member, initMethod, instanceClass); return new Constructor(mt, lf, member, initMethod, instanceClass);
} }
} }
@ -412,8 +414,8 @@ class DirectMethodHandle extends MethodHandle {
return fieldType.cast(obj); return fieldType.cast(obj);
} }
@Override @Override
MethodHandle viewAsType(MethodType newType) { MethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new Accessor(newType, form, member, fieldOffset); return new Accessor(mt, lf, member, fieldOffset);
} }
} }
@ -455,8 +457,8 @@ class DirectMethodHandle extends MethodHandle {
return fieldType.cast(obj); return fieldType.cast(obj);
} }
@Override @Override
MethodHandle viewAsType(MethodType newType) { MethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new StaticAccessor(newType, form, member, staticBase, staticOffset); return new StaticAccessor(mt, lf, member, staticBase, staticOffset);
} }
} }

View File

@ -1315,9 +1315,27 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
} }
/*non-public*/ /*non-public*/
MethodHandle viewAsType(MethodType newType) { MethodHandle viewAsType(MethodType newType, boolean strict) {
// No actual conversions, just a new view of the same method. // 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 // Decoding
@ -1372,6 +1390,9 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
//// Sub-classes can override these default implementations. //// Sub-classes can override these default implementations.
//// All these methods assume arguments are already validated. //// All these methods assume arguments are already validated.
/*non-public*/
abstract MethodHandle copyWith(MethodType mt, LambdaForm lf);
/*non-public*/ /*non-public*/
BoundMethodHandle rebind() { BoundMethodHandle rebind() {
// Bind 'this' into a new invoker, of the known class BMH. // Bind 'this' into a new invoker, of the known class BMH.

View File

@ -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 ? mh.type().parameterType(2) : mh.type().returnType()) == Object.class);
assert(isSetter || correctType.parameterType(0).getComponentType() == correctType.returnType()); assert(isSetter || correctType.parameterType(0).getComponentType() == correctType.returnType());
// safe to view non-strictly, because element type follows from array type // 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. // Atomically update accessor cache.
synchronized(cache) { synchronized(cache) {
@ -406,18 +406,21 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} }
@Override @Override
MethodHandle setVarargs(MemberName member) { boolean viewAsTypeChecks(MethodType newType, boolean strict) {
if (member.isVarargs()) return this; super.viewAsTypeChecks(newType, true);
return asFixedArity(); 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 @Override
MethodHandle viewAsType(MethodType newType) { MethodHandle setVarargs(MemberName member) {
if (newType.lastParameterType() != type().lastParameterType()) if (member.isVarargs()) return this;
throw new InternalError(); return asFixedArity();
MethodHandle newTarget = asFixedArity().viewAsType(newType);
// put back the varargs bit:
return new AsVarargsCollector(newTarget, newType, arrayType);
} }
@Override @Override
@ -434,6 +437,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
boolean isInvokeSpecial() { boolean isInvokeSpecial() {
return asFixedArity().isInvokeSpecial(); return asFixedArity().isInvokeSpecial();
} }
@Override
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
throw newIllegalArgumentException("do not use this");
}
} }
/** Factory method: Spread selected argument. */ /** Factory method: Spread selected argument. */
@ -996,9 +1004,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
boolean isInvokeSpecial() { boolean isInvokeSpecial() {
return target.isInvokeSpecial(); return target.isInvokeSpecial();
} }
@Override @Override
MethodHandle viewAsType(MethodType newType) { MethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new WrappedMember(target, newType, member, callerClass); throw newIllegalArgumentException("do not use this");
} }
} }

View File

@ -1579,7 +1579,7 @@ return mh1;
return false; return false;
return true; 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()); assert(!method.isStatic());
// receiver type of mh is too wide; narrow to caller // receiver type of mh is too wide; narrow to caller
if (!method.getDeclaringClass().isAssignableFrom(caller)) { if (!method.getDeclaringClass().isAssignableFrom(caller)) {
@ -1588,7 +1588,9 @@ return mh1;
MethodType rawType = mh.type(); MethodType rawType = mh.type();
if (rawType.parameterType(0) == caller) return mh; if (rawType.parameterType(0) == caller) return mh;
MethodType narrowType = rawType.changeParameterType(0, caller); 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. */ /** Check access and get the requested method. */
@ -1650,15 +1652,17 @@ return mh1;
checkMethod(refKind, refc, method); checkMethod(refKind, refc, method);
} }
MethodHandle mh = DirectMethodHandle.make(refKind, refc, method); DirectMethodHandle dmh = DirectMethodHandle.make(refKind, refc, method);
mh = maybeBindCaller(method, mh, callerClass); MethodHandle mh = dmh;
mh = mh.setVarargs(method);
// Optionally narrow the receiver argument to refc using restrictReceiver. // Optionally narrow the receiver argument to refc using restrictReceiver.
if (doRestrict && if (doRestrict &&
(refKind == REF_invokeSpecial || (refKind == REF_invokeSpecial ||
(MethodHandleNatives.refKindHasReceiver(refKind) && (MethodHandleNatives.refKindHasReceiver(refKind) &&
restrictProtectedReceiver(method)))) restrictProtectedReceiver(method)))) {
mh = restrictReceiver(method, mh, lookupClass()); mh = restrictReceiver(method, dmh, lookupClass());
}
mh = maybeBindCaller(method, mh, callerClass);
mh = mh.setVarargs(method);
return mh; return mh;
} }
private MethodHandle maybeBindCaller(MemberName method, MethodHandle 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. // Optionally check with the security manager; this isn't needed for unreflect* calls.
if (checkSecurity) if (checkSecurity)
checkSecurityManager(refc, field); checkSecurityManager(refc, field);
MethodHandle mh = DirectMethodHandle.make(refc, field); DirectMethodHandle dmh = DirectMethodHandle.make(refc, field);
boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) && boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) &&
restrictProtectedReceiver(field)); restrictProtectedReceiver(field));
if (doRestrict) if (doRestrict)
mh = restrictReceiver(field, mh, lookupClass()); return restrictReceiver(field, dmh, lookupClass());
return mh; return dmh;
} }
/** Check access and get the requested constructor. */ /** Check access and get the requested constructor. */
private MethodHandle getDirectConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException { private MethodHandle getDirectConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException {

View File

@ -773,16 +773,27 @@ class MethodType implements java.io.Serializable {
return sj.toString(); 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*/ /*non-public*/
boolean isViewableAs(MethodType newType) { boolean isViewableAs(MethodType newType, boolean keepInterfaces) {
if (!VerifyType.isNullConversion(returnType(), newType.returnType(), true)) if (!VerifyType.isNullConversion(returnType(), newType.returnType(), keepInterfaces))
return false; 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(); int argc = parameterCount();
if (argc != newType.parameterCount()) if (argc != newType.parameterCount())
return false; return false;
for (int i = 0; i < argc; i++) { 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 false;
} }
return true; return true;

View File

@ -37,4 +37,9 @@ final class SimpleMethodHandle extends MethodHandle {
/*non-public*/ static SimpleMethodHandle make(MethodType type, LambdaForm form) { /*non-public*/ static SimpleMethodHandle make(MethodType type, LambdaForm form) {
return new SimpleMethodHandle(type, form); return new SimpleMethodHandle(type, form);
} }
@Override
/*non-public*/ SimpleMethodHandle copyWith(MethodType mt, LambdaForm lf) {
return make(mt, lf);
}
} }