Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: ac6268d1c41f
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: dcb99b9c998e
Choose a head ref
  • 11 commits
  • 11 files changed
  • 1 contributor

Commits on Sep 15, 2015

  1. Copy the full SHA
    bdaa82b View commit details
  2. Copy the full SHA
    be6a2bf View commit details
  3. getName for JavaMethod

    kares committed Sep 15, 2015
    Copy the full SHA
    4e50bc7 View commit details
  4. Copy the full SHA
    41c9a22 View commit details
  5. Copy the full SHA
    bc6160b View commit details
  6. [ji] var-args Java method is a valid match even if the last parameter…

    … receives no arg
    
    `method(String, Object...)` will now be considered with a `method('foo')` call
    
    fixes #3279
    kares committed Sep 15, 2015
    Copy the full SHA
    e85df14 View commit details
  7. Copy the full SHA
    6544ac0 View commit details
  8. Copy the full SHA
    49061ca View commit details
  9. Copy the full SHA
    013e288 View commit details
  10. un-used local var assingment

    kares committed Sep 15, 2015
    Copy the full SHA
    3e1061e View commit details
  11. Copy the full SHA
    dcb99b9 View commit details
31 changes: 15 additions & 16 deletions core/src/main/java/org/jruby/java/dispatch/CallableSelector.java
Original file line number Diff line number Diff line change
@@ -529,7 +529,7 @@ public boolean match(Class type, IRubyObject arg) {
};

