Improve varargs handlnig in luajava bindings.

This commit is contained in:
James Roseborough
2010-05-22 17:47:31 +00:00
parent a65110df88
commit f146268c47
3 changed files with 58 additions and 76 deletions

View File

@@ -36,7 +36,7 @@ public class CoerceJavaToLua {
public LuaValue coerce( Object javaValue ); public LuaValue coerce( Object javaValue );
}; };
private static Map COERCIONS = new HashMap(); static final Map COERCIONS = new HashMap();
static { static {
Coercion boolCoercion = new Coercion() { Coercion boolCoercion = new Coercion() {

View File

@@ -37,8 +37,7 @@ public class CoerceLuaToJava {
public int score( int paramType ); public int score( int paramType );
}; };
private static Map COERCIONS = new HashMap(); static final Map COERCIONS = new HashMap();
private static Coercion OBJECT_COERCION;
static { static {
Coercion boolCoercion = new Coercion() { Coercion boolCoercion = new Coercion() {
@@ -232,7 +231,7 @@ public class CoerceLuaToJava {
/** Score a single parameter, including array handling */ /** Score a single parameter, including array handling */
private static int scoreParam(int paramType, Class c) { static int scoreParam(int paramType, Class c) {
if ( paramType == LuaValue.TUSERDATA && !c.isArray() ) if ( paramType == LuaValue.TUSERDATA && !c.isArray() )
return 0; return 0;
Coercion co = (Coercion) COERCIONS.get( c ); Coercion co = (Coercion) COERCIONS.get( c );
@@ -277,11 +276,23 @@ public class CoerceLuaToJava {
throw new LuaError("no coercion found for "+a.getClass()+" to "+c); throw new LuaError("no coercion found for "+a.getClass()+" to "+c);
} }
static Object[] coerceArgs(Varargs suppliedArgs, Class[] parameterTypes) { static Object[] coerceArgs(Varargs suppliedArgs, Class[] parameterTypes, boolean isvarargs) {
int nsupplied = suppliedArgs.narg();
int n = parameterTypes.length; int n = parameterTypes.length;
int nplain = Math.min(isvarargs? n-1: n, nsupplied);
Object[] args = new Object[n]; Object[] args = new Object[n];
for ( int i=0; i<n; i++ ) for ( int i=0; i<nplain; i++ )
args[i] = coerceArg( suppliedArgs.arg(i+1), parameterTypes[i] ); args[i] = coerceArg( suppliedArgs.arg(i+1), parameterTypes[i] );
if ( isvarargs ) {
int nvar = Math.max(0, nsupplied - nplain);
Class typevar = parameterTypes[n-1].getComponentType();
Object array = Array.newInstance(typevar, nvar);
for ( int index=0; index<nvar; index++ ) {
Object value = coerceArg( suppliedArgs.arg(nplain+index+1), typevar );
Array.set(array, index, value);
}
args[n-1] = array;
}
return args; return args;
} }

View File

@@ -43,8 +43,6 @@ import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaUserdata; import org.luaj.vm2.LuaUserdata;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.BaseLib;
import org.luaj.vm2.lib.OneArgFunction;
import org.luaj.vm2.lib.PackageLib; import org.luaj.vm2.lib.PackageLib;
import org.luaj.vm2.lib.ThreeArgFunction; import org.luaj.vm2.lib.ThreeArgFunction;
import org.luaj.vm2.lib.TwoArgFunction; import org.luaj.vm2.lib.TwoArgFunction;
@@ -52,14 +50,14 @@ import org.luaj.vm2.lib.VarArgFunction;
public class LuajavaLib extends VarArgFunction { public class LuajavaLib extends VarArgFunction {
private static final int INIT = 0; static final int INIT = 0;
private static final int BINDCLASS = 1; static final int BINDCLASS = 1;
private static final int NEWINSTANCE = 2; static final int NEWINSTANCE = 2;
private static final int NEW = 3; static final int NEW = 3;
private static final int CREATEPROXY = 4; static final int CREATEPROXY = 4;
private static final int LOADLIB = 5; static final int LOADLIB = 5;
private static final String[] NAMES = { static final String[] NAMES = {
"bindClass", "bindClass",
"newInstance", "newInstance",
"new", "new",
@@ -67,12 +65,17 @@ public class LuajavaLib extends VarArgFunction {
"loadLib", "loadLib",
}; };
private static final Map classMetatables = new HashMap(); static final Map classMetatables = new HashMap();
private static final int METHOD_MODIFIERS_VARARGS = 0x80; static final int METHOD_MODIFIERS_VARARGS = 0x80;
private static LuaValue LENGTH = valueOf("length"); static final LuaValue LENGTH = valueOf("length");
static final Map consCache = new HashMap();
static final Map consIndex = new HashMap();
static final Map methCache = new HashMap();
static final Map methIndex = new HashMap();
public LuajavaLib() { public LuajavaLib() {
} }
@@ -98,10 +101,11 @@ public class LuajavaLib extends VarArgFunction {
final Varargs consargs = args.subargs(2); final Varargs consargs = args.subargs(2);
final long paramssig = LuajavaLib.paramsSignatureOf( consargs ); final long paramssig = LuajavaLib.paramsSignatureOf( consargs );
final Constructor con = resolveConstructor( clazz, paramssig ); final Constructor con = resolveConstructor( clazz, paramssig );
final boolean isvarargs = ((con.getModifiers() & METHOD_MODIFIERS_VARARGS) != 0);
// coerce args, construct instance // coerce args, construct instance
Object[] cargs = CoerceLuaToJava.coerceArgs( consargs, con.getParameterTypes() ); final Object[] cargs = CoerceLuaToJava.coerceArgs( consargs, con.getParameterTypes(), isvarargs );
Object o = con.newInstance( cargs ); final Object o = con.newInstance( cargs );
// return result // return result
return toUserdata( o, clazz ); return toUserdata( o, clazz );
@@ -306,7 +310,7 @@ public class LuajavaLib extends VarArgFunction {
return LuaValue.userdataOf(instance,mt); return LuaValue.userdataOf(instance,mt);
} }
private static final class LMethod extends VarArgFunction { static final class LMethod extends VarArgFunction {
private final Class clazz; private final Class clazz;
private final String s; private final String s;
private LMethod(Class clazz, String s) { private LMethod(Class clazz, String s) {
@@ -319,14 +323,15 @@ public class LuajavaLib extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
try { try {
// find the method // find the method
Object instance = args.touserdata(1); final Object instance = args.touserdata(1);
Varargs methargs = args.subargs(2); final Varargs methargs = args.subargs(2);
long paramssig = LuajavaLib.paramsSignatureOf(methargs); final long paramssig = LuajavaLib.paramsSignatureOf(methargs);
Method meth = resolveMethod( clazz, s, paramssig ); final Method meth = resolveMethod( clazz, s, paramssig );
final boolean isvarargs = ((meth.getModifiers() & METHOD_MODIFIERS_VARARGS) != 0);
// coerce the arguments // coerce the arguments
Object[] margs = CoerceLuaToJava.coerceArgs( methargs, meth.getParameterTypes() ); final Object[] margs = CoerceLuaToJava.coerceArgs( methargs, meth.getParameterTypes(), isvarargs );
Object result = meth.invoke( instance, margs ); final Object result = meth.invoke( instance, margs );
// coerce the result // coerce the result
return CoerceJavaToLua.coerce(result); return CoerceJavaToLua.coerce(result);
@@ -338,13 +343,7 @@ public class LuajavaLib extends VarArgFunction {
} }
} }
private static Map consCache = static Constructor resolveConstructor(Class clazz, long paramssig ) {
new HashMap();
private static Map consIndex =
new HashMap();
private static Constructor resolveConstructor(Class clazz, long paramssig ) {
// get the cache // get the cache
Map cache = (Map) consCache.get( clazz ); Map cache = (Map) consCache.get( clazz );
@@ -357,31 +356,18 @@ public class LuajavaLib extends VarArgFunction {
return c; return c;
// get index // get index
Map index = (Map) consIndex.get( clazz ); Constructor[] cons = (Constructor[]) consIndex.get( clazz );
if ( index == null ) { if ( cons == null ) {
consIndex.put( clazz, index = new HashMap() ); consIndex.put( clazz, cons = clazz.getConstructors() );
Constructor[] cons = clazz.getConstructors(); if ( cons == null )
for ( int i=0; i<cons.length; i++ ) { throw new IllegalArgumentException("no public constructors");
Constructor con = cons[i];
Integer n = new Integer( con.getParameterTypes().length );
List list = (List) index.get(n);
if ( list == null )
index.put( n, list = new ArrayList() );
list.add( con );
}
} }
// figure out best list of arguments == supplied args
Integer n = new Integer( LuajavaLib.paramsCountFromSig(paramssig) );
List list = (List) index.get(n);
if ( list == null )
throw new IllegalArgumentException("no constructor with "+n+" args");
// find constructor with best score // find constructor with best score
int bests = Integer.MAX_VALUE; int bests = Integer.MAX_VALUE;
int besti = 0; int besti = 0;
for ( int i=0, size=list.size(); i<size; i++ ) { for ( int i=0, size=cons.length; i<size; i++ ) {
Constructor con = (Constructor) list.get(i); Constructor con = cons[i];
int paramType = LuajavaLib.paramTypeFromSig(paramssig, 0); int paramType = LuajavaLib.paramTypeFromSig(paramssig, 0);
int s = CoerceLuaToJava.scoreParamTypes(paramType, con.getParameterTypes()); int s = CoerceLuaToJava.scoreParamTypes(paramType, con.getParameterTypes());
if ( s < bests ) { if ( s < bests ) {
@@ -391,19 +377,12 @@ public class LuajavaLib extends VarArgFunction {
} }
// put into cache // put into cache
c = (Constructor) list.get(besti); c = cons[besti];
cache.put( paramssig, c ); cache.put( paramssig, c );
return c; return c;
} }
private static Map methCache = static Method resolveMethod(Class clazz, String methodName, long paramssig ) {
new HashMap();
private static Map methIndex =
new HashMap();
private static Method resolveMethod(Class clazz, String methodName, long paramssig ) {
// get the cache // get the cache
Map nameCache = (Map) methCache.get( clazz ); Map nameCache = (Map) methCache.get( clazz );
@@ -426,27 +405,19 @@ public class LuajavaLib extends VarArgFunction {
for ( int i=0; i<meths.length; i++ ) { for ( int i=0; i<meths.length; i++ ) {
Method meth = meths[i]; Method meth = meths[i];
String s = meth.getName(); String s = meth.getName();
Integer n = new Integer(meth.getParameterTypes().length); List list = (List) index.get(s);
Map map = (Map) index.get(s);
if ( map == null )
index.put( s, map = new HashMap() );
List list = (List) map.get(n);
if ( list == null ) if ( list == null )
map.put( n, list = new ArrayList() ); index.put( s, list = new ArrayList() );
list.add( meth ); list.add( meth );
} }
} }
// figure out best list of arguments == supplied args // figure out best list of arguments == supplied args
Map map = (Map) index.get(methodName); List list = (List) index.get(methodName);
if ( map == null )
throw new IllegalArgumentException("no method named '"+methodName+"'");
Integer n = new Integer( LuajavaLib.paramsCountFromSig( paramssig ) );
List list = (List) map.get(n);
if ( list == null ) if ( list == null )
throw new IllegalArgumentException("no method named '"+methodName+"' with "+n+" args"); throw new IllegalArgumentException("no method named '"+methodName+"'");
// find constructor with best score // find method with best score
int bests = Integer.MAX_VALUE; int bests = Integer.MAX_VALUE;
int besti = 0; int besti = 0;
for ( int i=0, size=list.size(); i<size; i++ ) { for ( int i=0, size=list.size(); i<size; i++ ) {