diff -urN lua-5.1/src/lapi.c lua-cnumber/src/lapi.c --- lua-5.1/src/lapi.c 2006年02月18日 13:31:24.312500000 -0500 +++ lua-cnumber/src/lapi.c 2006年02月18日 13:34:12.984375000 -0500 @@ -1075,3 +1075,11 @@ return name; } + +/* CNUMBER */ +LUA_API int lua_setcnumberhandler(lua_State * L, lua_Iscnumber is, lua_Getcnumber get, lua_Setcnumber set) { + L->l_G->iscnumber = is; + L->l_G->getcnumber = get; + L->l_G->setcnumber = set; + return 1; /* success */ +} diff -urN lua-5.1/src/lcode.c lua-cnumber/src/lcode.c --- lua-5.1/src/lcode.c 2006年02月18日 13:31:24.312500000 -0500 +++ lua-cnumber/src/lcode.c 2006年02月18日 13:34:12.984375000 -0500 @@ -312,6 +312,14 @@ e->k = VRELOCABLE; break; } + + /* CNUMBER */ + case VCNUMBER: { + e->u.s.info = luaK_codeABx(fs, OP_GETCNUMBER, 0, e->u.s.info); + e->k = VRELOCABLE; /* ok? */ + break; + } + case VINDEXED: { freereg(fs, e->u.s.aux); freereg(fs, e->u.s.info); @@ -481,6 +489,14 @@ luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); break; } + + /* CNUMBER */ + case VCNUMBER: { + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABx(fs, OP_SETCNUMBER, e, var->u.s.info); + break; + } + case VINDEXED: { int e = luaK_exp2RK(fs, ex); luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); diff -urN lua-5.1/src/lopcodes.c lua-cnumber/src/lopcodes.c --- lua-5.1/src/lopcodes.c 2006年02月18日 13:31:24.359375000 -0500 +++ lua-cnumber/src/lopcodes.c 2006年02月18日 13:34:13.000000000 -0500 @@ -26,6 +26,11 @@ "SETTABLE", "NEWTABLE", "SELF", + + /* CNUMBER */ + "GETCNUMBER", + "SETCNUMBER", + "ADD", "SUB", "MUL", @@ -72,6 +77,11 @@ ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ + + /* CNUMBER */ + ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_GETCNUMBER */ + ,opmode(0, 0, OpArgK, OpArgN, iABx) /* OP_SETCNUMBER */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ diff -urN lua-5.1/src/lopcodes.h lua-cnumber/src/lopcodes.h --- lua-5.1/src/lopcodes.h 2006年02月18日 13:31:24.359375000 -0500 +++ lua-cnumber/src/lopcodes.h 2006年02月18日 13:37:48.609375000 -0500 @@ -168,6 +168,10 @@ OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */ +/* CNUMBER */ +OP_GETCNUMBER,/* A Bx R(A) := CN(Bx) */ +OP_SETCNUMBER,/* A Bx CN(Bx) := R(A) */ + OP_ADD,/* A B C R(A) := RK(B) + RK(C) */ OP_SUB,/* A B C R(A) := RK(B) - RK(C) */ OP_MUL,/* A B C R(A) := RK(B) * RK(C) */ diff -urN lua-5.1/src/lparser.c lua-cnumber/src/lparser.c --- lua-5.1/src/lparser.c 2006年02月18日 13:31:24.359375000 -0500 +++ lua-cnumber/src/lparser.c 2006年02月18日 13:34:13.015625000 -0500 @@ -248,8 +248,19 @@ static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); FuncState *fs = ls->fs; - if (singlevaraux(fs, varname, var, 1) == VGLOBAL) - var->u.s.info = luaK_stringK(fs, varname); /* info points to global name */ + if (singlevaraux(fs, varname, var, 1) == VGLOBAL) { + + /* CNUMBER */ + int cnumber_id; + if (ls->L->l_G->iscnumber != NULL && ls->L->l_G->iscnumber(ls->L, getstr(varname), &cnumber_id)) { + var->k = VCNUMBER; + var->u.s.info = cnumber_id; + } + + else { + var->u.s.info = luaK_stringK(fs, varname); /* info points to global name */ + } + } } diff -urN lua-5.1/src/lparser.h lua-cnumber/src/lparser.h --- lua-5.1/src/lparser.h 2006年02月18日 13:31:24.359375000 -0500 +++ lua-cnumber/src/lparser.h 2006年02月18日 13:34:13.015625000 -0500 @@ -27,6 +27,10 @@ VLOCAL, /* info = local register */ VUPVAL, /* info = index of upvalue in `upvalues' */ VGLOBAL, /* info = index of table; aux = index of global name in `k' */ + + /* CNUMBER */ + VCNUMBER, /* info = index of variable */ + VINDEXED, /* info = table register; aux = index register (or `k') */ VJMP, /* info = instruction pc */ VRELOCABLE, /* info = instruction pc */ diff -urN lua-5.1/src/lstate.c lua-cnumber/src/lstate.c --- lua-5.1/src/lstate.c 2006年02月18日 13:31:24.375000000 -0500 +++ lua-cnumber/src/lstate.c 2006年02月18日 13:34:13.015625000 -0500 @@ -179,6 +179,12 @@ g->gcstepmul = LUAI_GCMUL; g->gcdept = 0; for (i=0; imt[i] = NULL; + + /* CNUMBER */ + g->iscnumber = NULL; + g->getcnumber = NULL; + g->setcnumber = NULL; + if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { /* memory allocation error: free partial state */ close_state(L); diff -urN lua-5.1/src/lstate.h lua-cnumber/src/lstate.h --- lua-5.1/src/lstate.h 2006年02月18日 13:31:24.375000000 -0500 +++ lua-cnumber/src/lstate.h 2006年02月18日 13:34:13.015625000 -0500 @@ -91,6 +91,12 @@ UpVal uvhead; /* head of double-linked list of all open upvalues */ struct Table *mt[NUM_TAGS]; /* metatables for basic types */ TString *tmname[TM_N]; /* array with tag-method names */ + + /* CNUMBER */ + lua_Iscnumber iscnumber; + lua_Getcnumber getcnumber; + lua_Setcnumber setcnumber; + } global_State; diff -urN lua-5.1/src/lua.h lua-cnumber/src/lua.h --- lua-5.1/src/lua.h 2006年02月18日 13:31:24.375000000 -0500 +++ lua-cnumber/src/lua.h 2006年02月18日 13:34:13.015625000 -0500 @@ -325,6 +325,19 @@ /* Functions to be called by the debuger in specific events */ typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); +/* CNUMBER */ +/* handlers for CNUMBER type */ +/* called by parser--given variable name, iff a CNUMBER, + returns 1 and sets CNUMBER ID, else returns 0. + A possible change is to pass LexState instead of lua_State. + */ +typedef int (*lua_Iscnumber) (lua_State * L, const char *varname, int *id); +/* called at runtime--sets the value of the CNUMBER with the + given ID. */ +typedef void (*lua_Setcnumber) (lua_State * L, int id, double value); +/* called at runtime--gets the value of the CNUMBER with the + given ID. */ +typedef double (*lua_Getcnumber) (lua_State * L, int id); LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar); LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); @@ -338,6 +351,9 @@ LUA_API int lua_gethookmask (lua_State *L); LUA_API int lua_gethookcount (lua_State *L); +/* CNUMBER */ +/* note: currently all must be set or all must be NULL */ +LUA_API int lua_setcnumberhandler(lua_State * L, lua_Iscnumber is, lua_Getcnumber get, lua_Setcnumber set); struct lua_Debug { int event; diff -urN lua-5.1/src/lvm.c lua-cnumber/src/lvm.c --- lua-5.1/src/lvm.c 2006年02月18日 13:31:24.390625000 -0500 +++ lua-cnumber/src/lvm.c 2006年02月18日 13:34:13.031250000 -0500 @@ -466,6 +466,18 @@ Protect(luaV_gettable(L, rb, RKC(i), ra)); continue; } + + /* CNUMBER */ + case OP_GETCNUMBER: { + setnvalue(ra, L->l_G->getcnumber(L, GETARG_Bx(i))); + continue; + } + case OP_SETCNUMBER: { + runtime_check(L, ttisnumber(ra)); + L->l_G->setcnumber(L, GETARG_Bx(i), nvalue(ra)); + continue; + } + case OP_ADD: { arith_op(luai_numadd, TM_ADD); continue; diff -urN lua-5.1/test/cnumber.c lua-cnumber/test/cnumber.c --- lua-5.1/test/cnumber.c 1969年12月31日 19:00:00.000000000 -0500 +++ lua-cnumber/test/cnumber.c 2006年02月18日 13:47:30.406250000 -0500 @@ -0,0 +1,258 @@ +/** + * Testing and benchmarking CNUMBER in Lua. + * David Manura, 2006-02 + */ + +#include "lua.h" +#include "lauxlib.h" +#include +#include +#include + +static double foo = 0.0; +static double foo2 = 0.0; +static double foo3 = 0.0; + +static lua_State * L = NULL; + + int +iscnumber(lua_State * L, const char * varname, int * id) +{ + /* printf("DEBUG:iscnumber:%s\n", (const char*)varname); */ + + if(strcmp(varname, "foo") == 0) { + *id = 1; return 1; /* yes */ + } + else if(strcmp(varname, "foo2") == 0) { + *id = 2; return 1; /* yes */ + } + else if(strcmp(varname, "foo3") == 0) { + *id = 3; return 1; /* yes */ + } + else { + return 0; // no + } +} + + double +getcnumber(lua_State *L, int id) +{ + /* printf("DEBUG:getcnumber:%d\n", (int)id); */ + + switch(id) { + case 1: { return foo; } + case 2: { return foo2; } + case 3: { return foo3; } + default: assert(0); + } + return 0; // should not occur +} + + void +setcnumber(lua_State *L, int id, double value) +{ + /* printf("DEBUG:setcnumber:%d,%f\n", (int)id, (double)value); */ + + switch(id) { + case 1: { foo = value; break; } + case 2: { foo2 = value; break; } + case 3: { foo3 = value; break; } + default: assert(0); + } +} + + static double +dostring_timed(const char * luacode) +{ + clock_t t1, t2; + double dt; + int status; + + t1 = clock(); + status = luaL_dostring(L, luacode); + t2 = clock(); + dt = (double)(t2 - t1) / (double)CLOCKS_PER_SEC; + + if(status != 0) { + printf("fail: %s\n", (const char*)lua_tostring(L, -1)); + lua_pop(L, 1); + } + + return dt; +} + + static int +get_foo_lua(lua_State * L) +{ + lua_pushnumber(L, foo); + return 1; +} + static int +set_foo_lua(lua_State * L) +{ + foo = lua_tonumber(L, -1); + return 0; +} + + static void +test_suite() +{ + L = lua_open(); + luaopen_base(L); + + /* globals and locals still work */ + dostring_timed( +"x = 2; x = x + 1\n" +"local y = 3; y = y + 1\n" +"assert(x == 3)\n" +"assert(y == 4)\n" + ); + + /* get/set CNUMBER */ + lua_setcnumberhandler(L, iscnumber, getcnumber, setcnumber); + dostring_timed( +"foo = 2; foo = foo + 1\n" +"local y = 3; y = y + 1\n" +"assert(foo == 3)\n" +"assert(y == 4)\n" + ); + assert(foo == 3); + + /* get/set CNUMBER with non-number */ + dostring_timed( +"foo = 5\n" +"assert(foo == 5)\n" +"foo = nil\n" +"assert(foo == 5)\n" +"foo = true\n" +"assert(foo == 5)\n" +"foo = 'string'\n" +"assert(foo == 5)\n" +"foo = 6\n" +"assert(foo == 6)\n" + ); + assert(foo == 6); + + lua_close(L); +} + + static void +benchmark() +{ + int n; + double t0 = 0.0; + double t1 = 0.0; + double t2 = 0.0; + double t3 = 0.0; + double t4 = 0.0; + double t5 = 0.0; + double t6 = 0.0; + + L = lua_open(); + luaopen_base(L); + + lua_setcnumberhandler(L, iscnumber, getcnumber, setcnumber); + + lua_register(L, "get_foo", get_foo_lua); + lua_register(L, "set_foo", set_foo_lua); + + /* benchmark */ + for (n = 0; n < 10; n++) { + /* empty loop */ + t0 += dostring_timed( +"for n=1,10000000 do\n" +"end\n" + ); + + /* CNUMBER */ + t1 += dostring_timed( +"foo = 0.0\n" +"for n=1,10000000 do\n" +" foo = foo + 1\n" +"end\n" +"assert(foo == 10000000, 't1')\n" + ); + + /* LOCAL */ + t2 += dostring_timed( +"local bar = 0.0\n" +"for n=1,10000000 do\n" +" bar = bar + 1\n" +"end\n" +"assert(bar == 10000000, 't2')\n" + ); + + /* GLOBAL */ + t3 += dostring_timed( +"baz = 0.0\n" +"for n=1,10000000 do\n" +" baz = baz + 1\n" +"end\n" +"assert(baz == 10000000, 't3')\n" +"baz = nil\n" + ); + + /* METATABLENUMBER */ + t4 += dostring_timed( +"local tmp\n" +"setmetatable(_G, {\n" +" __newindex = function(t,k,v) tmp = v end,\n" +" __index = function(t,k) return tmp end\n" +"})\n" +"baz = 0.0\n" +"for n=1,10000000 do\n" +" baz = baz + 1\n" +"end\n" +"assert(baz == 10000000, 't4')\n" +"setmetatable(_G, nil)\n" + ); + + /* METATABLETABLE */ + t5 += dostring_timed( +"local tmp = {}\n" +"setmetatable(_G, {\n" +" __newindex = function(t,k,v) rawset(tmp, k, v) end,\n" +" __index = function(t,k) return rawget(tmp, k) end\n" +"})\n" +"baz = 0.0\n" +"for n=1,10000000 do\n" +" baz = baz + 1\n" +"end\n" +"assert(baz == 10000000, 't5')\n" +"setmetatable(_G, nil)\n" + ); + + /* CFUNCTION */ + t6 += dostring_timed( +"set_foo(0.0)\n" +"for n=1,10000000 do\n" +" set_foo(get_foo() + 1)\n" +"end\n" +"assert(get_foo() == 10000000, 't6')\n" + ); + } + + printf("== Run Times (sec)\n"); + printf("LOOP : %f\n", (double)t0); + printf("CNUMBER : %f\n", (double)t1); + printf("LOCAL : %f\n", (double)t2); + printf("GLOBAL : %f\n", (double)t3); + printf("METATABLELOCAL : %f\n", (double)t4); + printf("METATABLETABLE : %f\n", (double)t5); + printf("CFUNCTION : %f\n", (double)t6); + + lua_close(L); +} + + int +main() +{ + printf("testing...\n"); + + test_suite(); + benchmark(); + + return 0; +} + +

AltStyle によって変換されたページ (->オリジナル) /