下面列出了java.lang.invoke.MethodType#changeReturnType ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private static MethodType createLambdaMethodType(Method method, MethodType instantiatedMethodType) {
boolean isStatic = Modifier.isStatic(method.getModifiers());
MethodType signature = isStatic ? instantiatedMethodType : instantiatedMethodType.changeParameterType(0, Object.class);
Class<?>[] params = method.getParameterTypes();
for (int i=0; i<params.length; i++){
if (Object.class.isAssignableFrom(params[i])){
signature = signature.changeParameterType(isStatic ? i : i+1, Object.class);
}
}
if (Object.class.isAssignableFrom(signature.returnType())){
signature = signature.changeReturnType(Object.class);
}
return signature;
}
private static MethodType createLambdaMethodType(Method method, MethodType instantiatedMethodType) {
boolean isStatic = Modifier.isStatic(method.getModifiers());
MethodType signature = isStatic ? instantiatedMethodType : instantiatedMethodType.changeParameterType(0, Object.class);
Class<?>[] params = method.getParameterTypes();
for (int i=0; i<params.length; i++){
if (Object.class.isAssignableFrom(params[i])){
signature = signature.changeParameterType(isStatic ? i : i+1, Object.class);
}
}
if (Object.class.isAssignableFrom(signature.returnType())){
signature = signature.changeReturnType(Object.class);
}
return signature;
}
OverloadedMethod(final List<MethodHandle> methodHandles, final OverloadedDynamicMethod parent, final MethodType callSiteType,
final LinkerServices linkerServices) {
this.parent = parent;
final Class<?> commonRetType = getCommonReturnType(methodHandles);
this.callSiteType = callSiteType.changeReturnType(commonRetType);
this.linkerServices = linkerServices;
fixArgMethods = new ArrayList<>(methodHandles.size());
varArgMethods = new ArrayList<>(methodHandles.size());
final int argNum = callSiteType.parameterCount();
for(MethodHandle mh: methodHandles) {
if(mh.isVarargsCollector()) {
final MethodHandle asFixed = mh.asFixedArity();
if(argNum == asFixed.type().parameterCount()) {
fixArgMethods.add(asFixed);
}
varArgMethods.add(mh);
} else {
fixArgMethods.add(mh);
}
}
fixArgMethods.trimToSize();
varArgMethods.trimToSize();
final MethodHandle bound = SELECT_METHOD.bindTo(this);
final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType(
callSiteType.changeReturnType(MethodHandle.class));
invoker = linkerServices.asTypeLosslessReturn(MethodHandles.foldArguments(
MethodHandles.exactInvoker(this.callSiteType), collecting), callSiteType);
}
OverloadedMethod(final List<MethodHandle> methodHandles, final OverloadedDynamicMethod parent, final MethodType callSiteType,
final LinkerServices linkerServices) {
this.parent = parent;
final Class<?> commonRetType = getCommonReturnType(methodHandles);
this.callSiteType = callSiteType.changeReturnType(commonRetType);
this.linkerServices = linkerServices;
fixArgMethods = new ArrayList<>(methodHandles.size());
varArgMethods = new ArrayList<>(methodHandles.size());
final int argNum = callSiteType.parameterCount();
for(MethodHandle mh: methodHandles) {
if(mh.isVarargsCollector()) {
final MethodHandle asFixed = mh.asFixedArity();
if(argNum == asFixed.type().parameterCount()) {
fixArgMethods.add(asFixed);
}
varArgMethods.add(mh);
} else {
fixArgMethods.add(mh);
}
}
fixArgMethods.trimToSize();
varArgMethods.trimToSize();
final MethodHandle bound = SELECT_METHOD.bindTo(this);
final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType(
callSiteType.changeReturnType(MethodHandle.class));
invoker = linkerServices.asTypeLosslessReturn(MethodHandles.foldArguments(
MethodHandles.exactInvoker(this.callSiteType), collecting), callSiteType);
}
OverloadedMethod(final List<MethodHandle> methodHandles, final OverloadedDynamicMethod parent, final MethodType callSiteType,
final LinkerServices linkerServices) {
this.parent = parent;
final Class<?> commonRetType = getCommonReturnType(methodHandles);
this.callSiteType = callSiteType.changeReturnType(commonRetType);
this.linkerServices = linkerServices;
fixArgMethods = new ArrayList<>(methodHandles.size());
varArgMethods = new ArrayList<>(methodHandles.size());
final int argNum = callSiteType.parameterCount();
for(MethodHandle mh: methodHandles) {
if(mh.isVarargsCollector()) {
final MethodHandle asFixed = mh.asFixedArity();
if(argNum == asFixed.type().parameterCount()) {
fixArgMethods.add(asFixed);
}
varArgMethods.add(mh);
} else {
fixArgMethods.add(mh);
}
}
fixArgMethods.trimToSize();
varArgMethods.trimToSize();
final MethodHandle bound = SELECT_METHOD.bindTo(this);
final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType(
callSiteType.changeReturnType(MethodHandle.class));
invoker = linkerServices.asTypeLosslessReturn(MethodHandles.foldArguments(
MethodHandles.exactInvoker(this.callSiteType), collecting), callSiteType);
}
OverloadedMethod(final List<MethodHandle> methodHandles, final OverloadedDynamicMethod parent, final MethodType callSiteType,
final LinkerServices linkerServices) {
this.parent = parent;
final Class<?> commonRetType = getCommonReturnType(methodHandles);
this.callSiteType = callSiteType.changeReturnType(commonRetType);
this.linkerServices = linkerServices;
fixArgMethods = new ArrayList<>(methodHandles.size());
varArgMethods = new ArrayList<>(methodHandles.size());
final int argNum = callSiteType.parameterCount();
for(MethodHandle mh: methodHandles) {
if(mh.isVarargsCollector()) {
final MethodHandle asFixed = mh.asFixedArity();
if(argNum == asFixed.type().parameterCount()) {
fixArgMethods.add(asFixed);
}
varArgMethods.add(mh);
} else {
fixArgMethods.add(mh);
}
}
fixArgMethods.trimToSize();
varArgMethods.trimToSize();
final MethodHandle bound = SELECT_METHOD.bindTo(this);
final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType(
callSiteType.changeReturnType(MethodHandle.class));
invoker = linkerServices.asTypeLosslessReturn(MethodHandles.foldArguments(
MethodHandles.exactInvoker(this.callSiteType), collecting), callSiteType);
}
static MethodHandle tweak(MethodHandle mh, int argPos, Class<?> type) {
MethodType mt = mh.type();
if (argPos == -1)
mt = mt.changeReturnType(type);
else
mt = mt.changeParameterType(argPos, type);
return MethodHandles.explicitCastArguments(mh, mt);
}
OverloadedMethod(final List<MethodHandle> methodHandles,
final OverloadedDynamicMethod parent,
final ClassLoader callSiteClassLoader,
final MethodType callSiteType,
final LinkerServices linkerServices,
final SecureLookupSupplier lookupSupplier) {
this.parent = parent;
this.callSiteClassLoader = callSiteClassLoader;
final Class<?> commonRetType = getCommonReturnType(methodHandles);
this.callSiteType = callSiteType.changeReturnType(commonRetType);
this.linkerServices = linkerServices;
this.lookupSupplier = lookupSupplier;
fixArgMethods = new ArrayList<>(methodHandles.size());
varArgMethods = new ArrayList<>(methodHandles.size());
final int argNum = callSiteType.parameterCount();
for(final MethodHandle mh: methodHandles) {
if(mh.isVarargsCollector()) {
final MethodHandle asFixed = mh.asFixedArity();
if(argNum == asFixed.type().parameterCount()) {
fixArgMethods.add(asFixed);
}
varArgMethods.add(mh);
} else {
fixArgMethods.add(mh);
}
}
fixArgMethods.trimToSize();
varArgMethods.trimToSize();
final MethodHandle bound = SELECT_METHOD.bindTo(this);
final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType(
callSiteType.changeReturnType(MethodHandle.class));
invoker = linkerServices.asTypeLosslessReturn(MethodHandles.foldArguments(
MethodHandles.exactInvoker(this.callSiteType), collecting), callSiteType);
}
OverloadedMethod(final List<MethodHandle> methodHandles, final OverloadedDynamicMethod parent, final MethodType callSiteType,
final LinkerServices linkerServices) {
this.parent = parent;
final Class<?> commonRetType = getCommonReturnType(methodHandles);
this.callSiteType = callSiteType.changeReturnType(commonRetType);
this.linkerServices = linkerServices;
fixArgMethods = new ArrayList<>(methodHandles.size());
varArgMethods = new ArrayList<>(methodHandles.size());
final int argNum = callSiteType.parameterCount();
for(MethodHandle mh: methodHandles) {
if(mh.isVarargsCollector()) {
final MethodHandle asFixed = mh.asFixedArity();
if(argNum == asFixed.type().parameterCount()) {
fixArgMethods.add(asFixed);
}
varArgMethods.add(mh);
} else {
fixArgMethods.add(mh);
}
}
fixArgMethods.trimToSize();
varArgMethods.trimToSize();
final MethodHandle bound = SELECT_METHOD.bindTo(this);
final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType(
callSiteType.changeReturnType(MethodHandle.class));
invoker = linkerServices.asTypeLosslessReturn(MethodHandles.foldArguments(
MethodHandles.exactInvoker(this.callSiteType), collecting), callSiteType);
}
@Override
protected MethodHandle initMethodHandle(ServicesAmp ampManager,
Method method)
throws IllegalAccessException
{
Class<?> []paramTypes = method.getParameterTypes();
int paramLen = paramTypes.length;
int resultOffset = findResultOffset(method, paramTypes);
method.setAccessible(true);
MethodHandle mh = MethodHandles.lookup().unreflect(method);
int []permute = new int[paramLen + 1];
permute[0] = 0;
for (int i = 0; i < resultOffset; i++) {
permute[i + 1] = i + 2;
}
for (int i = resultOffset + 1; i < paramLen; i++) {
permute[i + 1] = i + 1;
}
permute[resultOffset + 1] = 1;
MethodType type = MethodType.genericMethodType(paramLen + 1);
type = type.changeReturnType(void.class);
mh = mh.asFixedArity();
mh = mh.asType(type);
mh = MethodHandles.permuteArguments(mh, type, permute);
mh = mh.asSpreader(Object[].class, paramTypes.length - 1);
type = MethodType.methodType(void.class,
Object.class,
Result.class,
Object[].class);
return mh.asType(type);
}
OverloadedMethod(final List<MethodHandle> methodHandles, final OverloadedDynamicMethod parent, final MethodType callSiteType,
final LinkerServices linkerServices) {
this.parent = parent;
final Class<?> commonRetType = getCommonReturnType(methodHandles);
this.callSiteType = callSiteType.changeReturnType(commonRetType);
this.linkerServices = linkerServices;
fixArgMethods = new ArrayList<>(methodHandles.size());
varArgMethods = new ArrayList<>(methodHandles.size());
final int argNum = callSiteType.parameterCount();
for(MethodHandle mh: methodHandles) {
if(mh.isVarargsCollector()) {
final MethodHandle asFixed = mh.asFixedArity();
if(argNum == asFixed.type().parameterCount()) {
fixArgMethods.add(asFixed);
}
varArgMethods.add(mh);
} else {
fixArgMethods.add(mh);
}
}
fixArgMethods.trimToSize();
varArgMethods.trimToSize();
final MethodHandle bound = SELECT_METHOD.bindTo(this);
final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType(
callSiteType.changeReturnType(MethodHandle.class));
invoker = linkerServices.asTypeLosslessReturn(MethodHandles.foldArguments(
MethodHandles.exactInvoker(this.callSiteType), collecting), callSiteType);
}
private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<String> operations) throws Exception {
switch(callSiteDescriptor.getNameTokenCount()) {
case 2: {
// Must have three arguments: target object, property name, and property value.
assertParameterCount(callSiteDescriptor, 3);
// We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
// valid for us to convert return values proactively. Also, since we don't know what setters will be
// invoked, we'll conservatively presume Object return type. The one exception is void return.
final MethodType origType = callSiteDescriptor.getMethodType();
final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
// get_setter_handle(type, linkerServices))
// only with a bunch of method signature adjustments. Basically, retrieve method setter
// MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
// component's invocation.
// Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
// abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using
// Object return type).
final MethodType setterType = type.dropParameterTypes(1, 2);
// Bind property setter handle to the expected setter type and linker services. Type is
// MethodHandle(Object, String, Object)
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
callSiteDescriptor.changeMethodType(setterType), linkerServices);
// Cast getter to MethodHandle(O, N, V)
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
MethodHandle.class));
// Handle to invoke the setter R(MethodHandle, O, V)
final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
// Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations);
final MethodHandle fallbackFolded;
if(nextComponent == null) {
// Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
} else {
// Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the
// extra argument resulting from fold
fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
0, MethodHandle.class);
}
// fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
if(nextComponent == null) {
return getClassGuardedInvocationComponent(compositeSetter, type);
}
return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
case 3: {
// Must have two arguments: target object and property value
assertParameterCount(callSiteDescriptor, 2);
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
// If we have a property setter with this name, this composite operation will always stop here
if(gi != null) {
return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
}
// If we don't have a property setter with this name, always fall back to the next operation in the
// composite (if any)
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations);
}
default: {
// More than two name components; don't know what to do with it.
return null;
}
}
}
private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<String> operations) throws Exception {
switch(callSiteDescriptor.getNameTokenCount()) {
case 2: {
// Must have three arguments: target object, property name, and property value.
assertParameterCount(callSiteDescriptor, 3);
// We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
// valid for us to convert return values proactively. Also, since we don't know what setters will be
// invoked, we'll conservatively presume Object return type. The one exception is void return.
final MethodType origType = callSiteDescriptor.getMethodType();
final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
// get_setter_handle(type, linkerServices))
// only with a bunch of method signature adjustments. Basically, retrieve method setter
// MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
// component's invocation.
// Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
// abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using
// Object return type).
final MethodType setterType = type.dropParameterTypes(1, 2);
// Bind property setter handle to the expected setter type and linker services. Type is
// MethodHandle(Object, String, Object)
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
callSiteDescriptor.changeMethodType(setterType), linkerServices);
// Cast getter to MethodHandle(O, N, V)
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
MethodHandle.class));
// Handle to invoke the setter R(MethodHandle, O, V)
final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
// Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations);
final MethodHandle fallbackFolded;
if(nextComponent == null) {
// Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
} else {
// Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the
// extra argument resulting from fold
fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
0, MethodHandle.class);
}
// fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
if(nextComponent == null) {
return getClassGuardedInvocationComponent(compositeSetter, type);
}
return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
case 3: {
// Must have two arguments: target object and property value
assertParameterCount(callSiteDescriptor, 2);
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
// If we have a property setter with this name, this composite operation will always stop here
if(gi != null) {
return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
}
// If we don't have a property setter with this name, always fall back to the next operation in the
// composite (if any)
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations);
}
default: {
// More than two name components; don't know what to do with it.
return null;
}
}
}
private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<String> operations) throws Exception {
switch(callSiteDescriptor.getNameTokenCount()) {
case 2: {
// Must have three arguments: target object, property name, and property value.
assertParameterCount(callSiteDescriptor, 3);
// We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
// valid for us to convert return values proactively. Also, since we don't know what setters will be
// invoked, we'll conservatively presume Object return type. The one exception is void return.
final MethodType origType = callSiteDescriptor.getMethodType();
final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
// get_setter_handle(type, linkerServices))
// only with a bunch of method signature adjustments. Basically, retrieve method setter
// MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
// component's invocation.
// Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
// abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using
// Object return type).
final MethodType setterType = type.dropParameterTypes(1, 2);
// Bind property setter handle to the expected setter type and linker services. Type is
// MethodHandle(Object, String, Object)
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
callSiteDescriptor.changeMethodType(setterType), linkerServices);
// Cast getter to MethodHandle(O, N, V)
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
MethodHandle.class));
// Handle to invoke the setter R(MethodHandle, O, V)
final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
// Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations);
final MethodHandle fallbackFolded;
if(nextComponent == null) {
// Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
} else {
// Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the
// extra argument resulting from fold
fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
0, MethodHandle.class);
}
// fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
if(nextComponent == null) {
return getClassGuardedInvocationComponent(compositeSetter, type);
}
return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
case 3: {
// Must have two arguments: target object and property value
assertParameterCount(callSiteDescriptor, 2);
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
// If we have a property setter with this name, this composite operation will always stop here
if(gi != null) {
return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
}
// If we don't have a property setter with this name, always fall back to the next operation in the
// composite (if any)
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations);
}
default: {
// More than two name components; don't know what to do with it.
return null;
}
}
}
private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<String> operations) throws Exception {
switch(callSiteDescriptor.getNameTokenCount()) {
case 2: {
// Must have three arguments: target object, property name, and property value.
assertParameterCount(callSiteDescriptor, 3);
// We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
// valid for us to convert return values proactively. Also, since we don't know what setters will be
// invoked, we'll conservatively presume Object return type. The one exception is void return.
final MethodType origType = callSiteDescriptor.getMethodType();
final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
// get_setter_handle(type, linkerServices))
// only with a bunch of method signature adjustments. Basically, retrieve method setter
// MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
// component's invocation.
// Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
// abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using
// Object return type).
final MethodType setterType = type.dropParameterTypes(1, 2);
// Bind property setter handle to the expected setter type and linker services. Type is
// MethodHandle(Object, String, Object)
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
callSiteDescriptor.changeMethodType(setterType), linkerServices);
// Cast getter to MethodHandle(O, N, V)
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
MethodHandle.class));
// Handle to invoke the setter R(MethodHandle, O, V)
final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
// Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations);
final MethodHandle fallbackFolded;
if(nextComponent == null) {
// Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
} else {
// Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the
// extra argument resulting from fold
fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
0, MethodHandle.class);
}
// fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
if(nextComponent == null) {
return getClassGuardedInvocationComponent(compositeSetter, type);
}
return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
case 3: {
// Must have two arguments: target object and property value
assertParameterCount(callSiteDescriptor, 2);
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
// If we have a property setter with this name, this composite operation will always stop here
if(gi != null) {
return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
}
// If we don't have a property setter with this name, always fall back to the next operation in the
// composite (if any)
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations);
}
default: {
// More than two name components; don't know what to do with it.
return null;
}
}
}
private GuardedInvocationComponent getUnnamedPropertySetter(final ComponentLinkRequest req) throws Exception {
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
// Must have three arguments: target object, property name, and property value.
assertParameterCount(callSiteDescriptor, 3);
// We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
// valid for us to convert return values proactively. Also, since we don't know what setters will be
// invoked, we'll conservatively presume Object return type. The one exception is void return.
final MethodType origType = callSiteDescriptor.getMethodType();
final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
final LinkerServices linkerServices = req.linkerServices;
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
// get_setter_handle(type, linkerServices))
// only with a bunch of method signature adjustments. Basically, retrieve method setter
// MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
// component's invocation.
// Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
// abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using
// Object return type).
final MethodType setterType = type.dropParameterTypes(1, 2);
// Bind property setter handle to the expected setter type and linker services. Type is
// MethodHandle(Object, String, Object)
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
callSiteDescriptor.changeMethodType(setterType), linkerServices);
// Cast getter to MethodHandle(O, N, V)
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
MethodHandle.class));
// Handle to invoke the setter R(MethodHandle, O, V)
final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
// Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
1));
final GuardedInvocationComponent nextComponent = getNextComponent(req);
final MethodHandle fallbackFolded;
if (nextComponent == null) {
// Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
} else {
// Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the
// extra argument resulting from fold
fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
0, MethodHandle.class);
}
// fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
if(nextComponent == null) {
return getClassGuardedInvocationComponent(compositeSetter, type);
}
return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<String> operations) throws Exception {
switch(callSiteDescriptor.getNameTokenCount()) {
case 2: {
// Must have three arguments: target object, property name, and property value.
assertParameterCount(callSiteDescriptor, 3);
// We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
// valid for us to convert return values proactively. Also, since we don't know what setters will be
// invoked, we'll conservatively presume Object return type. The one exception is void return.
final MethodType origType = callSiteDescriptor.getMethodType();
final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
// get_setter_handle(type, linkerServices))
// only with a bunch of method signature adjustments. Basically, retrieve method setter
// MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
// component's invocation.
// Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
// abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using
// Object return type).
final MethodType setterType = type.dropParameterTypes(1, 2);
// Bind property setter handle to the expected setter type and linker services. Type is
// MethodHandle(Object, String, Object)
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
callSiteDescriptor.changeMethodType(setterType), linkerServices);
// Cast getter to MethodHandle(O, N, V)
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
MethodHandle.class));
// Handle to invoke the setter R(MethodHandle, O, V)
final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
// Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations);
final MethodHandle fallbackFolded;
if(nextComponent == null) {
// Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
} else {
// Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the
// extra argument resulting from fold
fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
0, MethodHandle.class);
}
// fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
if(nextComponent == null) {
return getClassGuardedInvocationComponent(compositeSetter, type);
}
return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
case 3: {
// Must have two arguments: target object and property value
assertParameterCount(callSiteDescriptor, 2);
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
// If we have a property setter with this name, this composite operation will always stop here
if(gi != null) {
return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
}
// If we don't have a property setter with this name, always fall back to the next operation in the
// composite (if any)
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations);
}
default: {
// More than two name components; don't know what to do with it.
return null;
}
}
}
protected MethodHandle initMethodHandle(ServicesAmp ampManager,
Method method)
throws IllegalAccessException
{
Class<?> []paramTypes = method.getParameterTypes();
int paramLen = paramTypes.length;
int resultOffset = findResultOffset(paramTypes);
method.setAccessible(true);
MethodHandle mh = MethodHandles.lookup().unreflect(method);
int []permute = new int[paramLen + 1];
permute[0] = 0;
for (int i = 0; i < resultOffset; i++) {
permute[i + 1] = i + 2;
}
for (int i = resultOffset + 1; i < paramLen; i++) {
permute[i + 1] = i + 1;
}
permute[resultOffset + 1] = 1;
MethodType type = MethodType.genericMethodType(paramLen + 1);
type = type.changeReturnType(void.class);
mh = mh.asType(type);
mh = filterMethod(ampManager,
mh,
method);
mh = MethodHandles.permuteArguments(mh, type, permute);
/*
if (paramLen > 0 && ! Object[].class.equals(paramTypes[paramLen - 1])) {
}
*/
mh = mh.asSpreader(Object[].class, paramLen - 1);
type = MethodType.methodType(void.class,
Object.class,
getResultClass(),
Object[].class);
return mh.asType(type);
}
private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<String> operations) throws Exception {
switch(callSiteDescriptor.getNameTokenCount()) {
case 2: {
// Must have three arguments: target object, property name, and property value.
assertParameterCount(callSiteDescriptor, 3);
// We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
// valid for us to convert return values proactively. Also, since we don't know what setters will be
// invoked, we'll conservatively presume Object return type. The one exception is void return.
final MethodType origType = callSiteDescriptor.getMethodType();
final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
// get_setter_handle(type, linkerServices))
// only with a bunch of method signature adjustments. Basically, retrieve method setter
// MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
// component's invocation.
// Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
// abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using
// Object return type).
final MethodType setterType = type.dropParameterTypes(1, 2);
// Bind property setter handle to the expected setter type and linker services. Type is
// MethodHandle(Object, String, Object)
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
callSiteDescriptor.changeMethodType(setterType), linkerServices);
// Cast getter to MethodHandle(O, N, V)
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
MethodHandle.class));
// Handle to invoke the setter R(MethodHandle, O, V)
final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
// Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations);
final MethodHandle fallbackFolded;
if(nextComponent == null) {
// Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
} else {
// Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the
// extra argument resulting from fold
fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
0, MethodHandle.class);
}
// fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
if(nextComponent == null) {
return getClassGuardedInvocationComponent(compositeSetter, type);
}
return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
case 3: {
// Must have two arguments: target object and property value
assertParameterCount(callSiteDescriptor, 2);
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
// If we have a property setter with this name, this composite operation will always stop here
if(gi != null) {
return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
}
// If we don't have a property setter with this name, always fall back to the next operation in the
// composite (if any)
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations);
}
default: {
// More than two name components; don't know what to do with it.
return null;
}
}
}