8050173: Add j.l.i.MethodHandle.copyWith(MethodType, LambdaForm)
Reviewed-by: vlivanov, psandoz
This commit is contained in:
parent
2f4b5e8534
commit
71bae4addc
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user