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);
|
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:
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user