From 2c857d3cb37a02fea461b1c52ade48f542221ee6 Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Mon, 26 May 2008 19:21:15 +0000 Subject: [PATCH] Streamline delegation chain for table event processing. --- src/core/org/luaj/lib/PackageLib.java | 26 ++-- src/core/org/luaj/lib/StringLib.java | 2 +- src/core/org/luaj/vm/LFunction.java | 26 ++++ src/core/org/luaj/vm/LTable.java | 34 +++-- src/core/org/luaj/vm/LValue.java | 41 ++---- src/core/org/luaj/vm/LuaState.java | 180 +++++++++++++++++--------- 6 files changed, 195 insertions(+), 114 deletions(-) diff --git a/src/core/org/luaj/lib/PackageLib.java b/src/core/org/luaj/lib/PackageLib.java index 7cf165cf..7ace4c0d 100644 --- a/src/core/org/luaj/lib/PackageLib.java +++ b/src/core/org/luaj/lib/PackageLib.java @@ -188,14 +188,14 @@ public class PackageLib extends LFunction { module = findtable( vm._G, modname ); if ( module == null ) vm.error( "name conflict for module '"+modname+"'" ); - LOADED.luaSetTable(vm, LOADED, modname, module); + LOADED.luaSetTable(vm, modname, module); } else { module = (LTable) value; } /* check whether table already has a _NAME field */ - LValue name = module.luaGetTable(vm, module, _NAME); + LValue name = module.luaGetTable(vm, _NAME); if ( name.isNil() ) { modinit( vm, module, modname ); } @@ -244,10 +244,10 @@ public class PackageLib extends LFunction { private static void modinit(LuaState vm, LTable module, LString modname) { /* module._M = module */ - module.luaSetTable(vm, module, _M, module); + module.luaSetTable(vm, _M, module); int e = modname.lastIndexOf(_DOT); - module.luaSetTable(vm, module, _NAME, modname ); - module.luaSetTable(vm, module, _PACKAGE, (e<0? _EMPTY: modname.substring(0,e+1)) ); + module.luaSetTable(vm, _NAME, modname ); + module.luaSetTable(vm, _PACKAGE, (e<0? _EMPTY: modname.substring(0,e+1)) ); } /** @@ -289,7 +289,7 @@ public class PackageLib extends LFunction { vm.resettop(); /* else must load it; iterate over available loaders */ - LValue val = pckg.luaGetTable(vm, pckg, _LOADERS); + LValue val = pckg.luaGetTable(vm, _LOADERS); if ( ! val.isTable() ) vm.error( "'package.loaders' must be a table" ); vm.pushlvalue(val); @@ -310,14 +310,14 @@ public class PackageLib extends LFunction { } // load the module using the loader - LOADED.luaSetTable(vm, LOADED, name, _SENTINEL); + LOADED.luaSetTable(vm, name, _SENTINEL); vm.pushlstring( name ); /* pass name as argument to module */ vm.call( 1, 1 ); /* run loaded module */ if ( ! vm.isnil(-1) ) /* non-nil return? */ - LOADED.luaSetTable(vm, LOADED, name, vm.topointer(-1) ); /* _LOADED[name] = returned value */ - LValue result = LOADED.luaGetTable(vm, LOADED, name); + LOADED.luaSetTable(vm, name, vm.topointer(-1) ); /* _LOADED[name] = returned value */ + LValue result = LOADED.luaGetTable(vm, name); if ( result == _SENTINEL ) { /* module did not set a value? */ - LOADED.luaSetTable(vm, LOADED, name, result=LBoolean.TRUE ); /* _LOADED[name] = true */ + LOADED.luaSetTable(vm, name, result=LBoolean.TRUE ); /* _LOADED[name] = true */ } vm.resettop(); vm.pushlvalue(result); @@ -330,10 +330,10 @@ public class PackageLib extends LFunction { private void loader_preload( LuaState vm ) { LString name = vm.tolstring(2); - LValue preload = pckg.luaGetTable(vm, pckg, _PRELOAD); + LValue preload = pckg.luaGetTable(vm, _PRELOAD); if ( ! preload.isTable() ) vm.error("package.preload '"+name+"' must be a table"); - LValue val = preload.luaGetTable(vm, preload, name); + LValue val = preload.luaGetTable(vm, name); if ( val.isNil() ) vm.pushstring("\n\tno field package.preload['"+name+"']"); vm.resettop(); @@ -371,7 +371,7 @@ public class PackageLib extends LFunction { private InputStream findfile(LuaState vm, String name, LString pname) { Platform p = Platform.getInstance(); - LValue pkg = pckg.luaGetTable(vm, pckg, pname); + LValue pkg = pckg.luaGetTable(vm, pname); if ( ! pkg.isString() ) vm.error("package."+pname+" must be a string"); String path = pkg.toJavaString(); diff --git a/src/core/org/luaj/lib/StringLib.java b/src/core/org/luaj/lib/StringLib.java index 2f0ec521..c4b711a0 100644 --- a/src/core/org/luaj/lib/StringLib.java +++ b/src/core/org/luaj/lib/StringLib.java @@ -667,7 +667,7 @@ public class StringLib extends LFunction { push_onecapture( 0, soffset, end ); LValue k = vm.topointer( -1 ); vm.pop( 1 ); - vm.pushlvalue( ((LTable) repl).luaGetTable( vm, repl, k ) ); + vm.pushlvalue( ((LTable) repl).luaGetTable( vm, k ) ); } else { vm.error( "string/function/table expected" ); return; diff --git a/src/core/org/luaj/vm/LFunction.java b/src/core/org/luaj/vm/LFunction.java index f6492d23..e2ba54f3 100644 --- a/src/core/org/luaj/vm/LFunction.java +++ b/src/core/org/luaj/vm/LFunction.java @@ -65,5 +65,31 @@ public class LFunction extends LValue { public int invoke( LuaState lua ) { return 0; } + + /** + * Process lua tag method __index when it points to a function. + * Default method calls the function using the vm. + * + * @param vm + * @param table + * @param key + * @return + */ + public LValue __index(LuaState vm, LValue table, LValue key) { + return vm.call(this, table, key); + } + + /** + * Process lua tag method __newindex when it points to a function + * Default method calls the function using the vm. + * + * @param vm + * @param table + * @param key + * @param val + */ + public void __newindex(LuaState vm, LValue table, LValue key, LValue val) { + vm.call(this, table, key, val); + } } diff --git a/src/core/org/luaj/vm/LTable.java b/src/core/org/luaj/vm/LTable.java index 2bf99d24..b3544ba8 100644 --- a/src/core/org/luaj/vm/LTable.java +++ b/src/core/org/luaj/vm/LTable.java @@ -202,6 +202,32 @@ public class LTable extends LValue { array[key-1]: hashGet(LInteger.valueOf(key)) ); } + + /** Set a table value, including metatable processing. + * + * As an optimization for the common case, looks directly in the table first + * before delgating to the vm for metatable processing. + */ + public void luaSetTable(LuaState vm, LValue key, LValue val) { + if ( containsKey(key) || m_metatable == null || ! m_metatable.containsKey(TM_NEWINDEX) ) + put( key, val ); + else + vm.luaV_settable(this, key, val); + } + + + /** Get a table value, including metatable processing. + * + * As an optimization for the common case, looks directly in the table first + * before delgating to the vm for metatable processing. + */ + public LValue luaGetTable(LuaState vm, LValue key) { + LValue val = get(key); + return ! val.isNil() || m_metatable == null || ! m_metatable.containsKey(TM_INDEX)? + val: + vm.luaV_gettable(this, key); + } + /** Check for null, and convert to nilor leave alone */ @@ -232,14 +258,6 @@ public class LTable extends LValue { (hashKeys.length>0 && hashKeys[hashFindSlot(LInteger.valueOf(key))]!=null)); } - public LValue luaGetTable(LuaState vm, LValue table, LValue key) { - return vm.luaV_gettable(table, key); - } - - public void luaSetTable(LuaState vm, LValue table, LValue key, LValue val) { - vm.luaV_settable(table, key, val); - } - private static final int MAX_KEY = 0x3fffffff; /** diff --git a/src/core/org/luaj/vm/LValue.java b/src/core/org/luaj/vm/LValue.java index 640e0e25..9088769d 100644 --- a/src/core/org/luaj/vm/LValue.java +++ b/src/core/org/luaj/vm/LValue.java @@ -39,6 +39,8 @@ public class LValue { /** Metatable tag for setting table mode */ public static final LString TM_MODE = new LString("__mode"); + private static final int MAXTAGLOOP = 100; + protected void conversionError(String target) { throw new LuaErrorException( "bad conversion: "+luaGetTypeName()+" to "+target ); } @@ -124,40 +126,19 @@ public class LValue { return false; } - /** set a value in a table - * For non-tables, goes straight to the meta-table. - * @param vm the calling vm - * @param table the table to operate on - * @param the key to set - * @param the value to set + /** Dispatch a settable operation. + * Default method delegates back to the vm for metatable processing. */ - public void luaSetTable(LuaState vm, LValue table, LValue key, LValue val) { - LTable mt = luaGetMetatable(); - if ( mt != null ) { - LValue event = mt.get( TM_NEWINDEX ); - if ( event != null && ! event.isNil() ) { - event.luaSetTable( vm, table, key, val ); - return; - } - } - indexError( vm, table ); + public void luaSetTable(LuaState vm, LValue key, LValue val) { + vm.luaV_settable(this, key, val); } - /** Get a value from a table - * @param vm the calling vm - * @param table the table from which to get the value - * @param key the key to look up - * @return TODO + + /** Dispatch a gettable operation. + * Default method delegates back to the vm for metatable processing. */ - public LValue luaGetTable(LuaState vm, LValue table, LValue key) { - LTable mt = luaGetMetatable(); - if ( mt != null ) { - LValue event = mt.get( TM_INDEX ); - if ( event != null && ! event.isNil() ) { - return event.luaGetTable( vm, table, key ); - } - } - return indexError( vm, table ); + public LValue luaGetTable(LuaState vm, LValue key) { + return vm.luaV_gettable(this, key); } /** Get the value as a LString diff --git a/src/core/org/luaj/vm/LuaState.java b/src/core/org/luaj/vm/LuaState.java index 8c4dfd8d..0a69a0e4 100644 --- a/src/core/org/luaj/vm/LuaState.java +++ b/src/core/org/luaj/vm/LuaState.java @@ -290,26 +290,28 @@ public class LuaState extends Lua { public void call( int nargs, int nreturns ) { // save stack state int oldbase = base; - - // rb is base of new call frame - int rb = this.base = top - 1 - nargs; - - // make or set up the call - this.nresults = nreturns; - if (this.stack[base].luaStackCall(this)) { - // call was set up on the stack, - // we still have to execute it - execute(); + try { + + // rb is base of new call frame + int rb = this.base = top - 1 - nargs; + + // make or set up the call + this.nresults = nreturns; + if (this.stack[base].luaStackCall(this)) { + // call was set up on the stack, + // we still have to execute it + execute(); + } + + // adjustTop only for case when call was completed + // and number of args > 0. If call completed but + // c == 0, leave top to point to end of results + if (nreturns >= 0) + luaV_adjusttop(rb + nreturns); + + } finally { + this.base = oldbase; } - - // adjustTop only for case when call was completed - // and number of args > 0. If call completed but - // c == 0, leave top to point to end of results - if (nreturns >= 0) - luaV_adjusttop(rb + nreturns); - - // restore base - this.base = oldbase; } /** @@ -554,7 +556,7 @@ public class LuaState extends Lua { b = LuaState.GETARG_Bx(i); key = k[b]; table = cl.env; - val = luaV_gettable(table, key); + val = table.luaGetTable(this, key); this.stack[base + a] = val; continue; } @@ -562,7 +564,7 @@ public class LuaState extends Lua { b = LuaState.GETARG_B(i); key = GETARG_RKC(k, i); table = this.stack[base + b]; - val = luaV_gettable(table, key); + val = table.luaGetTable(this, key); this.stack[base + a] = val; continue; } @@ -571,7 +573,7 @@ public class LuaState extends Lua { key = k[b]; val = this.stack[base + a]; table = cl.env; - luaV_settable(table, key, val); + table.luaSetTable(this, key, val); continue; } case LuaState.OP_SETUPVAL: { @@ -583,7 +585,7 @@ public class LuaState extends Lua { key = GETARG_RKB(k, i); val = GETARG_RKC(k, i); table = this.stack[base + a]; - luaV_settable(table, key, val); + table.luaSetTable(this, key, val); continue; } case LuaState.OP_NEWTABLE: { @@ -595,7 +597,7 @@ public class LuaState extends Lua { case LuaState.OP_SELF: { rkb = GETARG_RKB(k, i); rkc = GETARG_RKC(k, i); - val = luaV_gettable(rkb, rkc); + val = rkb.luaGetTable(this, rkc); this.stack[base + a] = val; this.stack[base + a + 1] = rkb; continue; @@ -903,7 +905,7 @@ public class LuaState extends Lua { error( "attempt to index ? (a "+nontable.luaGetTypeName()+" value)", 1 ); } - private LValue luaV_getmetafield(LValue t, LString tag) { + public static LValue luaV_getmetafield(LValue t, LString tag) { LTable mt = t.luaGetMetatable(); if ( mt == null ) return null; @@ -911,6 +913,7 @@ public class LuaState extends Lua { return h.isNil()? null: h; } + /** Get a key from a table using full metatable processing */ public LValue luaV_gettable(LValue table, LValue key) { LValue h=LNil.NIL,t=table; for ( int loop=0; loop */ public void getglobal(String s) { - pushlvalue( luaV_gettable(_G, new LString(s)) ); + pushlvalue( _G.luaGetTable(this, new LString(s)) ); } /** @@ -1487,7 +1463,7 @@ public class LuaState extends Lua { public void gettable(int index) { LValue t = totable(index); LValue k = poplvalue(); - pushlvalue( luaV_gettable(t, k) ); + pushlvalue( t.luaGetTable(this, k) ); } /** @@ -2101,7 +2077,7 @@ public class LuaState extends Lua { */ public void setfield(int index, LString k) { LTable t = totable(index); - luaV_settable(t, k, poplvalue()); + t.luaSetTable(this, k, poplvalue()); } /** @@ -2118,7 +2094,7 @@ public class LuaState extends Lua { * */ public void setglobal(String name) { - luaV_settable(_G, new LString(name), poplvalue()); + _G.luaSetTable(this, new LString(name), poplvalue()); } /** @@ -2158,7 +2134,7 @@ public class LuaState extends Lua { LTable t = totable(index); LValue v = poplvalue(); LValue k = poplvalue(); - luaV_settable(t, k, v); + t.luaSetTable(this, k, v); } /** @@ -2637,4 +2613,84 @@ public class LuaState extends Lua { public static void vmerror(String description) { throw new LuaErrorException( "internal error: "+description ); } + + /** + * Call a function with no arguments and one return value + * @param function + * @return + */ + public LValue call(LFunction function) { + int oldtop = top; + try { + top = base + this.calls[cc].closure.p.maxstacksize; + pushlvalue(function); + call(0,1); + return poplvalue(); + } finally { + top = oldtop; + } + } + + /** + * Call a function with one argument and one return value + * @param function + * @param arg0 + * @return + */ + public LValue call(LFunction function, LValue arg0) { + int oldtop = top; + try { + top = base + this.calls[cc].closure.p.maxstacksize; + pushlvalue(function); + pushlvalue(arg0); + call(1,1); + return poplvalue(); + } finally { + top = oldtop; + } + } + + /** + * Call a function with two arguments and one return value + * @param function + * @param arg0 + * @param arg1 + * @return + */ + public LValue call(LFunction function, LValue arg0, LValue arg1) { + int oldtop = top; + try { + top = base + this.calls[cc].closure.p.maxstacksize; + pushlvalue(function); + pushlvalue(arg0); + pushlvalue(arg1); + call(2,1); + return poplvalue(); + } finally { + top = oldtop; + } + } + + /** + * Call a function with three arguments and one return value + * @param function + * @param arg0 + * @param arg1 + * @param arg2 + * @return + */ + public LValue call(LFunction function, LValue arg0, LValue arg1, LValue arg2) { + int oldtop = top; + try { + top = base + this.calls[cc].closure.p.maxstacksize; + pushlvalue(function); + pushlvalue(arg0); + pushlvalue(arg1); + pushlvalue(arg2); + call(3,1); + return poplvalue(); + } finally { + top = oldtop; + } + } }