From 3377b95704e611a288791fee6a7bc59c5ecebf2d Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Mon, 28 Jan 2013 19:44:43 +0100 Subject: * More detailed DEBUG_SPEW logs * A bit of code cosmetics --- CHANGES | 4 + src/keeper.c | 43 +++-- src/lanes.c | 151 +++++++++------ src/lanes.lua | 2 +- src/tools.c | 577 ++++++++++++++++++++++++++++++++-------------------------- src/tools.h | 17 +- 6 files changed, 456 insertions(+), 338 deletions(-) diff --git a/CHANGES b/CHANGES index fc29440..66b5c23 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,9 @@ CHANGES: +CHANGE 57: BGe 28-Jan-13 + * More detailed DEBUG_SPEW logs + * A bit of code cosmetics + CHANGE 56: BGe 25-Jan-13 * version 3.4.4 * bugfix: take into account the fact that "coroutine" is no longer part of base library in Lua 5.2 diff --git a/src/keeper.c b/src/keeper.c index 516fe85..7485110 100644 --- a/src/keeper.c +++ b/src/keeper.c @@ -163,7 +163,7 @@ static void* const fifos_key = (void*) prepare_fifo_access; static void push_table( lua_State* L, int idx) { STACK_GROW( L, 4); - STACK_CHECK( L) + STACK_CHECK( L); idx = lua_absindex( L, idx); lua_pushlightuserdata( L, fifos_key); // ud fifos_key lua_rawget( L, LUA_REGISTRYINDEX); // ud fifos @@ -187,7 +187,7 @@ int keeper_push_linda_storage( lua_State* L, void* ptr) { struct s_Keeper* K = keeper_acquire( ptr); lua_State* KL = K->L; - STACK_CHECK( KL) + STACK_CHECK( KL); lua_pushlightuserdata( KL, fifos_key); // fifos_key lua_rawget( KL, LUA_REGISTRYINDEX); // fifos lua_pushlightuserdata( KL, ptr); // fifos ud @@ -206,7 +206,7 @@ int keeper_push_linda_storage( lua_State* L, void* ptr) keeper_fifo* fifo = prepare_fifo_access( KL, -1); // storage key fifo lua_pushvalue( KL, -2); // storage key fifo key luaG_inter_move( KL, L, 1); // storage key fifo // out key - STACK_CHECK( L) + STACK_CHECK( L); lua_newtable( L); // out key keyout luaG_inter_move( KL, L, 1); // storage key // out key keyout fifo lua_pushinteger( L, fifo->first); // out key keyout fifo first @@ -217,10 +217,10 @@ int keeper_push_linda_storage( lua_State* L, void* ptr) lua_setfield( L, -3, "limit"); // out key keyout fifo lua_setfield( L, -2, "fifo"); // out key keyout lua_rawset( L, -3); // out - STACK_END( L, 0) + STACK_END( L, 0); } lua_pop( KL, 1); // - STACK_END( KL, 0) + STACK_END( KL, 0); keeper_release( K); return 1; } @@ -565,26 +565,31 @@ char const* init_keepers( lua_State* L, int const _nbKeepers, lua_CFunction _on_ GKeepers = malloc( _nbKeepers * sizeof( struct s_Keeper)); for( i = 0; i < _nbKeepers; ++ i) { + lua_State* K; + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "### init_keepers %d BEGIN\n" INDENT_END, i)); + DEBUGSPEW_CODE( ++ debugspew_indent_depth); // We need to load all base libraries in the keeper states so that the transfer databases are populated properly // // 'io' for debugging messages, 'package' because we need to require modules exporting idfuncs // the others because they export functions that we may store in a keeper for transfer between lanes - lua_State* K = luaG_newstate( L, "*", _on_state_create); + K = luaG_newstate( L, "*", _on_state_create); - DEBUGSPEW_CODE( fprintf( stderr, "init_keepers %d\n", i)); + STACK_CHECK( K); + + // replace default 'package' contents with stuff gotten from the master state + lua_getglobal( L, "package"); + luaG_inter_copy_package( L, K, -1); + lua_pop( L, 1); + + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "### init_keepers %d END\n" INDENT_END, i)); + DEBUGSPEW_CODE( -- debugspew_indent_depth); - STACK_CHECK( K) // to see VM name in Decoda debugger lua_pushliteral( K, "Keeper #"); lua_pushinteger( K, i + 1); lua_concat( K, 2); lua_setglobal( K, "decoda_name"); - // replace default 'package' contents with stuff gotten from the master state - lua_getglobal( L, "package"); - luaG_inter_copy_package( L, K, -1); - lua_pop( L, 1); - #if KEEPER_MODEL == KEEPER_MODEL_C // create the fifos table in the keeper state lua_pushlightuserdata( K, fifos_key); @@ -611,7 +616,7 @@ char const* init_keepers( lua_State* L, int const _nbKeepers, lua_CFunction _on_ STACK_MID( K, 2); lua_pop( K, 2); #endif // KEEPER_MODEL == KEEPER_MODEL_LUA - STACK_END( K, 0) + STACK_END( K, 0); MUTEX_INIT( &GKeepers[i].lock_); GKeepers[i].L = K; //GKeepers[i].count = 0; @@ -630,7 +635,7 @@ void populate_keepers( lua_State* L) char const* name = luaL_checklstring( L, -1, &name_len); int i; - STACK_CHECK( L) + STACK_CHECK( L); STACK_GROW( L, 3); for( i = 0; i < GNbKeepers; ++ i) @@ -638,20 +643,20 @@ void populate_keepers( lua_State* L) lua_State* K = GKeepers[i].L; int res; MUTEX_LOCK( &GKeepers[i].lock_); - STACK_CHECK( K) + STACK_CHECK( K); STACK_GROW( K, 2); lua_getglobal( K, "require"); lua_pushlstring( K, name, name_len); res = lua_pcall( K, 1, 0, 0); - if( res != 0) + if( res != LUA_OK) { char const* err = luaL_checkstring( K, -1); luaL_error( L, "error requiring '%s' in keeper state: %s", name, err); } - STACK_END( K, 0) + STACK_END( K, 0); MUTEX_UNLOCK( &GKeepers[i].lock_); } - STACK_END( L, 0) + STACK_END( L, 0); } struct s_Keeper* keeper_acquire( void const* ptr) diff --git a/src/lanes.c b/src/lanes.c index 62d56c1..80f5b15 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -403,11 +403,11 @@ LUAG_FUNC( linda_send) STACK_GROW(L, 1); { struct s_Keeper *K = keeper_acquire( linda); - lua_State*KL = K->L; // need to do this for 'STACK_CHECK' - STACK_CHECK( KL) + lua_State *KL = K->L; // need to do this for 'STACK_CHECK' + STACK_CHECK( KL); for( ;;) { - STACK_MID(KL, 0) + STACK_MID( KL, 0); pushed = keeper_call( KL, KEEPER_API( send), L, linda, key_i); if( pushed < 0) { @@ -444,12 +444,12 @@ LUAG_FUNC( linda_send) enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings STACK_GROW(L, 1); - STACK_CHECK(L) + STACK_CHECK( L); lua_pushlightuserdata( L, CANCEL_TEST_KEY); lua_rawget( L, LUA_REGISTRYINDEX); s = lua_touserdata( L, -1); // lightuserdata (true 's_lane' pointer) or nil if in the main Lua state lua_pop(L, 1); - STACK_END(L,0) + STACK_END( L, 0); if( s) { prev_status = s->status; // RUNNING, most likely @@ -475,7 +475,7 @@ LUAG_FUNC( linda_send) } } } - STACK_END( KL, 0) + STACK_END( KL, 0); keeper_release( K); } @@ -602,12 +602,12 @@ LUAG_FUNC( linda_receive) enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings STACK_GROW(L,1); - STACK_CHECK(L) + STACK_CHECK( L); lua_pushlightuserdata( L, CANCEL_TEST_KEY); lua_rawget( L, LUA_REGISTRYINDEX); s = lua_touserdata( L, -1); // lightuserdata (true 's_lane' pointer) or nil if in the main Lua state - lua_pop(L, 1); - STACK_END(L, 0) + lua_pop( L, 1); + STACK_END( L, 0); if( s) { prev_status = s->status; // RUNNING, most likely @@ -959,7 +959,7 @@ static void linda_id( lua_State*L, char const * const which) else if (strcmp( which, "metatable" )==0) { - STACK_CHECK(L) + STACK_CHECK( L); lua_newtable(L); // metatable is its own index lua_pushvalue( L, -1); @@ -1008,7 +1008,7 @@ static void linda_id( lua_State*L, char const * const which) lua_pushliteral( L, BATCH_SENTINEL); lua_setfield(L, -2, "batched"); - STACK_END(L,1) + STACK_END( L, 1); } else if( strcmp( which, "module") == 0) { @@ -1441,12 +1441,12 @@ static bool_t cancel_test( lua_State*L ) { STACK_GROW(L,1); - STACK_CHECK(L) + STACK_CHECK( L); lua_pushlightuserdata( L, CANCEL_TEST_KEY ); lua_rawget( L, LUA_REGISTRYINDEX ); s= lua_touserdata( L, -1 ); // lightuserdata (true 's_lane' pointer) / nil lua_pop(L,1); - STACK_END(L,0) + STACK_END( L, 0); // 's' is NULL for the original main state (no-one can cancel that) // @@ -1773,12 +1773,12 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) // LUA_ERRMEM(4): memory allocation error #endif - DEBUGSPEW_CODE( fprintf( stderr, "Lane %p body: %s\n", L, get_errcode_name( rc))); + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p body: %s\n" INDENT_END, L, get_errcode_name( rc))); //STACK_DUMP(L); // Call finalizers, if the script has set them up. // rc2 = run_finalizers( L, rc); - DEBUGSPEW_CODE( fprintf( stderr, "Lane %p finalizer: %s\n", L, get_errcode_name( rc2))); + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p finalizer: %s\n" INDENT_END, L, get_errcode_name( rc2))); if( rc2 != LUA_OK) { // Error within a finalizer! @@ -1857,7 +1857,9 @@ static void require_one_module( lua_State* L, lua_State* L2, bool_t _fatal) { lua_pop( L2, 1); if( _fatal) + { luaL_error( L, "cannot pre-require modules without loading 'package' library first"); + } } else { @@ -1868,11 +1870,11 @@ static void require_one_module( lua_State* L, lua_State* L2, bool_t _fatal) } } -LUAG_FUNC( thread_new ) +LUAG_FUNC( thread_new) { - lua_State*L2; - struct s_lane *s; - struct s_lane **ud; + lua_State* L2; + struct s_lane* s; + struct s_lane** ud; char const* libs = lua_tostring( L, 2); lua_CFunction on_state_create = lua_iscfunction( L, 3) ? lua_tocfunction( L, 3) : NULL; @@ -1891,6 +1893,8 @@ LUAG_FUNC( thread_new ) } /* --- Create and prepare the sub state --- */ + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: setup\n" INDENT_END)); + DEBUGSPEW_CODE( ++ debugspew_indent_depth); // populate with selected libraries at the same time // @@ -1905,6 +1909,7 @@ LUAG_FUNC( thread_new ) ASSERT_L( lua_gettop(L2) == 0); + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: update 'package'\n" INDENT_END)); // package if( package) { @@ -1913,21 +1918,24 @@ LUAG_FUNC( thread_new ) // modules to require in the target lane *before* the function is transfered! + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: require 'lanes.core'\n" INDENT_END)); //start by requiring lanes.core, since it is a bit special // it is not fatal if 'require' isn't loaded, just ignore (may cause function transfer errors later on if the lane pulls the lanes module itself) - STACK_CHECK(L) - STACK_CHECK(L2) + STACK_CHECK( L); + STACK_CHECK( L2); lua_pushliteral( L, "lanes.core"); require_one_module( L, L2, FALSE); lua_pop( L, 1); - STACK_END(L2,0) - STACK_END(L,0) + STACK_END( L2, 0); + STACK_END (L, 0); - STACK_CHECK(L) - STACK_CHECK(L2) + STACK_CHECK( L); + STACK_CHECK( L2); if( required) { int nbRequired = 1; + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: require 'required' list\n" INDENT_END)); + DEBUGSPEW_CODE( ++ debugspew_indent_depth); // should not happen, was checked in lanes.lua before calling thread_new() if( lua_type( L, required) != LUA_TTABLE) { @@ -1947,22 +1955,25 @@ LUAG_FUNC( thread_new ) lua_pop( L, 1); ++ nbRequired; } + DEBUGSPEW_CODE( -- debugspew_indent_depth); } - STACK_END(L2,0) - STACK_END(L,0) + STACK_END( L2, 0); + STACK_END( L, 0); // Appending the specified globals to the global environment // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed... // if( glob != 0) { - STACK_CHECK(L) - STACK_CHECK(L2) + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: transfer globals\n" INDENT_END)); + STACK_CHECK( L); + STACK_CHECK( L2); if( !lua_istable( L, glob)) { return luaL_error( L, "Expected table, got %s", luaL_typename( L, glob)); } + DEBUGSPEW_CODE( ++ debugspew_indent_depth); lua_pushnil( L); lua_pushglobaltable( L2); // Lua 5.2 wants us to push the globals table on the stack while( lua_next( L, glob)) @@ -1974,23 +1985,29 @@ LUAG_FUNC( thread_new ) } lua_pop( L2, 1); - STACK_END(L2, 0) - STACK_END(L, 0) + STACK_END( L2, 0); + STACK_END( L, 0); + DEBUGSPEW_CODE( -- debugspew_indent_depth); } - ASSERT_L( lua_gettop(L2) == 0); + ASSERT_L( lua_gettop( L2) == 0); // Lane main function // - STACK_CHECK(L) + STACK_CHECK( L); if( lua_type( L, 1) == LUA_TFUNCTION) { + int res; + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: transfer lane body\n" INDENT_END)); + DEBUGSPEW_CODE( ++ debugspew_indent_depth); lua_pushvalue( L, 1); - if( luaG_inter_move( L, L2, 1) != 0) // L->L2 + res = luaG_inter_move( L, L2, 1); // L->L2 + DEBUGSPEW_CODE( -- debugspew_indent_depth); + if( res != 0) { return luaL_error( L, "tried to copy unsupported types"); } - STACK_MID(L,0) + STACK_MID( L, 0); } else if( lua_type( L, 1) == LUA_TSTRING) { @@ -2001,28 +2018,34 @@ LUAG_FUNC( thread_new ) } } - ASSERT_L( lua_gettop(L2) == 1); - ASSERT_L( lua_isfunction(L2,1)); + ASSERT_L( lua_gettop( L2) == 1); + ASSERT_L( lua_isfunction( L2, 1)); // revive arguments // - if( (args > 0) && (luaG_inter_copy( L, L2, args) != 0)) // L->L2 + if( args > 0) { - return luaL_error( L, "tried to copy unsupported types"); + int res; + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: transfer lane arguments\n" INDENT_END)); + DEBUGSPEW_CODE( ++ debugspew_indent_depth); + res = luaG_inter_copy( L, L2, args); // L->L2 + DEBUGSPEW_CODE( -- debugspew_indent_depth); + if( res != 0) + return luaL_error( L, "tried to copy unsupported types"); } - STACK_MID(L,0) + STACK_MID( L, 0); - ASSERT_L( (uint_t)lua_gettop(L2) == 1+args ); - ASSERT_L( lua_isfunction(L2,1) ); + ASSERT_L( (uint_t)lua_gettop( L2) == 1+args); + ASSERT_L( lua_isfunction( L2, 1)); // 's' is allocated from heap, not Lua, since its life span may surpass // the handle's (if free running thread) // - ud= lua_newuserdata( L, sizeof(struct s_lane*) ); - ASSERT_L(ud); + ud = lua_newuserdata( L, sizeof( struct s_lane*)); + ASSERT_L( ud); - s= *ud= malloc( sizeof(struct s_lane) ); - ASSERT_L(s); + s = *ud = malloc( sizeof( struct s_lane)); + ASSERT_L( s); //memset( s, 0, sizeof(struct s_lane) ); s->L= L2; @@ -2045,7 +2068,7 @@ LUAG_FUNC( thread_new ) // lua_pushvalue( L, lua_upvalueindex(1) ); lua_setmetatable( L, -2 ); - STACK_MID(L,1) + STACK_MID( L, 1); // Clear environment for the userdata // @@ -2064,8 +2087,11 @@ LUAG_FUNC( thread_new ) lua_sethook( L2, cancel_hook, LUA_MASKCOUNT, cs ); } + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: launching thread\n" INDENT_END)); THREAD_CREATE( &s->thread, lane_main, s, prio ); - STACK_END(L,1) + STACK_END( L, 1); + + DEBUGSPEW_CODE( -- debugspew_indent_depth); return 1; } @@ -2503,7 +2529,7 @@ LUAG_FUNC( wakeup_conv ) // .yday (day of the year) // .isdst (daylight saving on/off) - STACK_CHECK(L) + STACK_CHECK( L); lua_getfield( L, 1, "year" ); year= (int)lua_tointeger(L,-1); lua_pop(L,1); lua_getfield( L, 1, "month" ); month= (int)lua_tointeger(L,-1); lua_pop(L,1); lua_getfield( L, 1, "day" ); day= (int)lua_tointeger(L,-1); lua_pop(L,1); @@ -2517,7 +2543,7 @@ LUAG_FUNC( wakeup_conv ) lua_getfield( L, 1, "isdst" ); isdst= lua_isboolean(L,-1) ? lua_toboolean(L,-1) : -1; lua_pop(L,1); - STACK_END(L,0) + STACK_END( L, 0); t.tm_year= year-1900; t.tm_mon= month-1; // 0..11 @@ -2619,13 +2645,13 @@ static void init_once_LOCKED( lua_State* L, int const nbKeepers, lua_CFunction _ // ASSERT_L( timer_deep == NULL); - STACK_CHECK(L) + STACK_CHECK( L); { // proxy_ud= deep_userdata( idfunc ) // lua_pushliteral( L, "lanes-timer"); // push a name for debug purposes luaG_deep_userdata( L, linda_id); - STACK_MID( L, 2) + STACK_MID( L, 2); lua_remove( L, -2); // remove the name as we no longer need it ASSERT_L( lua_isuserdata(L,-1) ); @@ -2653,7 +2679,7 @@ static void init_once_LOCKED( lua_State* L, int const nbKeepers, lua_CFunction _ lua_rawset( L, LUA_REGISTRYINDEX); } - STACK_END(L,0) + STACK_END( L, 0); } static volatile long s_initCount = 0; @@ -2669,7 +2695,10 @@ LUAG_FUNC( configure) lua_Number shutdown_timeout = lua_tonumber( L, 3); bool_t track_lanes = lua_toboolean( L, 4); - STACK_CHECK( L) + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() BEGIN\n" INDENT_END, L)); + DEBUGSPEW_CODE( ++ debugspew_indent_depth); + STACK_CHECK( L); + // Create main module interface table lua_pushvalue( L, lua_upvalueindex( 2)); // ... M // remove configure() (this function) from the module interface @@ -2677,7 +2706,7 @@ LUAG_FUNC( configure) lua_setfield( L, -2, "configure"); // ... M // add functions to the module's table luaG_registerlibfuncs( L, lanes_functions); - STACK_MID( L, 1) + STACK_MID( L, 1); // metatable for threads // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join } @@ -2723,7 +2752,7 @@ LUAG_FUNC( configure) populate_func_lookup_table( L, -1, NULL); lua_pop( L, 1); // ... M - STACK_MID( L, 1) + STACK_MID( L, 1); /* * Making one-time initializations. * @@ -2765,14 +2794,16 @@ LUAG_FUNC( configure) } #endif // THREADAPI == THREADAPI_PTHREAD assert( timer_deep != NULL); - STACK_MID( L, 1) + STACK_MID( L, 1); // init_once_LOCKED initializes timer_deep, so we must do this after, of course luaG_push_proxy( L, linda_id, (DEEP_PRELUDE*) timer_deep); // ... M timer_deep lua_setfield( L, -2, "timer_gateway"); // ... M lua_pop( L, 1); // ... - STACK_END( L, 0) + STACK_END( L, 0); + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L)); + DEBUGSPEW_CODE( -- debugspew_indent_depth); // Return nothing return 0; } @@ -2810,7 +2841,7 @@ luaopen_lanes_core( lua_State* L) EnableCrashingOnCrashes(); STACK_GROW( L, 3); - STACK_CHECK( L) + STACK_CHECK( L); // sanity check: let's see if _"VERSION" matches what we we built against lua_getglobal( L, "_VERSION"); @@ -2838,6 +2869,6 @@ luaopen_lanes_core( lua_State* L) lua_call( L, 2, 0); } - STACK_END( L, 1) + STACK_END( L, 1); return 1; } diff --git a/src/lanes.lua b/src/lanes.lua index 6bd9e44..1d50f97 100644 --- a/src/lanes.lua +++ b/src/lanes.lua @@ -281,7 +281,7 @@ local function gen( ... ) elseif k=="package" then package_tbl = (type( v) == "table") and v or error( "Bad package: " .. tostring( v), lev) elseif k=="required" then - required= (type( v) == "table") and v or error( "Bad required: " .. tostring( v), lev) + required= (type( v) == "table") and v or error( "Bad 'required' option: expecting table, got " .. type( v), lev) --.. elseif k==1 then error( "unkeyed option: ".. tostring(v), lev ) else error( "Bad option: ".. tostring(k), lev ) diff --git a/src/tools.c b/src/tools.c index ade8cb8..552e61e 100644 --- a/src/tools.c +++ b/src/tools.c @@ -43,6 +43,8 @@ THE SOFTWARE. #include DEBUGSPEW_CODE( char const* debugspew_indent = "----+----!----+----!----+----!----+----!----+----!----+----!----+----!----+"); +DEBUGSPEW_CODE( int debugspew_indent_depth = 0); + MUTEX_T deep_lock; MUTEX_T mtid_lock; @@ -69,7 +71,7 @@ void luaG_dump( lua_State* L ) { // Note: this requires 'tostring()' to be defined. If it is NOT, // enable it for more debugging. // - STACK_CHECK(L) + STACK_CHECK( L); STACK_GROW( L, 2); lua_getglobal( L, "tostring" ); @@ -87,7 +89,7 @@ void luaG_dump( lua_State* L ) { fprintf( stderr, "%s", lua_tostring(L,-1) ); } lua_pop(L,1); - STACK_END(L,0) + STACK_END( L, 0); fprintf( stderr, "\n" ); } fprintf( stderr, "\n" ); @@ -125,8 +127,8 @@ static void open1lib( lua_State* L, char const* name, size_t len) { if( libs[i].func) { - DEBUGSPEW_CODE( fprintf( stderr, "opening %.*s library\n", len, name)); - STACK_CHECK( L) + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening %.*s library\n" INDENT_END, len, name)); + STACK_CHECK( L); #if LUA_VERSION_NUM >= 502 // open the library as if through require(), and create a global as well (the library table is left on the stack) luaL_requiref( L, libs[i].name, libs[i].func, 1); @@ -137,7 +139,7 @@ static void open1lib( lua_State* L, char const* name, size_t len) // pushes the module table on the stack lua_call( L, 0, 0); #endif // LUA_VERSION_NUM - STACK_END( L, 0) + STACK_END( L, 0); } break; } @@ -216,7 +218,7 @@ static char const* luaG_pushFQN(lua_State *L, int t, int last) { int i = 1; luaL_Buffer b; - STACK_CHECK( L) + STACK_CHECK( L); luaL_buffinit(L, &b); for( ; i < last; ++ i) { @@ -230,7 +232,7 @@ static char const* luaG_pushFQN(lua_State *L, int t, int last) luaL_addvalue( &b); } luaL_pushresult( &b); - STACK_END( L, 1) + STACK_END( L, 1); return lua_tostring( L, -1); } @@ -249,14 +251,14 @@ static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _ STACK_GROW( L, 6); // slot _i contains a table where we search for functions - STACK_CHECK( L) // ... {_i} + STACK_CHECK( L); // ... {_i} // if table is already visited, we are done lua_pushvalue( L, _i); // ... {_i} {} lua_rawget( L, cache); // ... {_i} nil|n visit_count = lua_tointeger( L, -1); // 0 if nil, else n lua_pop( L, 1); // ... {_i} - STACK_MID( L, 0) + STACK_MID( L, 0); if( visit_count > 0) { return; @@ -266,7 +268,7 @@ static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _ lua_pushvalue( L, _i); // ... {_i} {} lua_pushinteger( L, visit_count + 1); // ... {_i} {} 1 lua_rawset( L, cache); // ... {_i} - STACK_MID( L, 0) + STACK_MID( L, 0); // this table is at breadth_first_cache index lua_newtable( L); // ... {_i} {bfc} @@ -276,7 +278,7 @@ static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _ while( lua_next( L, _i) != 0) // ... {_i} {bfc} k v { // just for debug, not actually needed - //char const * key = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : "not a string"; + //char const* key = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : "not a string"; // subtable: process it recursively if( lua_istable( L, -1)) // ... {_i} {bfc} k {} { @@ -332,20 +334,23 @@ static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _ // remove table name from fqn stack lua_pushnil( L); // ... {_i} {bfc} k nil lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k - DEBUGSPEW_CODE( fprintf( stderr, "%.*spopulating: %s\n", _i, debugspew_indent, newName)); + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "function '%s'\n" INDENT_END, newName)); -- _depth; } else { lua_pop( L, 1); // ... {_i} {bfc} k } - STACK_MID( L, 2) + STACK_MID( L, 2); } // now process the tables we encountered at that depth ++ _depth; lua_pushnil( L); // ... {_i} {bfc} nil while( lua_next( L, breadth_first_cache) != 0) // ... {_i} {bfc} k {} { + DEBUGSPEW_CODE( char const* key = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : "not a string"); + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "table '%s'\n" INDENT_END, key)); + DEBUGSPEW_CODE( ++ debugspew_indent_depth); // un-visit this table in case we do need to process it lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} lua_rawget( L, cache); // ... {_i} {bfc} k {} n @@ -367,7 +372,8 @@ static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _ lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k {} populate_func_lookup_table_recur( L, _ctx_base, lua_gettop( L), _depth); // ... {_i} {bfc} k {} lua_pop( L, 1); // ... {_i} {bfc} k - STACK_MID( L, 2) + STACK_MID( L, 2); + DEBUGSPEW_CODE( -- debugspew_indent_depth); } // remove table name from fqn stack lua_pushnil( L); // ... {_i} {bfc} nil @@ -375,7 +381,7 @@ static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _ -- _depth; // we are done with our cache lua_pop( L, 1); // ... {_i} - STACK_END( L, 0) + STACK_END( L, 0); // we are done // ... {_i} {bfc} } @@ -387,9 +393,10 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* _name) int const ctx_base = lua_gettop( L) + 1; int const in_base = lua_absindex( L, _i); int const start_depth = _name ? 1 : 0; - DEBUGSPEW_CODE( fprintf( stderr, "%p: populate_func_lookup_table('%s')\n", L, _name ? _name : "NULL")); + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, _name ? _name : "NULL")); + DEBUGSPEW_CODE( ++ debugspew_indent_depth); STACK_GROW( L, 3); - STACK_CHECK( L) + STACK_CHECK( L); lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // {}? if( lua_isnil( L, -1)) // nil { @@ -414,7 +421,8 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* _name) } populate_func_lookup_table_recur( L, ctx_base, in_base, start_depth); // {...} {fqn} {cache} lua_pop( L, 3); - STACK_END( L, 0) + STACK_END( L, 0); + DEBUGSPEW_CODE( -- debugspew_indent_depth); } /* @@ -447,11 +455,14 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_ return L; } + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END)); + DEBUGSPEW_CODE( ++ debugspew_indent_depth); + STACK_GROW( L, 2); - STACK_CHECK( L) + STACK_CHECK( L); if( _on_state_create) { - DEBUGSPEW_CODE( fprintf( stderr, "calling on_state_create()\n")); + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END)); lua_pushcfunction( L, _on_state_create); lua_call( L, 0, 0); } @@ -466,13 +477,13 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_ { if( libs[0] == '*' && libs[1] == 0) // special "*" case (mainly to help with LuaJIT compatibility) { - DEBUGSPEW_CODE( fprintf( stderr, "opening ALL standard libraries\n")); + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); luaL_openlibs( L); libs = NULL; // done with libs } else { - DEBUGSPEW_CODE( fprintf( stderr, "opening base library\n")); + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening base library\n" INDENT_END)); #if LUA_VERSION_NUM >= 502 // open base library the same way as in luaL_openlibs() luaL_requiref( L, "_G", luaopen_base, 1); @@ -484,7 +495,7 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_ #endif // LUA_VERSION_NUM } } - STACK_END( L, 0) + STACK_END( L, 0); // scan all libraries, open them one by one if( libs) @@ -508,12 +519,13 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_ lua_gc( L, LUA_GCRESTART, 0); - STACK_CHECK( L) + STACK_CHECK( L); // after opening base, register the functions it exported in our name<->function database lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack populate_func_lookup_table( L, -1, NULL); lua_pop( L, 1); - STACK_END( L, 0) + STACK_END( L, 0); + DEBUGSPEW_CODE( -- debugspew_indent_depth); return L; } @@ -554,7 +566,7 @@ void set_deep_lookup( lua_State *L ) { STACK_GROW(L,3); - STACK_CHECK(L) + STACK_CHECK( L); #if 1 push_registry_subtable( L, DEEP_LOOKUP_KEY ); #else @@ -580,7 +592,7 @@ void set_deep_lookup( lua_State *L ) { // [-1]: lookup table (empty) } #endif - STACK_MID(L,1) + STACK_MID( L, 1); lua_insert(L,-3); @@ -594,7 +606,7 @@ void set_deep_lookup( lua_State *L ) { lua_rawset( L, -3 ); // A->B lua_pop( L,1 ); - STACK_END(L,-2) + STACK_END( L, -2); } /* @@ -605,7 +617,7 @@ void get_deep_lookup( lua_State *L ) { STACK_GROW(L,1); - STACK_CHECK(L) + STACK_CHECK( L); lua_pushlightuserdata( L, DEEP_LOOKUP_KEY ); lua_rawget( L, LUA_REGISTRYINDEX ); @@ -621,7 +633,7 @@ void get_deep_lookup( lua_State *L ) { } lua_remove(L,-2); // remove lookup, or unused key - STACK_END(L,0) + STACK_END( L, 0); } /* @@ -637,7 +649,7 @@ luaG_IdFunction get_idfunc( lua_State *L, int index ) STACK_GROW(L,1); - STACK_CHECK(L) + STACK_CHECK( L); if (!lua_getmetatable( L, index )) return NULL; // no metatable @@ -649,7 +661,7 @@ luaG_IdFunction get_idfunc( lua_State *L, int index ) ret= (luaG_IdFunction)lua_touserdata(L,-1); lua_pop(L,1); - STACK_END(L,0) + STACK_END( L, 0); return ret; } @@ -728,7 +740,7 @@ void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelud STACK_GROW(L,4); - STACK_CHECK(L) + STACK_CHECK( L); proxy= lua_newuserdata( L, sizeof( DEEP_PRELUDE* ) ); ASSERT_L(proxy); @@ -784,7 +796,7 @@ void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelud // 2 - cause the target state to require the module that exported the idfunc // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc - STACK_CHECK(L) + STACK_CHECK( L); { char const * modname; // make sure the function pushed a single value on the stack! @@ -839,9 +851,9 @@ void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelud lua_pop( L, 1); // ... } } - STACK_END(L,0) + STACK_END( L, 0); } - STACK_MID(L,2) + STACK_MID( L, 2); ASSERT_L( lua_isuserdata(L,-2) ); ASSERT_L( lua_istable(L,-1) ); @@ -857,7 +869,7 @@ void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelud lua_rawset(L, -3); lua_pop(L, 1); // Remove the cache proxy table - STACK_END(L,1) + STACK_END( L, 1); // [-1]: proxy userdata } @@ -894,7 +906,7 @@ int luaG_deep_userdata( lua_State *L, luaG_IdFunction idfunc) prelude->refcount= 0; // 'luaG_push_proxy' will lift it to 1 STACK_GROW(L,1); - STACK_CHECK(L) + STACK_CHECK( L); // lightuserdata= idfunc( "new" [, ...] ) // @@ -915,7 +927,7 @@ int luaG_deep_userdata( lua_State *L, luaG_IdFunction idfunc) // // [-1]: proxy userdata - STACK_END(L,1) + STACK_END( L, 1); return 1; } @@ -930,12 +942,12 @@ void *luaG_todeep( lua_State *L, luaG_IdFunction idfunc, int index ) { DEEP_PRELUDE **proxy; - STACK_CHECK(L) + STACK_CHECK( L); if( get_idfunc(L,index) != idfunc) return NULL; // no metatable, or wrong kind proxy= (DEEP_PRELUDE**)lua_touserdata( L, index ); - STACK_END(L,0) + STACK_END( L, 0); return (*proxy)->deep; } @@ -993,7 +1005,7 @@ void push_registry_subtable_mode( lua_State *L, void *token, const char* mode ) STACK_GROW(L,3); - STACK_CHECK(L) + STACK_CHECK( L); lua_pushlightuserdata( L, token ); lua_rawget( L, LUA_REGISTRYINDEX ); @@ -1021,7 +1033,7 @@ void push_registry_subtable_mode( lua_State *L, void *token, const char* mode ) lua_setmetatable(L, -2); } } - STACK_END(L,1) + STACK_END( L, 1); ASSERT_L( lua_istable(L,-1) ); } @@ -1049,7 +1061,7 @@ uint_t get_mt_id( lua_State *L, int i ) { STACK_GROW(L,3); - STACK_CHECK(L) + STACK_CHECK( L); push_registry_subtable( L, REG_MTID ); lua_pushvalue(L, i); lua_rawget( L, -2 ); @@ -1059,7 +1071,7 @@ uint_t get_mt_id( lua_State *L, int i ) { id= (uint_t)lua_tointeger(L,-1); // 0 for nil lua_pop(L,1); - STACK_MID(L,1) + STACK_MID( L, 1); if (id==0) { MUTEX_LOCK( &mtid_lock ); @@ -1078,7 +1090,7 @@ uint_t get_mt_id( lua_State *L, int i ) { } lua_pop(L,1); // remove 'reg[REG_MTID]' reference - STACK_END(L,0) + STACK_END( L, 0); return id; } @@ -1111,7 +1123,7 @@ static bool_t push_cached_table( lua_State *L2, uint_t L2_cache_i, lua_State *L, // L2_cache[id_str]= [{...}] // - STACK_CHECK(L2) + STACK_CHECK( L2); // We don't need to use the from state ('L') in ID since the life span // is only for the duration of a copy (both states are locked). @@ -1149,7 +1161,7 @@ static bool_t push_cached_table( lua_State *L2, uint_t L2_cache_i, lua_State *L, lua_remove(L2,-2); ret= TRUE; // from cache } - STACK_END(L2,1) + STACK_END( L2, 1); // // L2 [-1]: table to use as destination @@ -1176,7 +1188,7 @@ static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, ui // L2_cache[id_str]= function // - STACK_CHECK( L2) + STACK_CHECK( L2); // We don't need to use the from state ('L') in ID since the life span // is only for the duration of a copy (both states are locked). @@ -1204,7 +1216,7 @@ static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, ui { lua_remove( L2, -2); // ... {cache} ... function } - STACK_END( L2, 1) + STACK_END( L2, 1); // // L2 [-1]: function @@ -1226,7 +1238,7 @@ int discover_object_name_recur( lua_State* L, int _shortest, int _length) return _shortest; } STACK_GROW( L, 3); - STACK_CHECK(L) + STACK_CHECK( L); // stack top contains the table to search in lua_pushvalue( L, -1); // o "r" {c} {fqn} ... {?} {?} lua_rawget( L, cache); // o "r" {c} {fqn} ... {?} nil/1 @@ -1299,7 +1311,7 @@ int discover_object_name_recur( lua_State* L, int _shortest, int _length) lua_pushvalue( L, -1); // o "r" {c} {fqn} ... {?} {?} lua_pushnil( L); // o "r" {c} {fqn} ... {?} {?} nil lua_rawset( L, cache); // o "r" {c} {fqn} ... {?} - STACK_END( L, 0) + STACK_END( L, 0); return _shortest; } @@ -1345,13 +1357,14 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i) char const* fqn; // L // L2 size_t len; _ASSERT_L( L, lua_isfunction( L, i)); // ... f ... - STACK_CHECK( L) + STACK_CHECK( L); // fetch the name from the source state's lookup table lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // ... f ... {} _ASSERT_L( L, lua_istable( L, -1)); lua_pushvalue( L, i); // ... f ... {} f lua_rawget( L, -2); // ... f ... {} "f.q.n" fqn = lua_tolstring( L, -1, &len); + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END, fqn)); // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database lua_pop( L, 2); // ... f ... if( !fqn) @@ -1366,9 +1379,9 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i) (void) luaL_error( L, "%s '%s' not found in %s origin transfer database.", lua_tostring( L, -3), lua_tostring( L, -2), from ? from : "main"); return; } - STACK_END( L, 0) + STACK_END( L, 0); // push the equivalent function in the destination's stack, retrieved from the lookup table - STACK_CHECK( L2) + STACK_CHECK( L2); lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_KEY); // {} _ASSERT_L( L2, lua_istable( L2, -1)); lua_pushlstring( L2, fqn, len); // {} "f.q.n" @@ -1384,7 +1397,7 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i) return; } lua_remove( L2, -2); // f - STACK_END( L2, 1) + STACK_END( L2, 1); } /* @@ -1403,7 +1416,7 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin ASSERT_L( L2_cache_i != 0); // ... {cache} ... p STACK_GROW(L,2); - STACK_CHECK(L) + STACK_CHECK( L); if( funcSubType == FST_Bytecode) { @@ -1448,7 +1461,7 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin // fills 'name' 'namewhat' and 'linedefined', pops function lua_getinfo(L, ">nS", &ar); // ... b name = ar.namewhat; - fprintf( stderr, "%.*sFNAME: %s @ %d\n", i, s_indent, ar.short_src, ar.linedefined); // just gives NULL + fprintf( stderr, INDENT_BEGIN "FNAME: %s @ %d\n", i, s_indent, ar.short_src, ar.linedefined); // just gives NULL } #endif // LOG_FUNC_INFO { @@ -1480,7 +1493,7 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin // cache[p] = function lua_rawset( L2, L2_cache_i); // ... {cache} ... function } - STACK_MID( L, 0) + STACK_MID( L, 0); /* push over any upvalues; references to this function will come from * cache so we don't end up in eternal loop. @@ -1497,7 +1510,7 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin #endif // LUA_VERSION_NUM for( n = 0; (DEBUGSPEW_CODE( upname =) lua_getupvalue( L, i, 1 + n)) != NULL; ++ n) { // ... _G up[n] - DEBUGSPEW_CODE( fprintf( stderr, "%.*sUPNAME[%d]: %s\n", i, debugspew_indent, n, upname)); + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "UPNAME[%d]: %s\n" INDENT_END, n, upname)); #if LUA_VERSION_NUM == 502 if( lua_rawequal( L, -1, -2)) // is the upvalue equal to the global table? { @@ -1517,7 +1530,7 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin } // L2: function + 'n' upvalues (>=0) - STACK_MID( L, 0) + STACK_MID( L, 0); // Set upvalues (originally set to 'nil' by 'lua_load') { @@ -1539,11 +1552,10 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin else // C function OR LuaJIT fast function!!! { lua_pop( L2, 1); // ... {cache} ... - DEBUGSPEW_CODE( fprintf( stderr, "%.*sFNAME: [C] function %p \n", i, debugspew_indent, cfunc)); // No need to transfer upvalues for C/JIT functions since they weren't actually copied, only looked up lookup_native_func( L2, L, i); // ... {cache} ... function } - STACK_END( L, 0) + STACK_END( L, 0); } /* @@ -1558,206 +1570,253 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin */ static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i, enum e_vt vt ) { - bool_t ret= TRUE; + bool_t ret= TRUE; - STACK_GROW( L2, 1 ); + STACK_GROW( L2, 1 ); - STACK_CHECK(L2) + STACK_CHECK( L2); - switch ( lua_type(L,i) ) { - /* Basic types allowed both as values, and as table keys */ + switch ( lua_type( L, i)) + { + /* Basic types allowed both as values, and as table keys */ - case LUA_TBOOLEAN: - lua_pushboolean( L2, lua_toboolean(L, i) ); - break; + case LUA_TBOOLEAN: + lua_pushboolean( L2, lua_toboolean( L, i)); + break; - case LUA_TNUMBER: - /* LNUM patch support (keeping integer accuracy) */ + case LUA_TNUMBER: + /* LNUM patch support (keeping integer accuracy) */ #ifdef LUA_LNUM - if (lua_isinteger(L,i)) { - lua_pushinteger( L2, lua_tointeger(L, i) ); - break; - } + if( lua_isinteger(L,i)) + { + lua_Integer v = lua_tointeger( L, i); + DEBUGSPEW_CODE( if( vt == VT_KEY) fprintf( stderr, INDENT_BEGIN "KEY: %d\n" INDENT_END, v)); + lua_pushinteger( L2, v); + break; + } + else #endif - lua_pushnumber( L2, lua_tonumber(L, i) ); - break; - - case LUA_TSTRING: { - size_t len; const char* s = lua_tolstring( L, i, &len); - DEBUGSPEW_CODE( if( vt == VT_KEY) fprintf( stderr, "%.*sKEY: %s\n", i, debugspew_indent, s)); - lua_pushlstring( L2, s, len ); - } break; - - case LUA_TLIGHTUSERDATA: - lua_pushlightuserdata( L2, lua_touserdata(L, i) ); - break; - - /* The following types are not allowed as table keys */ - - case LUA_TUSERDATA: if (vt==VT_KEY) { ret=FALSE; break; } - /* Allow only deep userdata entities to be copied across - */ - if (!luaG_copydeep( L, L2, i )) { - // Cannot copy it full; copy as light userdata - // - lua_pushlightuserdata( L2, lua_touserdata(L, i) ); - } break; - - case LUA_TNIL: if (vt==VT_KEY) { ret=FALSE; break; } - lua_pushnil(L2); - break; - - case LUA_TFUNCTION: if (vt==VT_KEY) { ret=FALSE; break; } { - /* - * Passing C functions is risky; if they refer to LUA_ENVIRONINDEX - * and/or LUA_REGISTRYINDEX they might work unintended (not work) - * at the target. - * - * On the other hand, NOT copying them causes many self tests not - * to work (timer, hangtest, ...) - * - * The trouble is, we cannot KNOW if the function at hand is safe - * or not. We cannot study it's behaviour. We could trust the user, - * but they might not even know they're sending lua_CFunction over - * (as upvalues etc.). - */ + { + lua_Number v = lua_tonumber( L, i); + DEBUGSPEW_CODE( if( vt == VT_KEY) fprintf( stderr, INDENT_BEGIN "KEY: " LUA_NUMBER_FMT "\n" INDENT_END, v)); + lua_pushnumber( L2, v); + } + break; + + case LUA_TSTRING: + { + size_t len; + char const* s = lua_tolstring( L, i, &len); + DEBUGSPEW_CODE( if( vt == VT_KEY) fprintf( stderr, INDENT_BEGIN "KEY: %s\n" INDENT_END, s)); + lua_pushlstring( L2, s, len); + } + break; + + case LUA_TLIGHTUSERDATA: + lua_pushlightuserdata( L2, lua_touserdata(L, i)); + break; + + /* The following types are not allowed as table keys */ + + case LUA_TUSERDATA: + if( vt == VT_KEY) + { + ret = FALSE; + break; + } + /* Allow only deep userdata entities to be copied across + */ + if( !luaG_copydeep( L, L2, i)) + { + // Cannot copy it full; copy as light userdata + // + lua_pushlightuserdata( L2, lua_touserdata( L, i)); + } + break; + + case LUA_TNIL: + if( vt == VT_KEY) + { + ret = FALSE; + break; + } + lua_pushnil( L2); + break; + + case LUA_TFUNCTION: + if( vt == VT_KEY) + { + ret = FALSE; + break; + } + { + /* + * Passing C functions is risky; if they refer to LUA_ENVIRONINDEX + * and/or LUA_REGISTRYINDEX they might work unintended (not work) + * at the target. + * + * On the other hand, NOT copying them causes many self tests not + * to work (timer, hangtest, ...) + * + * The trouble is, we cannot KNOW if the function at hand is safe + * or not. We cannot study it's behaviour. We could trust the user, + * but they might not even know they're sending lua_CFunction over + * (as upvalues etc.). + */ #if 0 - if (lua_iscfunction(L,i)) - luaL_error( L, "Copying lua_CFunction between Lua states is risky, and currently disabled." ); + if( lua_iscfunction( L, i)) + luaL_error( L, "Copying lua_CFunction between Lua states is risky, and currently disabled." ); #endif - STACK_CHECK(L2) - push_cached_func( L2, L2_cache_i, L, i ); - ASSERT_L( lua_isfunction(L2,-1) ); - STACK_END(L2,1) - } break; + STACK_CHECK( L2); + push_cached_func( L2, L2_cache_i, L, i); + ASSERT_L( lua_isfunction( L2, -1)); + STACK_END( L2, 1); + } + break; - case LUA_TTABLE: if (vt==VT_KEY) { ret=FALSE; break; } { - - STACK_CHECK(L) - STACK_CHECK(L2) - - /* Check if we've already copied the same table from 'L' (during this transmission), and - * reuse the old copy. This allows table upvalues shared by multiple - * local functions to point to the same table, also in the target. - * Also, this takes care of cyclic tables and multiple references - * to the same subtable. - * - * Note: Even metatables need to go through this test; to detect - * loops s.a. those in required module tables (getmetatable(lanes).lanes == lanes) - */ - if (push_cached_table( L2, L2_cache_i, L, i )) { - ASSERT_L( lua_istable(L2, -1) ); // from cache - break; - } - ASSERT_L( lua_istable(L2,-1) ); - - STACK_GROW( L, 2 ); - STACK_GROW( L2, 2 ); - - lua_pushnil(L); // start iteration - while( lua_next( L, i ) ) { - uint_t val_i= lua_gettop(L); - uint_t key_i= val_i-1; - - /* Only basic key types are copied over; others ignored - */ - if (inter_copy_one_( L2, 0 /*key*/, L, key_i, VT_KEY )) { - /* - * Contents of metatables are copied with cache checking; - * important to detect loops. - */ - if (inter_copy_one_( L2, L2_cache_i, L, val_i, VT_NORMAL )) { - ASSERT_L( lua_istable(L2,-3) ); - lua_rawset( L2, -3 ); // add to table (pops key & val) - } else { - luaL_error( L, "Unable to copy over type '%s' (in %s)", - luaL_typename(L,val_i), - vt==VT_NORMAL ? "table":"metatable" ); - } - } - lua_pop( L, 1 ); // pop value (next round) - } - STACK_MID(L,0) - STACK_MID(L2,1) - - /* Metatables are expected to be immutable, and copied only once. - */ - if (lua_getmetatable( L, i )) { - // - // L [-1]: metatable - - uint_t mt_id= get_mt_id( L, -1 ); // Unique id for the metatable - - STACK_GROW(L2,4); - - push_registry_subtable( L2, REG_MTID ); - STACK_MID(L2,2); - lua_pushinteger( L2, mt_id ); - lua_rawget( L2, -2 ); - // - // L2 ([-3]: copied table) - // [-2]: reg[REG_MTID] - // [-1]: nil/metatable pre-known in L2 - - STACK_MID(L2,3); - - if (lua_isnil(L2,-1)) { /* L2 did not know the metatable */ - lua_pop(L2,1); - STACK_MID(L2,2); -ASSERT_L( lua_istable(L,-1) ); - if (inter_copy_one_( L2, L2_cache_i /*for function cacheing*/, L, lua_gettop(L) /*[-1]*/, VT_METATABLE )) { - // - // L2 ([-3]: copied table) - // [-2]: reg[REG_MTID] - // [-1]: metatable (copied from L) - - STACK_MID(L2,3); - // mt_id -> metatable - // - lua_pushinteger(L2,mt_id); - lua_pushvalue(L2,-2); - lua_rawset(L2,-4); - - // metatable -> mt_id - // - lua_pushvalue(L2,-1); - lua_pushinteger(L2,mt_id); - lua_rawset(L2,-4); - - STACK_MID(L2,3); - } else { - luaL_error( L, "Error copying a metatable" ); - } - STACK_MID(L2,3); - } - // L2 ([-3]: copied table) - // [-2]: reg[REG_MTID] - // [-1]: metatable (pre-known or copied from L) + case LUA_TTABLE: + if( vt == VT_KEY) + { + ret = FALSE; + break; + } + { + STACK_CHECK( L); + STACK_CHECK( L2); + + /* Check if we've already copied the same table from 'L' (during this transmission), and + * reuse the old copy. This allows table upvalues shared by multiple + * local functions to point to the same table, also in the target. + * Also, this takes care of cyclic tables and multiple references + * to the same subtable. + * + * Note: Even metatables need to go through this test; to detect + * loops s.a. those in required module tables (getmetatable(lanes).lanes == lanes) + */ + if( push_cached_table( L2, L2_cache_i, L, i)) + { + ASSERT_L( lua_istable( L2, -1)); // from cache + break; + } + ASSERT_L( lua_istable( L2,-1)); - lua_remove(L2,-2); // take away 'reg[REG_MTID]' - // - // L2: ([-2]: copied table) - // [-1]: metatable for that table + STACK_GROW( L, 2); + STACK_GROW( L2, 2); - lua_setmetatable( L2, -2 ); - - // L2: [-1]: copied table (with metatable set if source had it) + lua_pushnil( L); // start iteration + while( lua_next( L, i)) + { + uint_t val_i = lua_gettop(L); + uint_t key_i = val_i - 1; - lua_pop(L,1); // remove source metatable (L, not L2!) - } - STACK_END(L2,1) - STACK_END(L,0) - } break; + /* Only basic key types are copied over; others ignored + */ + if( inter_copy_one_( L2, 0 /*key*/, L, key_i, VT_KEY)) + { + /* + * Contents of metatables are copied with cache checking; + * important to detect loops. + */ + if( inter_copy_one_( L2, L2_cache_i, L, val_i, VT_NORMAL)) + { + ASSERT_L( lua_istable(L2,-3)); + lua_rawset( L2, -3); // add to table (pops key & val) + } + else + { + luaL_error( L, "Unable to copy over type '%s' (in %s)", luaL_typename( L, val_i), (vt == VT_NORMAL) ? "table" : "metatable"); + } + } + lua_pop( L, 1); // pop value (next round) + } + STACK_MID( L, 0); + STACK_MID( L2, 1); - /* The following types cannot be copied */ + /* Metatables are expected to be immutable, and copied only once. + */ + if( lua_getmetatable( L, i)) + { + // + // L [-1]: metatable - case LUA_TTHREAD: - ret=FALSE; break; - } + uint_t mt_id = get_mt_id( L, -1); // Unique id for the metatable - STACK_END(L2, ret? 1:0) + STACK_GROW( L2, 4); - return ret; + push_registry_subtable( L2, REG_MTID); + STACK_MID( L2, 2); + lua_pushinteger( L2, mt_id); + lua_rawget( L2, -2); + // + // L2 ([-3]: copied table) + // [-2]: reg[REG_MTID] + // [-1]: nil/metatable pre-known in L2 + + STACK_MID( L2, 3); + + if( lua_isnil( L2, -1)) + { /* L2 did not know the metatable */ + lua_pop( L2, 1); + STACK_MID( L2, 2); + ASSERT_L( lua_istable(L,-1)); + if( inter_copy_one_( L2, L2_cache_i /*for function cacheing*/, L, lua_gettop(L) /*[-1]*/, VT_METATABLE)) + { + // + // L2 ([-3]: copied table) + // [-2]: reg[REG_MTID] + // [-1]: metatable (copied from L) + + STACK_MID( L2, 3); + // mt_id -> metatable + // + lua_pushinteger( L2, mt_id); + lua_pushvalue( L2, -2); + lua_rawset( L2, -4); + + // metatable -> mt_id + // + lua_pushvalue( L2, -1); + lua_pushinteger( L2, mt_id); + lua_rawset( L2, -4); + + STACK_MID( L2, 3); + } + else + { + luaL_error( L, "Error copying a metatable"); + } + STACK_MID( L2, 3); + } + // L2 ([-3]: copied table) + // [-2]: reg[REG_MTID] + // [-1]: metatable (pre-known or copied from L) + + lua_remove( L2, -2); // take away 'reg[REG_MTID]' + // + // L2: ([-2]: copied table) + // [-1]: metatable for that table + + lua_setmetatable( L2, -2); + + // L2: [-1]: copied table (with metatable set if source had it) + + lua_pop( L, 1); // remove source metatable (L, not L2!) + } + STACK_END( L2, 1); + STACK_END( L, 0); + } + break; + + /* The following types cannot be copied */ + + case LUA_TTHREAD: + ret = FALSE; + break; + } + + STACK_END( L2, ret ? 1 : 0); + + return ret; } @@ -1829,9 +1888,11 @@ int luaG_inter_move( lua_State* L, lua_State* L2, uint_t n) void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx) { + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_inter_copy_package()\n" INDENT_END)); + DEBUGSPEW_CODE( ++ debugspew_indent_depth); // package - STACK_CHECK( L) - STACK_CHECK( L2) + STACK_CHECK( L); + STACK_CHECK( L2); _idx = lua_absindex( L, _idx); if( lua_type( L, _idx) != LUA_TTABLE) { @@ -1845,6 +1906,7 @@ void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx) char const* entries[] = { "path", "cpath", "preload", (LUA_VERSION_NUM == 501) ? "loaders" : "searchers", NULL}; for( i = 0; entries[i]; ++ i) { + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s\n" INDENT_END, entries[i])); lua_getfield( L, _idx, entries[i]); if( lua_isnil( L, -1)) { @@ -1852,14 +1914,21 @@ void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx) } else { + DEBUGSPEW_CODE( ++ debugspew_indent_depth); luaG_inter_move( L, L2, 1); // moves the entry to L2 + DEBUGSPEW_CODE( -- debugspew_indent_depth); lua_setfield( L2, -2, entries[i]); // set package[entries[i]] } } } + else + { + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "'package' not loaded, nothing to do\n" INDENT_END)); + } lua_pop( L2, 1); - STACK_END( L2, 0) - STACK_END( L, 0) + STACK_END( L2, 0); + STACK_END( L, 0); + DEBUGSPEW_CODE( -- debugspew_indent_depth); } @@ -1882,7 +1951,7 @@ static int new_require( lua_State *L) //char const* modname = luaL_checkstring( L, 1); STACK_GROW( L, args + 1); - STACK_CHECK( L) + STACK_CHECK( L); lua_pushvalue( L, lua_upvalueindex(1)); for( i = 1; i <= args; ++ i) @@ -1900,7 +1969,7 @@ static int new_require( lua_State *L) MUTEX_UNLOCK( &require_cs); // the required module (or an error message) is left on the stack as returned value by original require function - STACK_END( L, 1) + STACK_END( L, 1); if (rc) lua_error(L); // error message already at [-1] @@ -1914,7 +1983,7 @@ static int new_require( lua_State *L) void serialize_require( lua_State *L ) { STACK_GROW( L, 1); - STACK_CHECK( L) + STACK_CHECK( L); // Check 'require' is there; if not, do nothing // @@ -1931,5 +2000,5 @@ void serialize_require( lua_State *L ) lua_pop( L, 1); } - STACK_END( L, 0) + STACK_END( L, 0); } diff --git a/src/tools.h b/src/tools.h index e4fbd94..f79d2ad 100644 --- a/src/tools.h +++ b/src/tools.h @@ -38,6 +38,9 @@ #define USE_DEBUG_SPEW 0 #if USE_DEBUG_SPEW extern char const* debugspew_indent; +extern int debugspew_indent_depth; +#define INDENT_BEGIN "%.*s " +#define INDENT_END , debugspew_indent_depth, debugspew_indent #define DEBUGSPEW_CODE(_code) _code #else // USE_DEBUG_SPEW #define DEBUGSPEW_CODE(_code) @@ -53,10 +56,16 @@ extern char const* debugspew_indent; #else #define _ASSERT_L(lua,c) do { if (!(c)) luaL_error( lua, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #c ); } while( 0) // - #define STACK_CHECK(L) { int _oldtop_##L = lua_gettop(L); - #define STACK_MID(L,change) { int a= lua_gettop(L)-_oldtop_##L; int b= (change); \ - if (a != b) luaL_error( L, "STACK ASSERT failed (%d not %d): %s:%d", a, b, __FILE__, __LINE__ ); } - #define STACK_END(L,change) STACK_MID(L,change) } + #define STACK_CHECK(L) { int const _oldtop_##L = lua_gettop( L) + #define STACK_MID(L,change) \ + do \ + { \ + int a = lua_gettop( L) - _oldtop_##L; \ + int b = (change); \ + if( a != b) \ + luaL_error( L, "STACK ASSERT failed (%d not %d): %s:%d", a, b, __FILE__, __LINE__ ); \ + } while( 0) + #define STACK_END(L,change) STACK_MID(L,change); } #define STACK_DUMP(L) luaG_dump(L); #endif -- cgit v1.2.3-55-g6feb