private static boolean exactMatch(ParameterTypes paramTypes, IRubyObject... args) {
Class[] types = paramTypes.getParameterTypes();
final Class[] types = paramTypes.getParameterTypes();

if (args.length != types.length) return false;

@@ -542,7 +542,7 @@ private static boolean exactMatch(ParameterTypes paramTypes, IRubyObject... args
}

private static boolean assignableAndPrimitivable(ParameterTypes paramTypes, IRubyObject... args) {
Class[] types = paramTypes.getParameterTypes();
final Class[] types = paramTypes.getParameterTypes();

if (args.length != types.length) return false;

@@ -555,7 +555,7 @@ private static boolean assignableAndPrimitivable(ParameterTypes paramTypes, IRub
}

private static boolean assignableOrDuckable(ParameterTypes paramTypes, IRubyObject... args) {
Class[] types = paramTypes.getParameterTypes();
final Class[] types = paramTypes.getParameterTypes();

if (args.length != types.length) return false;

@@ -568,31 +568,30 @@ private static boolean assignableOrDuckable(ParameterTypes paramTypes, IRubyObje
}

private static boolean assignableAndPrimitivableWithVarargs(ParameterTypes paramTypes, IRubyObject... args) {
// bail out if this is not a varargs method
if (!paramTypes.isVarArgs()) return false;
if ( ! paramTypes.isVarArgs() ) return false; // bail out if this is not a varargs method

Class[] types = paramTypes.getParameterTypes();

Class varArgArrayType = types[types.length - 1];
Class varArgType = varArgArrayType.getComponentType();
final Class[] types = paramTypes.getParameterTypes();

// if there's no args, we only match when there's just varargs
if ( args.length == 0 ) return types.length <= 1;

// dig out as many trailing args as will fit, ensuring they match varargs type
int nonVarargs = types.length - 1;
for (int i = args.length - 1; i >= nonVarargs; i--) {
if (!(ASSIGNABLE.match(varArgType, args[i]) || PRIMITIVABLE.match(varArgType, args[i]))) {
final int last = types.length - 1;

if ( args.length < last ) return false; // can't match - paramTypes method is not usable!
for ( int i = 0; i < last; i++ ) { // first check non-vararg argument types match
if (!(ASSIGNABLE.match(types[i], args[i]) || PRIMITIVABLE.match(types[i], args[i]))) {
return false;
}
}

// check remaining args
for (int i = 0; i < nonVarargs; i++) {
if (!(ASSIGNABLE.match(types[i], args[i]) || PRIMITIVABLE.match(types[i], args[i]))) {
final Class varArgType = types[last].getComponentType();
// dig out as many trailing args as will fit, ensuring they match varargs type
for ( int i = last; i < args.length; i++ ) {
if (!(ASSIGNABLE.match(varArgType, args[i]) || PRIMITIVABLE.match(varArgType, args[i]))) {
return false;
}
}

return true;
}

Original file line number Diff line number Diff line change
@@ -16,9 +16,7 @@
public final class ConstructorInvoker extends RubyToJavaInvoker {

public ConstructorInvoker(RubyModule host, List<Constructor> ctors) {
super(host, ctors.toArray(new Constructor[ctors.size()]));

trySetAccessible(getAccessibleObjects());
super(host, setAccessible( ctors.toArray(new Constructor[ctors.size()]) ) );
}

@Override
6 changes: 2 additions & 4 deletions core/src/main/java/org/jruby/java/invokers/MethodInvoker.java
Original file line number Diff line number Diff line change
@@ -11,13 +11,11 @@
public abstract class MethodInvoker extends RubyToJavaInvoker {

MethodInvoker(RubyModule host, List<Method> methods) {
super(host, methods.toArray(new Method[methods.size()]));
trySetAccessible(getAccessibleObjects());
super(host, setAccessible( methods.toArray(new Method[methods.size()]) ) );
}

MethodInvoker(RubyModule host, Method method) {
super(host, new Method[] { method });
trySetAccessible(getAccessibleObjects());
super(host, setAccessible(method));
}

@Override
113 changes: 82 additions & 31 deletions core/src/main/java/org/jruby/java/invokers/RubyToJavaInvoker.java
Original file line number Diff line number Diff line change
@@ -10,7 +10,6 @@
import org.jruby.Ruby;
import org.jruby.RubyModule;
import org.jruby.exceptions.RaiseException;
import org.jruby.internal.runtime.methods.CallConfiguration;
import org.jruby.internal.runtime.methods.JavaMethod;
import org.jruby.java.dispatch.CallableSelector;
import org.jruby.java.proxies.ArrayJavaProxy;
@@ -33,48 +32,73 @@ public abstract class RubyToJavaInvoker extends JavaMethod {
protected final JavaCallable javaCallable; /* null if multiple callable members */
protected final JavaCallable[][] javaCallables; /* != null if javaCallable == null */
protected final JavaCallable[] javaVarargsCallables; /* != null if any var args callables */
protected final int minVarargsArity;

// in case multiple callables (overloaded Java method - same name different args)
// for the invoker exists CallableSelector caches resolution based on args here
final IntHashMap<JavaCallable> cache;

private final Ruby runtime;
private final Member[] members;

RubyToJavaInvoker(RubyModule host, Member member) {
super(host, Visibility.PUBLIC);
this.runtime = host.getRuntime();

final JavaCallable callable;
JavaCallable[] varargsCallables = null;
int minVarArgsArity = -1;

callable = createCallable(runtime, member);
int minArity = callable.getArity();
if ( callable.isVarArgs() ) { // TODO does it need to happen?
varargsCallables = createCallableArray(callable);
minVarArgsArity = getMemberArity(member) - 1;
}

cache = NULL_CACHE; // if there's a single callable - matching (and thus the cache) won't be used

this.javaCallable = callable;
this.javaCallables = null;
this.javaVarargsCallables = varargsCallables;

setArity(minArity, minArity, minVarArgsArity);
setupNativeCall();
}

RubyToJavaInvoker(RubyModule host, Member[] members) {
super(host, Visibility.PUBLIC, CallConfiguration.FrameNoneScopeNone);
this.members = members;
super(host, Visibility.PUBLIC);
this.runtime = host.getRuntime();
// we set all Java methods to optional, since many/most have overloads
setArity(Arity.OPTIONAL);

// initialize all the callables for this method
final JavaCallable callable;
final JavaCallable[][] callables;
JavaCallable[] varargsCallables = null;
int varArgsArity = Integer.MAX_VALUE;
int minVarArgsArity = -1; int maxArity, minArity;

final int length = members.length;
if ( length == 1 ) {
callable = createCallable(runtime, members[0]);
maxArity = minArity = callable.getArity();
if ( callable.isVarArgs() ) {
varargsCallables = createCallableArray(callable);
minVarArgsArity = getMemberArity(members[0]) - 1;
}
callables = null;

cache = NULL_CACHE; // if there's a single callable - matching (and thus the cache) won't be used
}
else {
callable = null;
callable = null; maxArity = -1; minArity = Integer.MAX_VALUE;

IntHashMap<ArrayList<JavaCallable>> arityMap = new IntHashMap<ArrayList<JavaCallable>>(length, 1);

ArrayList<JavaCallable> varArgs = null; int maxArity = 0;
ArrayList<JavaCallable> varArgs = null;
for ( int i = 0; i < length; i++ ) {
final Member method = members[i];
final int currentArity = getMemberParameterTypes(method).length;
final int currentArity = getMemberArity(method);
maxArity = Math.max(currentArity, maxArity);
minArity = Math.min(currentArity, minArity);

final JavaCallable javaMethod = createCallable(runtime, method);

ArrayList<JavaCallable> methodsForArity = arityMap.get(currentArity);
if (methodsForArity == null) {
@@ -84,14 +108,22 @@ public abstract class RubyToJavaInvoker extends JavaMethod {
methodsForArity = new ArrayList<JavaCallable>(length);
arityMap.put(currentArity, methodsForArity);
}

final JavaCallable javaMethod = createCallable(runtime, method);
methodsForArity.add(javaMethod);

if ( isMemberVarArgs(method) ) {
varArgsArity = Math.min(currentArity - 1, varArgsArity);
if ( javaMethod.isVarArgs() ) {
final int usableArity = currentArity - 1;
// (String, Object...) has usable arity == 1 ... (String)
if ((methodsForArity = arityMap.get(usableArity)) == null) {
methodsForArity = new ArrayList<JavaCallable>(length);
arityMap.put(usableArity, methodsForArity);
}
methodsForArity.add(javaMethod);

if (varArgs == null) varArgs = new ArrayList<JavaCallable>(length);
varArgs.add(javaMethod);

if ( minVarArgsArity == -1 ) minVarArgsArity = Integer.MAX_VALUE;
minVarArgsArity = Math.min(usableArity, minVarArgsArity);
}
}

@@ -113,9 +145,26 @@ public abstract class RubyToJavaInvoker extends JavaMethod {
this.javaCallable = callable;
this.javaCallables = callables;
this.javaVarargsCallables = varargsCallables;
this.minVarargsArity = varArgsArity;

// if it's not overloaded, set up a NativeCall
setArity(minArity, maxArity, minVarArgsArity);
setupNativeCall();
}

private void setArity(final int minArity, final int maxArity, final int minVarArgsArity) {
if ( minVarArgsArity == -1 ) { // no var-args
if ( minArity == maxArity ) {
setArity( Arity.fixed(minArity) );
}
else { // multiple overloads
setArity( Arity.required(minArity) ); // but <= maxArity
}
}
else {
setArity( Arity.required(minVarArgsArity < minArity ? minVarArgsArity : minArity) );
}
}

final void setupNativeCall() { // if it's not overloaded, set up a NativeCall
if (javaCallable != null) {
// no constructor support yet
if (javaCallable instanceof org.jruby.javasupport.JavaMethod) {
@@ -142,14 +191,6 @@ private boolean setNativeCallIfPublic(final Method method) {
return false;
}

protected final Member[] getMembers() {
return members;
}

protected AccessibleObject[] getAccessibleObjects() {
return (AccessibleObject[]) getMembers();
}

protected abstract JavaCallable createCallable(Ruby runtime, Member member);

protected abstract JavaCallable[] createCallableArray(JavaCallable callable);
@@ -160,11 +201,12 @@ protected AccessibleObject[] getAccessibleObjects() {

protected abstract Class[] getMemberParameterTypes(Member member);

@Deprecated // no longer used!
protected abstract boolean isMemberVarArgs(Member member);

//final int getMemberArity(Member member) {
// return getMemberParameterTypes(member).length;
//}
final int getMemberArity(Member member) {
return getMemberParameterTypes(member).length;
}

public static Object[] convertArguments(final ParameterTypes method, final IRubyObject[] args) {
final Class<?>[] paramTypes = method.getParameterTypes();
@@ -213,11 +255,20 @@ static JavaProxy castJavaProxy(final IRubyObject self) {
return (JavaProxy) self;
}

static void trySetAccessible(AccessibleObject... accesibles) {
static <T extends AccessibleObject> T setAccessible(T accessible) {
if ( ! Ruby.isSecurityRestricted() ) {
try { accessible.setAccessible(true); }
catch (SecurityException e) {}
}
return accessible;
}

static <T extends AccessibleObject> T[] setAccessible(T[] accessibles) {
if ( ! Ruby.isSecurityRestricted() ) {
try { AccessibleObject.setAccessible(accesibles, true); }
catch(SecurityException e) {}
try { AccessibleObject.setAccessible(accessibles, true); }
catch (SecurityException e) {}
}
return accessibles;
}

protected JavaCallable findCallable(IRubyObject self, String name, IRubyObject[] args, final int arity) {
4 changes: 4 additions & 0 deletions core/src/main/java/org/jruby/javasupport/JavaMethod.java
Original file line number Diff line number Diff line change
@@ -526,6 +526,10 @@ private IRubyObject convertReturn(Object result) {
// return parameterTypes;
//}

public String getName() {
return method.getName();
}

@Override
public Class<?>[] getExceptionTypes() {
return method.getExceptionTypes();
Loading