package org.jruby.java.dispatch;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.jruby.Ruby;
import org.jruby.RubyBignum;
import org.jruby.RubyBoolean;
import org.jruby.RubyFixnum;
import org.jruby.RubyFloat;
import org.jruby.RubyInteger;
import org.jruby.RubyProc;
import org.jruby.RubyString;
import org.jruby.java.invokers.RubyToJavaInvoker;
import org.jruby.javasupport.JavaCallable;
import org.jruby.javasupport.JavaClass;
import org.jruby.javasupport.JavaUtil;
import org.jruby.javasupport.ParameterTypes;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.cli.Options;
import org.jruby.util.collections.IntHashMap;
import static org.jruby.util.CodegenUtils.getBoxType;
import static org.jruby.util.CodegenUtils.prettyParams;
import static org.jruby.javasupport.Java.getFunctionalInterfaceMethod;
public class CallableSelector {
private CallableSelector() { }
public static <T extends ParameterTypes> T matchingCallableArityN(Ruby runtime, CallableCache<T> cache, T[] methods, IRubyObject[] args) {
final int signatureCode = argsHashCode(args);
T method = cache.getSignature(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, args);
if (method != null) cache.putSignature(signatureCode, method);
}
return method;
}
public static <T extends ParameterTypes> T matchingCallableArityOne(Ruby runtime, CallableCache<T> cache, T[] methods, IRubyObject arg0) {
final int signatureCode = argsHashCode(arg0);
T method = cache.getSignature(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0);
if (method != null) cache.putSignature(signatureCode, method);
}
return method;
}
public static <T extends ParameterTypes> T matchingCallableArityTwo(Ruby runtime, CallableCache<T> cache, T[] methods, IRubyObject arg0, IRubyObject arg1) {
final int signatureCode = argsHashCode(arg0, arg1);
T method = cache.getSignature(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1);
if (method != null) cache.putSignature(signatureCode, method);
}
return method;
}
public static <T extends ParameterTypes> T matchingCallableArityThree(Ruby runtime, CallableCache<T> cache, T[] methods, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
final int signatureCode = argsHashCode(arg0, arg1, arg2);
T method = cache.getSignature(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1, arg2);
if (method != null) cache.putSignature(signatureCode, method);
}
return method;
}
public static <T extends ParameterTypes> T matchingCallableArityFour(Ruby runtime, CallableCache<T> cache, T[] methods, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3) {
final int signatureCode = argsHashCode(arg0, arg1, arg2, arg3);
T method = cache.getSignature(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1, arg2, arg3);
if (method != null) cache.putSignature(signatureCode, method);
}
return method;
}
public static <T extends JavaCallable> T matchingCallableArityN(Ruby runtime, RubyToJavaInvoker<T> invoker, T[] methods, IRubyObject[] args) {
final int signatureCode = argsHashCode(args);
T method = invoker.getSignature(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, args);
if (method != null) invoker.putSignature(signatureCode, method);
}
return method;
}
public static <T extends JavaCallable> T matchingCallableArityZero(Ruby runtime, RubyToJavaInvoker<T> invoker, T[] methods) {
final int signatureCode = 0;
T method = invoker.getSignature(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods);
if (method != null) invoker.putSignature(signatureCode, method);
}
return method;
}
public static <T extends JavaCallable> T matchingCallableArityOne(Ruby runtime, RubyToJavaInvoker<T> invoker, T[] methods, IRubyObject arg0) {
final int signatureCode = argsHashCode(arg0);
T method = invoker.getSignature(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0);
if (method != null) invoker.putSignature(signatureCode, method);
}
return method;
}
public static <T extends JavaCallable> T matchingCallableArityTwo(Ruby runtime, RubyToJavaInvoker<T> invoker, T[] methods, IRubyObject arg0, IRubyObject arg1) {
final int signatureCode = argsHashCode(arg0, arg1);
T method = invoker.getSignature(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1);
if (method != null) invoker.putSignature(signatureCode, method);
}
return method;
}
public static <T extends JavaCallable> T matchingCallableArityThree(Ruby runtime, RubyToJavaInvoker<T> invoker, T[] methods, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
final int signatureCode = argsHashCode(arg0, arg1, arg2);
T method = invoker.getSignature(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1, arg2);
if (method != null) invoker.putSignature(signatureCode, method);
}
return method;
}
public static <T extends JavaCallable> T matchingCallableArityFour(Ruby runtime, RubyToJavaInvoker<T> invoker, T[] methods, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3) {
final int signatureCode = argsHashCode(arg0, arg1, arg2, arg3);
T method = invoker.getSignature(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1, arg2, arg3);
if (method != null) invoker.putSignature(signatureCode, method);
}
return method;
}
private static <T extends ParameterTypes> T findMatchingCallableForArgs(final Ruby runtime,
final T[] methods, final IRubyObject... args) {
T method = null;
final List<T> candidates = findCallableCandidates(methods, args);
final int size = candidates.size();
if ( size > 0 ) {
if ( size == 1 ) method = candidates.get(0);
else {
T mostSpecific = candidates.get(0);
Class<?>[] msTypes = mostSpecific.getParameterTypes();
boolean ambiguous = false;
final IRubyObject lastArg = args.length > 0 ? args[ args.length - 1 ] : null;
int mostSpecificArity = Integer.MIN_VALUE;
final int procArity;
if ( lastArg instanceof RubyProc ) {
final Method implMethod; final int last = msTypes.length - 1;
if ( last >= 0 && msTypes[last].isInterface() &&
( implMethod = getFunctionalInterfaceMethod(msTypes[last]) ) != null ) {
mostSpecificArity = implMethod.getParameterTypes().length;
}
procArity = procArityValue(lastArg);
}
else {
procArity = Integer.MIN_VALUE;
}
for ( int c = 1; c < size; c++ ) {
final T candidate = candidates.get(c);
final Class<?>[] cTypes = candidate.getParameterTypes();
final boolean lastArgProc = procArity != Integer.MIN_VALUE;
final Boolean moreSpecific = moreSpecificTypes(msTypes, cTypes, lastArgProc);
if ( moreSpecific == Boolean.TRUE ) {
mostSpecific = candidate; msTypes = cTypes;
ambiguous = false; continue ;
}
else {
for ( int i = 0; i < msTypes.length; i++ ) {
final Class<?> msType = msTypes[i], cType = cTypes[i];
if ( msType == cType || msType.isAssignableFrom(cType) || cType.isAssignableFrom(msType) ) {
ambiguous = false; break;
}
else if ( cType.isPrimitive() && msType.isAssignableFrom(getBoxType(cType)) ) {
ambiguous = false; break;
}
else {
ambiguous = true;
}
}
}
if ( lastArgProc ) {
final Method implMethod; final int last = cTypes.length - 1;
if ( last >= 0 && cTypes[last].isInterface() && ( implMethod = getFunctionalInterfaceMethod(cTypes[last]) ) != null ) {
final int methodArity = implMethod.getParameterTypes().length;
if ( methodArity == procArity ) {
if ( mostSpecificArity == methodArity ) ambiguous = true;
else {
mostSpecific = candidate; msTypes = cTypes;
mostSpecificArity = procArity; ambiguous = false;
}
continue;
}
else if ( mostSpecificArity != procArity ) {
if ( methodArity < procArity ) {
if ( mostSpecificArity == methodArity ) ambiguous = true;
else if ( mostSpecificArity < methodArity ) {
mostSpecific = candidate; msTypes = cTypes;
mostSpecificArity = methodArity; ambiguous = false;
}
continue;
}
else if ( procArity < 0 && methodArity >= -(procArity + 1) ) {
if ( mostSpecificArity == methodArity ) ambiguous = true;
else {
final int msa = mostSpecificArity + procArity;
final int ma = methodArity + procArity;
if ( ( msa < 0 && ma < 0 && msa < ma ) ||
( msa >= 0 && ma >= 0 && msa > ma ) ||
( msa > ma ) ) {
mostSpecific = candidate; msTypes = cTypes;
mostSpecificArity = methodArity;
}
ambiguous = false;
}
continue;
}
}
else {
ambiguous = false;
}
}
}
if ( ambiguous ) {
int msPref = 0, cPref = 0;
for ( int i = 0; i < msTypes.length; i++ ) {
final Class<?> msType = msTypes[i], cType = cTypes[i];
msPref += calcTypePreference(msType, args[i]);
cPref += calcTypePreference(cType, args[i]);
}
if ( msPref > cPref ) ambiguous = false;
}
}
method = mostSpecific;
if ( ambiguous ) {
if (Options.JI_AMBIGUOUS_CALLS_DEBUG.load()) {
runtime.newRuntimeError(
"multiple Java methods found, dumping backtrace and choosing "
+ ((Member) ((JavaCallable) method).accessibleObject()).getName()
+ prettyParams(msTypes)
).printStackTrace(runtime.getErr());
} else {
runtime.getWarnings().warn(
"multiple Java methods found, use -X" + Options.JI_AMBIGUOUS_CALLS_DEBUG.propertyName() + " for backtrace. Choosing "
+ ((Member) ((JavaCallable) method).accessibleObject()).getName()
+ prettyParams(msTypes));
}
}
}
}
if (method == null) {
method = findMatchingCallableForArgsFallback(runtime, methods, args);
}
return method;
}
private static Boolean moreSpecificTypes(final Class[] msTypes, final Class[] cTypes,
final boolean lastArgProc) {
final int last = msTypes.length - 1;
int moreSpecific = 0; Class<?> msType, cType;
for ( int i = 0; i < last; i++ ) {
msType = msTypes[i]; cType = cTypes[i];
if ( msType == cType ) ;
else if ( msType.isAssignableFrom(cType) ) {
moreSpecific++;
}
else if ( cType.isAssignableFrom(msType) ) {
moreSpecific--;
}
}
if ( last >= 0 ) {
msType = msTypes[last]; cType = cTypes[last];
if ( lastArgProc ) {
if ( cType.isAssignableFrom(RubyProc.class) ) {
if ( ! msType.isAssignableFrom(RubyProc.class) ) moreSpecific++;
}
else {
return null;
}
}
else {
if ( msType == cType ) ;
else if ( msType.isAssignableFrom(cType) ) {
moreSpecific++;
}
else if ( cType.isAssignableFrom(msType) ) {
moreSpecific--;
}
}
}
return moreSpecific > 0 ? Boolean.TRUE : Boolean.FALSE;
}
private static <T extends ParameterTypes> T findMatchingCallableForArgsFallback(final Ruby runtime,
final T[] methods, final IRubyObject... args) {
T method = findCallable(methods, Exact, args);
if (method == null) {
method = findCallable(methods, AssignableAndPrimitivable, args);
if (method == null) {
method = findCallable(methods, AssignableOrDuckable, args);
if (method == null) {
method = findCallable(methods, AssignableOrDuckable, args);
if (method == null) {
method = findCallable(methods, AssignableAndPrimitivableWithVarargs, args);
}
}
}
}
return method;
}
private static <T extends ParameterTypes> T findCallable(T[] callables, CallableAcceptor acceptor, IRubyObject[] args) {
T bestCallable = null;
int bestScore = -1;
for ( int i = 0; i < callables.length; i++ ) {
final T callable = callables[i];
if ( acceptor.accept(callable, args) ) {
int currentScore = calcExactnessScore(callable, args);
if (currentScore > bestScore) {
bestCallable = callable; bestScore = currentScore;
}
}
}
return bestCallable;
}
@SuppressWarnings("unchecked")
private static <T extends ParameterTypes> List<T> findCallableCandidates(final T[] callables,
final IRubyObject[] args) {
for ( int c = 0; c < callables.length; c++ ) {
final T callable = callables[c];
if ( exactMatch(callable, args ) ) return Collections.singletonList(callable);
}
final ArrayList<T> retained = new ArrayList<T>(callables.length);
ParameterTypes[] incoming = callables.clone();
for ( int i = 0; i < args.length; i++ ) {
retained.clear();
for ( int c = 0; c < incoming.length; c++ ) {
ParameterTypes callable = incoming[c];
if ( callable == null ) continue;
Class[] types = callable.getParameterTypes();
if ( PRIMITIVABLE.match( types[i], args[i] ) ) {
retained.add((T) callable);
incoming[c] = null;
}
}
for ( int c = 0; c < incoming.length; c++ ) {
ParameterTypes callable = incoming[c];
if ( callable == null ) continue;
Class[] types = callable.getParameterTypes();
if ( ASSIGNABLE.match( types[i], args[i] ) ) {
retained.add((T) callable);
incoming[c] = null;
}
}
if ( retained.isEmpty() ) {
for ( int c = 0; c < incoming.length; c++ ) {
ParameterTypes callable = incoming[c];
if ( callable == null ) continue;
Class[] types = callable.getParameterTypes();
if ( DUCKABLE.match( types[i], args[i] ) ) {
retained.add((T) callable);
}
}
}
incoming = retained.toArray( new ParameterTypes[retained.size()] );
}
int j = 0; for ( int i = 0; i < retained.size(); i++ ) {
T callable = retained.get(i);
if ( callable.isVarArgs() ) {
if ( callable.getArity() > args.length - 1 ) continue;
}
else {
if ( callable.getArity() != args.length ) continue;
}
retained.set(j++, callable);
}
return j < retained.size() ? retained.subList(0, j) : retained;
}
private static int calcExactnessScore(final ParameterTypes callable, final IRubyObject[] args) {
final Class[] types = callable.getParameterTypes();
int count = 0;
if ( callable.isVarArgs() ) {
final int nonVarargs = types.length - 1;
count += 1;
for (int i = 0; i < nonVarargs && i < args.length; i++) {
if ( types[i] == getJavaClass(args[i]) ) count++;
}
}
else {
for (int i = 0; i < args.length; i++) {
if ( types[i] == getJavaClass(args[i]) ) count++;
}
}
return count;
}
private static interface CallableAcceptor {
public boolean accept(ParameterTypes types, IRubyObject[] args);
}
private static final CallableAcceptor Exact = new CallableAcceptor() {
public boolean accept(ParameterTypes types, IRubyObject[] args) {
return exactMatch(types, args);
}
};
private static final CallableAcceptor AssignableAndPrimitivable = new CallableAcceptor() {
public boolean accept(ParameterTypes types, IRubyObject[] args) {
return assignableAndPrimitivable(types, args);
}
};
private static final CallableAcceptor AssignableOrDuckable = new CallableAcceptor() {
public boolean accept(ParameterTypes types, IRubyObject[] args) {
return assignableOrDuckable(types, args);
}
};
private static final CallableAcceptor AssignableAndPrimitivableWithVarargs = new CallableAcceptor() {
public boolean accept(ParameterTypes types, IRubyObject[] args) {
return assignableAndPrimitivableWithVarargs(types, args);
}
};
private static interface Matcher {
public boolean match(final Class<?> type, final IRubyObject arg);
}
private static final Matcher EXACT = new Matcher() {
public boolean match(final Class<?> type, final IRubyObject arg) {
final Class<?> argClass = getJavaClass(arg);
return type == argClass || (type.isPrimitive() && getBoxType(type) == argClass);
}
@Override public String toString() { return "EXACT"; }
};
private static final Matcher ASSIGNABLE = new Matcher() {
public boolean match(Class type, IRubyObject arg) {
return assignable(type, arg);
}
@Override public String toString() { return "ASSIGNABLE"; }
};
private static final Matcher PRIMITIVABLE = new Matcher() {
public boolean match(Class type, IRubyObject arg) {
return primitivable(type, arg);
}
@Override public String toString() { return "PRIMITIVABLE"; }
};
private static final Matcher DUCKABLE = new Matcher() {
public boolean match(Class type, IRubyObject arg) {
return duckable(type, arg);
}
@Override public String toString() { return "DUCKABLE"; }
};
private static boolean exactMatch(ParameterTypes paramTypes, IRubyObject... args) {
final Class[] types = paramTypes.getParameterTypes();
if (args.length != types.length) return false;
for (int i = 0; i < types.length; i++) {
if (!EXACT.match(types[i], args[i])) {
return false;
}
}
return true;
}
private static boolean assignableAndPrimitivable(ParameterTypes paramTypes, IRubyObject... args) {
final Class[] types = paramTypes.getParameterTypes();
if (args.length != types.length) return false;
for (int i = 0; i < types.length; i++) {
if (!(ASSIGNABLE.match(types[i], args[i]) && PRIMITIVABLE.match(types[i], args[i]))) {
return false;
}
}
return true;
}
private static boolean assignableOrDuckable(ParameterTypes paramTypes, IRubyObject... args) {
final Class[] types = paramTypes.getParameterTypes();
if (args.length != types.length) return false;
for (int i = 0; i < types.length; i++) {
if (!(ASSIGNABLE.match(types[i], args[i]) || DUCKABLE.match(types[i], args[i]))) {
return false;
}
}
return true;
}
private static boolean assignableAndPrimitivableWithVarargs(ParameterTypes paramTypes, IRubyObject... args) {
if ( ! paramTypes.isVarArgs() ) return false;
final Class[] types = paramTypes.getParameterTypes();
if ( args.length == 0 ) return types.length <= 1;
final int last = types.length - 1;
if ( args.length < last ) return false;
for ( int i = 0; i < last; i++ ) {
if (!(ASSIGNABLE.match(types[i], args[i]) || PRIMITIVABLE.match(types[i], args[i]))) {
return false;
}
}
final Class varArgType = types[last].getComponentType();
for ( int i = last; i < args.length; i++ ) {
if (!(ASSIGNABLE.match(varArgType, args[i]) || PRIMITIVABLE.match(varArgType, args[i]))) {
return false;
}
}
return true;
}
private static boolean assignable(Class<?> type, final IRubyObject arg) {
return JavaClass.assignable(type, getJavaClass(arg)) ||
( arg != null && type.isAssignableFrom(arg.getClass()) );
}
private static boolean primitivable(final Class<?> type, final IRubyObject arg) {
final Class<?> argClass = getJavaClass(arg);
if (type.isPrimitive()) {
if (type == Integer.TYPE || type == Long.TYPE || type == Short.TYPE || type == Character.TYPE) {
return argClass == long.class ||
argClass == byte.class ||
argClass == short.class ||
argClass == char.class ||
argClass == int.class ||
argClass == Long.class ||
argClass == Byte.class ||
argClass == Short.class ||
argClass == Character.class ||
argClass == Integer.class;
}
if (type == Float.TYPE || type == Double.TYPE) {
return argClass == double.class ||
argClass == float.class ||
argClass == Float.class ||
argClass == Double.class;
}
if (type == Boolean.TYPE) {
return argClass == boolean.class ||
argClass == Boolean.class;
}
}
return false;
}
private static int calcTypePreference(Class<?> type, final IRubyObject arg) {
final boolean primitive = type.isPrimitive();
if ( primitive ) type = getBoxType(type);
if ( Number.class.isAssignableFrom(type) || Character.class == type ) {
if ( arg instanceof RubyFixnum ) {
if ( type == Long.class ) return 10;
if ( type == Integer.class ) return 8;
if ( type == BigInteger.class ) return 7;
if ( type == Short.class ) return 6;
if ( type == Byte.class ) return 4;
if ( type == Float.class ) return 3;
if ( type == Double.class ) return 2;
return 1;
}
if ( arg instanceof RubyBignum ) {
if ( type == BigInteger.class ) return 10;
if ( type == Long.class ) return 4;
if ( type == Double.class ) return 6;
if ( type == Float.class ) return 5;
return 1;
}
if ( arg instanceof RubyInteger ) {
if ( type == Long.class ) return 10;
if ( type == Integer.class ) return 8;
if ( type == Float.class ) return 3;
if ( type == Double.class ) return 2;
return 1;
}
if ( arg instanceof RubyFloat ) {
if ( type == Double.class ) return 10;
if ( type == Float.class ) return 8;
if ( type == BigDecimal.class ) return 6;
if ( type == Long.class ) return 4;
if ( type == Integer.class ) return 3;
if ( type == Short.class ) return 2;
return 1;
}
}
else if ( arg instanceof RubyString ) {
if ( type == String.class ) return 10;
if ( type == byte[].class ) return 8;
if ( CharSequence.class.isAssignableFrom(type) ) return 7;
if ( type == Character.class ) return 1;
}
else if ( arg instanceof RubyBoolean ) {
if ( type == Boolean.class ) return 10;
}
return 0;
}
private static boolean duckable(final Class<?> type, final IRubyObject arg) {
return JavaUtil.isDuckTypeConvertable(getJavaClass(arg), type);
}
private static int argsHashCode(IRubyObject a0) {
return 31 + javaClassOrProcHashCode(a0);
}
private static int argsHashCode(IRubyObject a0, IRubyObject a1) {
return 17 * ( 31 + javaClassHashCode(a0) ) +
javaClassOrProcHashCode(a1);
}
private static int argsHashCode(IRubyObject a0, IRubyObject a1, IRubyObject a2) {
return 17 * ( 17 * ( 31 + javaClassHashCode(a0) ) + javaClassHashCode(a1) ) +
javaClassOrProcHashCode(a2);
}
private static int argsHashCode(IRubyObject a0, IRubyObject a1, IRubyObject a2, IRubyObject a3) {
return 17 * ( 17 * ( 17 * ( 31 + javaClassHashCode(a0) ) + javaClassHashCode(a1) ) + javaClassHashCode(a2) ) +
javaClassOrProcHashCode(a3);
}
private static int argsHashCode(final IRubyObject[] args) {
final int last = args.length - 1;
if ( last == -1 ) return 0;
int result = 31;
for ( int i = 0; i < last; i++ ) {
result = 17 * ( result + javaClassHashCode( args[i] ) );
}
return result + javaClassOrProcHashCode( args[last] );
}
private static int javaClassHashCode(final IRubyObject arg) {
return arg.getJavaClass().hashCode();
}
private static int javaClassOrProcHashCode(final IRubyObject arg) {
final Class<?> javaClass = arg.getJavaClass();
return javaClass == RubyProc.class ? 11 * procArityValue(arg) : javaClass.hashCode();
}
private static int procArityValue(final IRubyObject proc) {
return ((RubyProc) proc).getBlock().getSignature().arityValue();
}
private static Class<?> getJavaClass(final IRubyObject arg) {
return arg != null ? arg.getJavaClass() : void.class;
}
public static interface CallableCache<T extends ParameterTypes> {
T getSignature(int signatureCode) ;
void putSignature(int signatureCode, T callable) ;
}
@Deprecated
public static <T extends ParameterTypes> IntHashMap<T> newCallableCache() {
return new IntHashMap<T>(8);
}
@SuppressWarnings("unchecked")
@Deprecated
public static ParameterTypes matchingCallableArityN(Ruby runtime, Map cache, ParameterTypes[] methods, IRubyObject[] args) {
final int signatureCode = argsHashCode(args);
ParameterTypes method = (ParameterTypes) cache.get(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, args);
if (method != null) cache.put(signatureCode, method);
}
return method;
}
@SuppressWarnings("unchecked")
@Deprecated
public static JavaCallable matchingCallableArityN(Ruby runtime, Map cache, JavaCallable[] methods, IRubyObject[] args) {
final int signatureCode = argsHashCode(args);
JavaCallable method = (JavaCallable) cache.get(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, args);
if (method != null) cache.put(signatureCode, method);
}
return method;
}
@Deprecated
public static JavaCallable matchingCallableArityOne(Ruby runtime, Map cache, JavaCallable[] methods, IRubyObject arg0) {
final int signatureCode = argsHashCode(arg0);
JavaCallable method = (JavaCallable) cache.get(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0);
if (method != null) cache.put(signatureCode, method);
}
return method;
}
@Deprecated
public static JavaCallable matchingCallableArityTwo(Ruby runtime, Map cache, JavaCallable[] methods, IRubyObject arg0, IRubyObject arg1) {
final int signatureCode = argsHashCode(arg0, arg1);
JavaCallable method = (JavaCallable) cache.get(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1);
if (method != null) cache.put(signatureCode, method);
}
return method;
}
@Deprecated
public static JavaCallable matchingCallableArityThree(Ruby runtime, Map cache, JavaCallable[] methods, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
final int signatureCode = argsHashCode(arg0, arg1, arg2);
JavaCallable method = (JavaCallable) cache.get(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1, arg2);
if (method != null) cache.put(signatureCode, method);
}
return method;
}
@Deprecated
public static JavaCallable matchingCallableArityFour(Ruby runtime, Map cache, JavaCallable[] methods, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3) {
final int signatureCode = argsHashCode(arg0, arg1, arg2, arg3);
JavaCallable method = (JavaCallable) cache.get(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1, arg2, arg3);
if (method != null) cache.put(signatureCode, method);
}
return method;
}
}