}
// checkArity(desc.anno, method, specificArity);
SmartBinder targetBinder;
SmartHandle target;
Signature baseSignature;
if (specificArity >= 0) {
baseSignature = SPECIFIC_ARITY_SIGNATURES[specificArity];
} else {
baseSignature = VARIABLE_ARITY_SIGNATURE;
}
targetBinder = SmartBinder.from(baseSignature);
MethodHandle returnFilter = null;
boolean castReturn = false;
if (desc.returnClass != IRubyObject.class) {
if (desc.returnClass == void.class) {
returnFilter = MethodHandles.constant(IRubyObject.class, runtime.getNil());
} else {
castReturn = true;
}
}
if (desc.isStatic) {
if (desc.hasContext) {
if (desc.hasBlock) {
// straight through with no permutation necessary
} else {
targetBinder = targetBinder.exclude("block");
}
} else {
if (desc.hasBlock) {
targetBinder = targetBinder.exclude("context");
} else {
targetBinder = targetBinder.exclude("context", "block");
}
}
if (returnFilter != null) {
targetBinder = targetBinder
.filterReturn(returnFilter);
} else if (castReturn) {
targetBinder = targetBinder
.castReturn(desc.returnClass);
}
} else {
if (desc.hasContext) {
if (desc.hasBlock) {
targetBinder = targetBinder.permute("self", "context", "arg*", "block");
} else {
targetBinder = targetBinder.permute("self", "context", "arg*");
}
} else {
if (desc.hasBlock) {
targetBinder = targetBinder.permute("self", "arg*", "block");
} else {
targetBinder = targetBinder.permute("self", "arg*");
}
}
if (returnFilter != null) {
targetBinder = targetBinder
.filterReturn(returnFilter);
} else if (castReturn) {
targetBinder = targetBinder
.castReturn(desc.returnClass);
}
targetBinder = targetBinder
.castArg("self", desc.getDeclaringClass());
}
if (desc.isStatic) {
target = targetBinder
.invokeStaticQuiet(LOOKUP, desc.getDeclaringClass(), javaMethodName);
} else {
target = targetBinder
.invokeVirtualQuiet(LOOKUP, javaMethodName);
}
CallConfiguration callConfig = CallConfiguration.getCallConfigByAnno(desc.anno);
if (!callConfig.isNoop()) {
target = SmartHandle
.from(target.signature(), InvocationLinker.wrapWithFraming(baseSignature, callConfig, implementationClass, rubyName, target.handle(), null));
}
if (specificArity >= 0) {
targets[specificArity] = target.handle();
} else {
targets[4] = target.handle();
}
}
if (targets[4] == null) {
// provide a variable-arity path for specific-arity target
Signature VARIABLE_ARITY_SIGNATURE = Signature
.returning(IRubyObject.class)
.appendArg("context", ThreadContext.class)
.appendArg("self", IRubyObject.class)
.appendArg("args", IRubyObject[].class)
.appendArg("block", Block.class);
// convert all specific-arity handles into varargs handles
MethodHandle[] varargsTargets = new MethodHandle[4];
for (int i = 0; i < 4; i++) {
// TODO arity error
if (targets[i] == null) continue;
if (i == 0) {
varargsTargets[i] = MethodHandles.dropArguments(targets[i], 2, IRubyObject[].class);
} else {
varargsTargets[i] = SmartBinder
.from(VARIABLE_ARITY_SIGNATURE)
.permute("context", "self", "block", "args")
.spread("arg", i)
.permute("context", "self", "arg*", "block")
.invoke(targets[i]).handle();
}
}
SmartHandle HANDLE_GETTER = SmartBinder
.from(Signature.returning(MethodHandle.class).appendArg("targets", MethodHandle[].class).appendArg("arity", int.class))
.arrayGet();
SmartHandle handleLookup = SmartBinder
.from(Signature.returning(MethodHandle.class).appendArg("args", IRubyObject[].class))
.filterReturn(HANDLE_GETTER.bindTo(varargsTargets))
.cast(int.class, Object.class)
.invokeStaticQuiet(LOOKUP, Array.class, "getLength");
SmartHandle variableCall = SmartBinder
.from(VARIABLE_ARITY_SIGNATURE)
.fold("handle", handleLookup)
.invoker();
targets[4] = variableCall.handle();
}
// TODO: tracing