From 7b4f59c5ebc84e426e2876906b24d7dd73342f07 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Mon, 19 Nov 2018 09:16:49 +0100 Subject: Internal code tweaks * Registry access code utility macros * CONFIG_REGKEY and LOOKUP_REGKEY are now lightuserdata instead of strings * Stack checking debug macros improvements --- src/deep.c | 39 +++++++++--------- src/keeper.c | 34 ++++++++-------- src/lanes.c | 62 ++++++++++++++-------------- src/lanes_private.h | 5 +-- src/linda.c | 9 +++-- src/macros_and_utils.h | 68 ++++++++++++++++++++++++------- src/tools.c | 107 +++++++++++++++++++++++++++---------------------- src/tools.h | 11 +++-- src/universe.c | 25 ++++-------- 9 files changed, 202 insertions(+), 158 deletions(-) (limited to 'src') diff --git a/src/deep.c b/src/deep.c index c351bf7..a486a72 100644 --- a/src/deep.c +++ b/src/deep.c @@ -33,6 +33,7 @@ THE SOFTWARE. */ #include +#include #include #include #include @@ -63,20 +64,18 @@ THE SOFTWARE. static void push_registry_subtable_mode( lua_State* L, UniqueKey key_, const char* mode_) { STACK_GROW( L, 3); - STACK_CHECK( L); + STACK_CHECK( L, 0); - push_unique_key( L, key_); // key - lua_rawget( L, LUA_REGISTRYINDEX); // {}|nil + REGISTRY_GET( L, key_); // {}|nil + STACK_MID( L, 1); if( lua_isnil( L, -1)) { lua_pop( L, 1); // lua_newtable( L); // {} - push_unique_key( L, key_); // {} key - lua_pushvalue( L, -2); // {} key {} - // _R[key_] = {} - lua_rawset( L, LUA_REGISTRYINDEX); // {} + REGISTRY_SET( L, key_, lua_pushvalue( L, -2)); // {} + STACK_MID( L, 1); // Set its metatable if requested if( mode_) @@ -128,16 +127,16 @@ static DECLARE_CONST_UNIQUE_KEY( DEEP_PROXY_CACHE_KEY, 0x05773d6fc26be106); static void set_deep_lookup( lua_State* L) { STACK_GROW( L, 3); - STACK_CHECK( L); // a b + STACK_CHECK( L, 2); // a b push_registry_subtable( L, DEEP_LOOKUP_KEY); // a b {} - STACK_MID( L, 1); + STACK_MID( L, 3); lua_insert( L, -3); // {} a b lua_pushvalue( L, -1); // {} a b b lua_pushvalue( L,-3); // {} a b b a lua_rawset( L, -5); // {} a b lua_rawset( L, -3); // {} lua_pop( L, 1); // - STACK_END( L, -2); + STACK_END( L, 0); } /* @@ -147,17 +146,15 @@ static void set_deep_lookup( lua_State* L) static void get_deep_lookup( lua_State* L) { STACK_GROW( L, 1); - STACK_CHECK( L); // a - push_unique_key( L, DEEP_LOOKUP_KEY); // a DLK - lua_rawget( L, LUA_REGISTRYINDEX); // a {} - + STACK_CHECK( L, 1); // a + REGISTRY_GET( L, DEEP_LOOKUP_KEY); // a {} if( !lua_isnil( L, -1)) { lua_insert( L, -2); // {} a lua_rawget( L, -2); // {} b } lua_remove( L, -2); // a|b - STACK_END( L, 0); + STACK_END( L, 1); } /* @@ -180,7 +177,7 @@ static inline luaG_IdFunction get_idfunc( lua_State* L, int index, LookupMode mo // of course, we could just trust the caller, but we won't luaG_IdFunction ret; STACK_GROW( L, 1); - STACK_CHECK( L); + STACK_CHECK( L, 0); if( !lua_getmetatable( L, index)) // deep ... metatable? { @@ -284,7 +281,7 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, Lo if( U) MUTEX_UNLOCK( &U->deep_lock); STACK_GROW( L, 7); - STACK_CHECK( L); + STACK_CHECK( L, 0); proxy = lua_newuserdata( L, sizeof(DeepPrelude*)); // DPC proxy ASSERT_L( proxy); @@ -318,7 +315,7 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, Lo lua_newtable( L); // DPC proxy metatable lua_pushnil( L); // DPC proxy metatable nil } - if (lua_isnil(L, -1)) + if( lua_isnil( L, -1)) { // Add our own '__gc' method lua_pop( L, 1); // DPC proxy metatable @@ -438,9 +435,9 @@ int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) char const* errmsg; STACK_GROW( L, 1); - STACK_CHECK( L); + STACK_CHECK( L, 0); { - int oldtop = lua_gettop( L); + int const oldtop = lua_gettop( L); DeepPrelude* prelude = idfunc( L, eDO_new); if( prelude == NULL) { @@ -484,7 +481,7 @@ void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) { DeepPrelude** proxy; - STACK_CHECK( L); + STACK_CHECK( L, 0); // ensure it is actually a deep userdata if( get_idfunc( L, index, eLM_LaneBody) != idfunc) { diff --git a/src/keeper.c b/src/keeper.c index 0471cb7..ae3e2a8 100644 --- a/src/keeper.c +++ b/src/keeper.c @@ -166,10 +166,9 @@ static DECLARE_CONST_UNIQUE_KEY( FIFOS_KEY, 0xdce50bbc351cd465); static void push_table( lua_State* L, int idx_) { STACK_GROW( L, 4); - STACK_CHECK( L); + STACK_CHECK( L, 0); idx_ = lua_absindex( L, idx_); - push_unique_key( L, FIFOS_KEY); // ud fifos_key - lua_rawget( L, LUA_REGISTRYINDEX); // ud fifos + REGISTRY_GET( L, FIFOS_KEY); // ud fifos lua_pushvalue( L, idx_); // ud fifos ud lua_rawget( L, -2); // ud fifos fifos[ud] STACK_MID( L, 2); @@ -192,9 +191,8 @@ int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t lua_State* const KL = K ? K->L : NULL; if( KL == NULL) return 0; STACK_GROW( KL, 4); - STACK_CHECK( KL); - push_unique_key( KL, FIFOS_KEY); // fifos_key - lua_rawget( KL, LUA_REGISTRYINDEX); // fifos + STACK_CHECK( KL, 0); + REGISTRY_GET( KL, FIFOS_KEY); // fifos lua_pushlightuserdata( KL, ptr_); // fifos ud lua_rawget( KL, -2); // fifos storage lua_remove( KL, -2); // storage @@ -207,7 +205,7 @@ int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t // move data from keeper to destination state KEEPER MAIN lua_pushnil( KL); // storage nil STACK_GROW( L, 5); - STACK_CHECK( L); + STACK_CHECK( L, 0); lua_newtable( L); // out while( lua_next( KL, -2)) // storage key fifo { @@ -240,12 +238,13 @@ int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t int keepercall_clear( lua_State* L) { STACK_GROW( L, 3); - push_unique_key( L, FIFOS_KEY); // ud fifos_key - lua_rawget( L, LUA_REGISTRYINDEX); // ud fifos + STACK_CHECK( L, 0); + REGISTRY_GET( L, FIFOS_KEY); // ud fifos lua_pushvalue( L, 1); // ud fifos ud lua_pushnil( L); // ud fifos ud nil lua_rawset( L, -3); // ud fifos lua_pop( L, 1); // ud + STACK_END( L, 0); return 0; } @@ -634,11 +633,14 @@ void init_keepers( Universe* U, lua_State* L) void* allocUD; lua_Alloc allocF = lua_getallocf( L, &allocUD); - STACK_CHECK( L); // L K + STACK_CHECK( L, 0); // L K lua_getfield( L, 1, "nb_keepers"); // nb_keepers nb_keepers = (int) lua_tointeger( L, -1); lua_pop( L, 1); // - assert( nb_keepers >= 1); + if( nb_keepers < 1) + { + (void) luaL_error( L, "Bad number of keepers (%d)", nb_keepers); + } // Keepers contains an array of 1 s_Keeper, adjust for the actual number of keeper states { @@ -654,6 +656,7 @@ void init_keepers( Universe* U, lua_State* L) } for( i = 0; i < nb_keepers; ++ i) // keepersUD { + // note that we will leak K if we raise an error later lua_State* K = PROPAGATE_ALLOCF_ALLOC(); if( K == NULL) { @@ -667,10 +670,12 @@ void init_keepers( Universe* U, lua_State* L) // therefore, we need a recursive mutex. MUTEX_RECURSIVE_INIT( &U->keepers->keeper_array[i].keeper_cs); + STACK_CHECK( K, 0); + // copy the universe pointer in the keeper itself universe_store( K, U); + STACK_MID( K, 0); - STACK_CHECK( K); // make sure 'package' is initialized in keeper states, so that we have require() // this because this is needed when transferring deep userdata object luaL_requiref( K, "package", luaopen_package, 1); // package @@ -705,10 +710,7 @@ void init_keepers( Universe* U, lua_State* L) lua_setglobal( K, "decoda_name"); // // create the fifos table in the keeper state - push_unique_key( K, FIFOS_KEY); // fifo_key - lua_newtable( K); // fifo_key {} - lua_rawset( K, LUA_REGISTRYINDEX); // - + REGISTRY_SET( K, FIFOS_KEY, lua_newtable( K)); STACK_END( K, 0); } STACK_END( L, 0); diff --git a/src/lanes.c b/src/lanes.c index 037e44f..ae29af2 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -114,7 +114,7 @@ THE SOFTWARE. // intern the debug name in the specified lua state so that the pointer remains valid when the lane's state is closed static void securize_debug_threadname( lua_State* L, Lane* s) { - STACK_CHECK( L); + STACK_CHECK( L, 0); STACK_GROW( L, 3); lua_getuservalue( L, 1); lua_newtable( L); @@ -196,10 +196,9 @@ struct s_Linda; static bool_t push_registry_table( lua_State* L, UniqueKey key, bool_t create) { STACK_GROW( L, 3); - STACK_CHECK( L); - push_unique_key( L, key); // key - lua_rawget( L, LUA_REGISTRYINDEX); // t? + STACK_CHECK( L, 0); + REGISTRY_GET( L, key); // ? if( lua_isnil( L, -1)) // nil? { lua_pop( L, 1); // @@ -1179,7 +1178,7 @@ LUAG_FUNC( require) char const* name = lua_tostring( L, 1); int const nargs = lua_gettop( L); DEBUGSPEW_CODE( Universe* U = universe_get( L)); - STACK_CHECK( L); + STACK_CHECK( L, 0); DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s BEGIN\n" INDENT_END, name)); DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); lua_pushvalue( L, lua_upvalueindex(1)); // "name" require @@ -1204,7 +1203,7 @@ LUAG_FUNC( register) lua_settop( L, 2); luaL_argcheck( L, (mod_type == LUA_TTABLE) || (mod_type == LUA_TFUNCTION), 2, "unexpected module type"); DEBUGSPEW_CODE( Universe* U = universe_get( L)); - STACK_CHECK( L); // "name" mod_table + STACK_CHECK( L, 0); // "name" mod_table DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register %s BEGIN\n" INDENT_END, name)); DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); populate_func_lookup_table( L, -1, name); @@ -1265,10 +1264,10 @@ LUAG_FUNC( lane_new) L2 = luaG_newstate( U, L, libs_str); // L // L2 STACK_GROW( L2, nargs + 3); // - STACK_CHECK( L2); + STACK_CHECK( L2, 0); STACK_GROW( L, 3); // func libs cancelstep priority globals package required gc_cb [... args ...] - STACK_CHECK( L); + STACK_CHECK( L, 0); // give a default "Lua" name to the thread to see VM name in Decoda debugger lua_pushfstring( L2, "Lane #%p", L2); // "..." @@ -1409,7 +1408,7 @@ LUAG_FUNC( lane_new) } STACK_END( L, -nargs); ASSERT_L( lua_gettop( L) == FIXED_ARGS); - STACK_CHECK( L); + STACK_CHECK( L, 0); STACK_MID( L2, 1 + nargs); // 's' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread) @@ -1463,9 +1462,7 @@ LUAG_FUNC( lane_new) lua_setuservalue( L, -2); // func libs cancelstep priority globals package required gc_cb lane // Store 's' in the lane's registry, for 'cancel_test()' (even if 'cs'==0 we still do cancel tests at pending send/receive). - push_unique_key( L2, CANCEL_TEST_KEY); // func [... args ...] k - lua_pushlightuserdata( L2, s); // func [... args ...] k s - lua_rawset( L2, LUA_REGISTRYINDEX); // func [... args ...] + REGISTRY_SET( L2, CANCEL_TEST_KEY, lua_pushlightuserdata( L2, s)); // func [... args ...] if( cancelstep_idx) { @@ -1679,7 +1676,7 @@ LUAG_FUNC( thread_join) return 2; } - STACK_CHECK( L); + STACK_CHECK( L, 0); // Thread is DONE/ERROR_ST/CANCELLED; all ours now if( s->mstatus == KILLED) // OS thread was killed if thread_cancel was forced @@ -1961,7 +1958,7 @@ LUAG_FUNC( wakeup_conv ) // .yday (day of the year) // .isdst (daylight saving on/off) - STACK_CHECK( L); + STACK_CHECK( L, 0); 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); @@ -1975,7 +1972,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 @@ -2101,7 +2098,7 @@ LUAG_FUNC( configure) #endif // THREADAPI == THREADAPI_PTHREAD STACK_GROW( L, 4); - STACK_CHECK( L); + STACK_CHECK_ABS( L, 1); // settings DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() BEGIN\n" INDENT_END, L)); DEBUGSPEW_CODE( if( U) ++ U->debugspew_indent_depth); @@ -2121,7 +2118,7 @@ LUAG_FUNC( configure) } } lua_pop( L, 1); // settings - STACK_MID( L, 0); + STACK_MID( L, 1); // grab or create the universe if( U == NULL) @@ -2155,13 +2152,13 @@ LUAG_FUNC( configure) U->selfdestruct_first = SELFDESTRUCT_END; initialize_on_state_create( U, L); init_keepers( U, L); - STACK_MID( L, 0); + STACK_MID( L, 1); // Initialize 'timer_deep'; a common Linda object shared by all states lua_pushcfunction( L, LG_linda); // settings lanes.linda lua_pushliteral( L, "lanes-timer"); // settings lanes.linda "lanes-timer" lua_call( L, 1, 1); // settings linda - STACK_MID( L, 1); + STACK_MID( L, 2); // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer U->timer_deep = *(DeepPrelude**) lua_touserdata( L, -1); @@ -2169,7 +2166,7 @@ LUAG_FUNC( configure) ++ U->timer_deep->refcount; lua_pop( L, 1); // settings } - STACK_MID( L, 0); + STACK_MID( L, 1); // Serialize calls to 'require' from now on, also in the primary state serialize_require( DEBUGSPEW_PARAM_COMMA( U) L); @@ -2189,7 +2186,7 @@ LUAG_FUNC( configure) lua_setfield( L, -2, "threads"); // settings M } #endif // HAVE_LANE_TRACKING - STACK_MID( L, 1); + STACK_MID( L, 2); { char const* errmsg; @@ -2200,7 +2197,7 @@ LUAG_FUNC( configure) } lua_setfield( L, -2, "timer_gateway"); // settings M } - STACK_MID( L, 1); + STACK_MID( L, 2); // prepare the metatable for threads // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join, get_debug_threadname } @@ -2244,9 +2241,10 @@ LUAG_FUNC( configure) push_unique_key( L, CANCEL_ERROR); // settings M CANCEL_ERROR lua_setfield( L, -2, "cancel_error"); // settings M + STACK_MID( L, 2); // reference stack contains only the function argument 'settings' // we'll need this every time we transfer some C function from/to this state - lua_newtable( L); - lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); + REGISTRY_SET( L, LOOKUP_REGKEY, lua_newtable( L)); + STACK_MID( L, 2); // register all native functions found in that module in the transferable functions database // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) @@ -2264,11 +2262,11 @@ LUAG_FUNC( configure) populate_func_lookup_table( L, -1, NULL); lua_pop( L, 1); // settings M } - // set _R[CONFIG_REGKEY] = settings - lua_pushvalue( L, -2); // settings M settings - lua_setfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); // settings M - lua_pop( L, 1); // settings - STACK_END( L, 0); + lua_pop( L, 1); // settings + + // set _R[CONFIG_REGKEY] = settings + REGISTRY_SET( L, CONFIG_REGKEY, lua_pushvalue( L, -2)); // -2 because CONFIG_REGKEY is pushed before the value itself + STACK_END( L, 1); DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L)); DEBUGSPEW_CODE( -- U->debugspew_indent_depth); // Return the settings table @@ -2331,7 +2329,7 @@ int LANES_API luaopen_lanes_core( lua_State* L) #endif // defined PLATFORM_WIN32 && !defined NDEBUG STACK_GROW( L, 4); - STACK_CHECK( L); + STACK_CHECK( L, 0); // Create main module interface table // we only have 1 closure, which must be called to configure Lanes @@ -2339,7 +2337,7 @@ int LANES_API luaopen_lanes_core( lua_State* L) lua_pushvalue( L, 1); // M "lanes.core" lua_pushvalue( L, -2); // M "lanes.core" M lua_pushcclosure( L, LG_configure, 2); // M LG_configure() - lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); // M LG_configure() settings + REGISTRY_GET( L, CONFIG_REGKEY); // M LG_configure() settings if( !lua_isnil( L, -1)) // this is not the first require "lanes.core": call configure() immediately { lua_pushvalue( L, -1); // M LG_configure() settings settings @@ -2370,7 +2368,7 @@ static int default_luaopen_lanes( lua_State* L) // call this instead of luaopen_lanes_core() when embedding Lua and Lanes in a custom application void LANES_API luaopen_lanes_embedded( lua_State* L, lua_CFunction _luaopen_lanes) { - STACK_CHECK( L); + STACK_CHECK( L, 0); // pre-require lanes.core so that when lanes.lua calls require "lanes.core" it finds it is already loaded luaL_requiref( L, "lanes.core", luaopen_lanes_core, 0); // ... lanes.core lua_pop( L, 1); // ... diff --git a/src/lanes_private.h b/src/lanes_private.h index 1adfa31..16c178d 100644 --- a/src/lanes_private.h +++ b/src/lanes_private.h @@ -96,9 +96,8 @@ static inline Lane* get_lane_from_registry( lua_State* L) { Lane* s; STACK_GROW( L, 1); - STACK_CHECK( L); - push_unique_key( L, CANCEL_TEST_KEY); - lua_rawget( L, LUA_REGISTRYINDEX); + STACK_CHECK( L, 0); + REGISTRY_GET( L, CANCEL_TEST_KEY); s = lua_touserdata( L, -1); // lightuserdata (true 's_lane' pointer) / nil lua_pop( L, 1); STACK_END( L, 0); diff --git a/src/linda.c b/src/linda.c index ee60ebc..4d1fa9f 100644 --- a/src/linda.c +++ b/src/linda.c @@ -31,6 +31,7 @@ THE SOFTWARE. */ #include +#include #include "threading.h" #include "compat.h" @@ -171,7 +172,7 @@ LUAG_FUNC( linda_send) Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' if( KL == NULL) return 0; - STACK_CHECK( KL); + STACK_CHECK( KL, 0); for( ;;) { if( s != NULL) @@ -832,7 +833,7 @@ static void* linda_id( lua_State* L, DeepOp op_) case eDO_metatable: { - STACK_CHECK( L); + STACK_CHECK( L, 0); lua_newtable( L); // metatable is its own index lua_pushvalue( L, -1); @@ -892,10 +893,10 @@ static void* linda_id( lua_State* L, DeepOp op_) // some constants lua_pushliteral( L, BATCH_SENTINEL); - lua_setfield(L, -2, "batched"); + lua_setfield( L, -2, "batched"); push_unique_key( L, NIL_SENTINEL); - lua_setfield(L, -2, "null"); + lua_setfield( L, -2, "null"); STACK_END( L, 1); return NULL; diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h index 550fc0a..acbe690 100644 --- a/src/macros_and_utils.h +++ b/src/macros_and_utils.h @@ -46,26 +46,52 @@ extern char const* debugspew_indent; #ifdef NDEBUG -#define _ASSERT_L(lua,c) /*nothing*/ -#define STACK_CHECK(L) /*nothing*/ -#define STACK_MID(L,c) /*nothing*/ -#define STACK_END(L,c) /*nothing*/ -#define STACK_DUMP(L) /*nothing*/ +#define _ASSERT_L(lua,c) //nothing +#define STACK_CHECK(L,o) //nothing +#define STACK_CHECK_ABS(L,o) //nothing +#define STACK_MID(L,c) //nothing +#define STACK_END(L,c) //nothing +#define STACK_DUMP(L) //nothing #else // NDEBUG #define _ASSERT_L( L, cond_) if( (cond_) == 0) { (void) luaL_error( L, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #cond_);} -#define STACK_CHECK(L) { int const _oldtop_##L = lua_gettop( L) -#define STACK_MID(L,change) \ - do \ +#define STACK_CHECK( L, offset_) \ { \ - int stack_check_a = lua_gettop( L) - _oldtop_##L; \ - int stack_check_b = (change); \ - if( stack_check_a != stack_check_b) \ - luaL_error( L, "STACK ASSERT failed (%d not %d): %s:%d", stack_check_a, stack_check_b, __FILE__, __LINE__ ); \ - } while( 0) -#define STACK_END(L,change) STACK_MID(L,change); } + int const L##_delta = offset_; \ + if( (L##_delta < 0) || (lua_gettop( L) < L##_delta)) \ + { \ + assert( FALSE); \ + (void) luaL_error( L, "STACK INIT ASSERT failed (%d not %d): %s:%d", lua_gettop( L), L##_delta, __FILE__, __LINE__); \ + } \ + int const L##_oldtop = lua_gettop( L) - L##_delta + +#define STACK_CHECK_ABS( L, offset_) \ + { \ + int const L##_pos = offset_; \ + if( lua_gettop( L) < L##_pos) \ + { \ + assert( FALSE); \ + (void) luaL_error( L, "STACK INIT ASSERT failed (%d not %d): %s:%d", lua_gettop( L), L##_pos, __FILE__, __LINE__); \ + } \ + int const L##_oldtop = 0 + +#define STACK_MID( L, change) \ + do \ + { \ + int stack_check_a = lua_gettop( L) - L##_oldtop; \ + int stack_check_b = (change); \ + if( stack_check_a != stack_check_b) \ + { \ + assert( FALSE); \ + luaL_error( L, "STACK ASSERT failed (%d not %d): %s:%d", stack_check_a, stack_check_b, __FILE__, __LINE__); \ + } \ + } while( 0) + +#define STACK_END( L, change) \ + STACK_MID( L, change); \ + } #define STACK_DUMP( L) luaG_dump( L) @@ -75,4 +101,18 @@ extern char const* debugspew_indent; #define STACK_GROW( L, n) do { if (!lua_checkstack(L,(int)(n))) luaL_error( L, "Cannot grow stack!" ); } while( 0) +// non-string keyed registry access +#define REGISTRY_SET( L, key_, value_) \ +{ \ + push_unique_key( L, key_); \ + value_; \ + lua_rawset( L, LUA_REGISTRYINDEX); \ +} + +#define REGISTRY_GET( L, key_) \ +{ \ + push_unique_key( L, key_); \ + lua_rawget( L, LUA_REGISTRYINDEX); \ +} + #endif // MACROS_AND_UTILS_H diff --git a/src/tools.c b/src/tools.c index 6f71dd8..e54e0c0 100644 --- a/src/tools.c +++ b/src/tools.c @@ -32,6 +32,7 @@ THE SOFTWARE. */ #include +#include #include #include #include @@ -50,14 +51,11 @@ THE SOFTWARE. extern bool_t copydeep( Universe* U, lua_State* L, lua_State* L2, int index, LookupMode mode_); extern void push_registry_subtable( lua_State* L, void* key_); -char const* const CONFIG_REGKEY = "ee932492-a654-4506-9da8-f16540bdb5d4"; -char const* const LOOKUP_REGKEY = "ddea37aa-50c7-4d3f-8e0b-fb7a9d62bac5"; - DEBUGSPEW_CODE( char const* debugspew_indent = "----+----!----+----!----+----!----+----!----+----!----+----!----+----!----+"); /*---=== luaG_dump ===---*/ - +#ifdef _DEBUG void luaG_dump( lua_State* L) { int top = lua_gettop( L); @@ -79,7 +77,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, 0); STACK_GROW( L, 2); lua_getglobal( L, "tostring"); @@ -105,10 +103,11 @@ void luaG_dump( lua_State* L) } fprintf( stderr, "\n"); } +#endif // _DEBUG void initialize_on_state_create( Universe* U, lua_State* L) { - STACK_CHECK( L); + STACK_CHECK( L, 0); lua_getfield( L, -1, "on_state_create"); // settings on_state_create|nil if( !lua_isnil( L, -1)) { @@ -142,14 +141,19 @@ void initialize_on_state_create( Universe* U, lua_State* L) // just like lua_xmove, args are (from, to) static void copy_one_time_settings( Universe* U, lua_State* L, lua_State* L2) { - STACK_GROW( L, 1); + STACK_GROW( L, 2); + STACK_CHECK( L, 0); + STACK_CHECK( L2, 0); + REGISTRY_GET( L, CONFIG_REGKEY); // config // copy settings from from source to destination registry - lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); - if( luaG_inter_move( U, L, L2, 1, eLM_LaneBody) < 0) // error? + if( luaG_inter_move( U, L, L2, 1, eLM_LaneBody) < 0) // // config { (void) luaL_error( L, "failed to copy settings when loading lanes.core"); } - lua_setfield( L2, LUA_REGISTRYINDEX, CONFIG_REGKEY); + // set L2:_R[CONFIG_REGKEY] = settings + REGISTRY_SET( L2, CONFIG_REGKEY, lua_insert( L2, -2)); // + STACK_END( L2, 0); + STACK_END( L, 0); } @@ -212,7 +216,7 @@ static void open1lib( DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L, char con { bool_t const isLanesCore = (libfunc == require_lanes_core) ? TRUE : FALSE; // don't want to create a global for "lanes.core" DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening %.*s library\n" INDENT_END, (int) len_, name_)); - STACK_CHECK( L); + STACK_CHECK( L, 0); // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) luaL_requiref( L, name_, libfunc, !isLanesCore); // lanes.core doesn't declare a global, so scan it here and now @@ -301,7 +305,7 @@ static char const* luaG_pushFQN( lua_State* L, int t, int last, size_t* length) { int i = 1; luaL_Buffer b; - STACK_CHECK( L); + STACK_CHECK( L, 0); luaL_buffinit( L, &b); for( ; i < last; ++ i) { @@ -339,7 +343,7 @@ static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth) DEBUGSPEW_CODE( char const *newName); DEBUGSPEW_CODE( Universe* U = universe_get( L)); - STACK_CHECK( L); + STACK_CHECK( L, 0); // first, raise an error if the function is already known lua_pushvalue( L, -1); // ... {bfc} k o o lua_rawget( L, dest); // ... {bfc} k o name? @@ -412,7 +416,7 @@ 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 (or a full userdata with a metatable) - STACK_CHECK( L); // ... {_i} + STACK_CHECK( L, 0); // ... {_i} // if object is a userdata, replace it by its metatable if( lua_type( L, _i) == LUA_TUSERDATA) @@ -530,8 +534,9 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "NULL")); DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); STACK_GROW( L, 3); - STACK_CHECK( L); - lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // {} + STACK_CHECK( L, 0); + REGISTRY_GET( L, LOOKUP_REGKEY); // {} + STACK_MID( L, 1); ASSERT_L( lua_istable( L, -1)); if( lua_type( L, in_base) == LUA_TFUNCTION) // for example when a module is a simple function { @@ -585,12 +590,12 @@ void call_on_state_create( Universe* U, lua_State* L, lua_State* from_, LookupMo { if( U->on_state_create_func != NULL) { - STACK_CHECK( L); + STACK_CHECK( L, 0); DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END)); if( U->on_state_create_func != (lua_CFunction) initialize_on_state_create) { // C function: recreate a closure in the new state, bypassing the lookup scheme - lua_pushcfunction( L, U->on_state_create_func); + lua_pushcfunction( L, U->on_state_create_func); // on_state_create() } else // Lua function located in the config table, copied when we opened "lanes.core" { @@ -600,10 +605,12 @@ void call_on_state_create( Universe* U, lua_State* L, lua_State* from_, LookupMo // this doesn't count as an error though return; } - lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); - lua_getfield( L, -1, "on_state_create"); - lua_remove( L, -2); + REGISTRY_GET( L, CONFIG_REGKEY); // {} + STACK_MID( L, 1); + lua_getfield( L, -1, "on_state_create"); // {} on_state_create() + lua_remove( L, -2); // on_state_create() } + STACK_MID( L, 1); // capture error and raise it in caller state if( lua_pcall( L, 0, 0, 0) != LUA_OK) { @@ -640,16 +647,16 @@ lua_State* luaG_newstate( Universe* U, lua_State* from_, char const* libs_) } STACK_GROW( L, 2); + STACK_CHECK_ABS( L, 0); // copy the universe as a light userdata (only the master state holds the full userdata) // that way, if Lanes is required in this new state, we'll know we are part of this universe universe_store( L, U); - - STACK_CHECK( L); + STACK_MID( L, 0); // we'll need this every time we transfer some C function from/to this state - lua_newtable( L); - lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); + REGISTRY_SET( L, LOOKUP_REGKEY, lua_newtable( L)); + STACK_MID( L, 0); // neither libs (not even 'base') nor special init func: we are done if( libs_ == NULL && U->on_state_create_func == NULL) @@ -724,7 +731,7 @@ lua_State* luaG_newstate( Universe* U, lua_State* from_, char const* libs_) // will raise an error in from_ in case of problem call_on_state_create( U, L, from_, eLM_LaneBody); - STACK_CHECK( L); + STACK_CHECK( L, 0); // after all this, register everything we find 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); @@ -769,7 +776,7 @@ static uint_t get_mt_id( Universe* U, lua_State* L, int i) STACK_GROW( L, 3); - STACK_CHECK( L); + STACK_CHECK( L, 0); push_registry_subtable( L, REG_MTID); lua_pushvalue( L, i); lua_rawget( L, -2); @@ -839,7 +846,7 @@ static char const* find_lookup_name( lua_State* L, uint_t i, LookupMode mode_, c DEBUGSPEW_CODE( Universe* const U = universe_get( L)); char const* fqn; ASSERT_L( lua_isfunction( L, i) || lua_istable( L, i)); // ... v ... - STACK_CHECK( L); + STACK_CHECK( L, 0); STACK_GROW( L, 3); // up to 3 slots are necessary on error if( mode_ == eLM_FromKeeper) { @@ -859,7 +866,8 @@ static char const* find_lookup_name( lua_State* L, uint_t i, LookupMode mode_, c else { // fetch the name from the source state's lookup table - lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // ... v ... {} + REGISTRY_GET( L, LOOKUP_REGKEY); // ... v ... {} + STACK_MID( L, 1); ASSERT_L( lua_istable( L, -1)); lua_pushvalue( L, i); // ... v ... {} v lua_rawget( L, -2); // ... v ... {} "f.q.n" @@ -915,7 +923,7 @@ static bool_t lookup_table( lua_State* L2, lua_State* L, uint_t i, LookupMode mo return FALSE; } // push the equivalent table in the destination's stack, retrieved from the lookup table - STACK_CHECK( L2); // L // L2 + STACK_CHECK( L2, 0); // L // L2 STACK_GROW( L2, 3); // up to 3 slots are necessary on error switch( mode_) { @@ -931,7 +939,8 @@ static bool_t lookup_table( lua_State* L2, lua_State* L, uint_t i, LookupMode mo case eLM_LaneBody: case eLM_FromKeeper: - lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // {} + REGISTRY_GET( L2, LOOKUP_REGKEY); // {} + STACK_MID( L2, 1); ASSERT_L( lua_istable( L2, -1)); lua_pushlstring( L2, fqn, len); // {} "f.q.n" lua_rawget( L2, -2); // {} t @@ -987,7 +996,7 @@ static bool_t push_cached_table( lua_State* L2, uint_t L2_cache_i, lua_State* L, ASSERT_L( L2_cache_i != 0); STACK_GROW( L2, 3); - STACK_CHECK( L2); + STACK_CHECK( L2, 0); // 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). @@ -1027,7 +1036,7 @@ static int discover_object_name_recur( lua_State* L, int shortest_, int depth_) return shortest_; } STACK_GROW( L, 3); - STACK_CHECK( L); + STACK_CHECK( L, 0); // 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 @@ -1170,7 +1179,7 @@ int luaG_nameof( lua_State* L) } STACK_GROW( L, 4); - STACK_CHECK( L); + STACK_CHECK( L, 0); // this slot will contain the shortest name we found when we are done lua_pushnil( L); // o nil // push a cache that will contain all already visited tables @@ -1207,7 +1216,7 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, LookupMod size_t len; char const* fqn = find_lookup_name( L, i, mode_, upName_, &len); // push the equivalent function in the destination's stack, retrieved from the lookup table - STACK_CHECK( L2); // L // L2 + STACK_CHECK( L2, 0); // L // L2 STACK_GROW( L2, 3); // up to 3 slots are necessary on error switch( mode_) { @@ -1223,7 +1232,8 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, LookupMod case eLM_LaneBody: case eLM_FromKeeper: - lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // {} + REGISTRY_GET( L2, LOOKUP_REGKEY); // {} + STACK_MID( L2, 1); ASSERT_L( lua_istable( L2, -1)); lua_pushlstring( L2, fqn, len); // {} "f.q.n" lua_rawget( L2, -2); // {} f @@ -1290,7 +1300,7 @@ static void inter_copy_func( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_ luaL_Buffer b; ASSERT_L( L2_cache_i != 0); // ... {cache} ... p STACK_GROW( L, 2); - STACK_CHECK( L); + STACK_CHECK( L, 0); // 'lua_dump()' needs the function at top of stack // if already on top of the stack, no need to push again @@ -1447,7 +1457,7 @@ static void push_cached_func( Universe* U, lua_State* L2, uint_t L2_cache_i, lua // L2_cache[id_str]= function // - STACK_CHECK( L2); + STACK_CHECK( L2, 0); // 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). @@ -1492,7 +1502,7 @@ static bool_t push_cached_metatable( Universe* U, lua_State* L2, uint_t L2_cache { uint_t const mt_id = get_mt_id( U, L, -1); // Unique id for the metatable - STACK_CHECK( L2); + STACK_CHECK( L2, 0); STACK_GROW( L2, 4); // do we already know this metatable? push_registry_subtable( L2, REG_MTID); // rst @@ -1605,8 +1615,8 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu bool_t ret = TRUE; int val_type = lua_type( L, i); STACK_GROW( L2, 1); - STACK_CHECK( L); // L // L2 - STACK_CHECK( L2); // L // L2 + STACK_CHECK( L, 0); // L // L2 + STACK_CHECK( L2, 0); // L // L2 /* Skip the object if it has metatable with { __lanesignore = true } */ if( lua_getmetatable( L, i)) // ... mt @@ -1618,6 +1628,7 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu } lua_pop( L, 2); // ... } + STACK_MID( L, 0); /* Lets push nil to L2 if the object should be ignored */ switch( val_type) @@ -1786,7 +1797,7 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu { DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "FUNCTION %s\n" INDENT_END, upName_)); DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); - STACK_CHECK( L2); + STACK_CHECK( L2, 0); push_cached_func( U, L2, L2_cache_i, L, i, mode_, upName_); STACK_END( L2, 1); DEBUGSPEW_CODE( -- U->debugspew_indent_depth); @@ -1800,8 +1811,8 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu break; } { - STACK_CHECK( L); - STACK_CHECK( L2); + STACK_CHECK( L, 0); + STACK_CHECK( L2, 0); /* * First, let's try to see if this table is special (aka is it some table that we registered in our lookup databases during module registration?) @@ -1943,8 +1954,8 @@ int luaG_inter_copy_package( Universe* U, lua_State* L, lua_State* L2, int packa DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_inter_copy_package()\n" INDENT_END)); DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); // package - STACK_CHECK( L); - STACK_CHECK( L2); + STACK_CHECK( L, 0); + STACK_CHECK( L2, 0); package_idx_ = lua_absindex( L, package_idx_); if( lua_type( L, package_idx_) != LUA_TTABLE) { @@ -2009,7 +2020,7 @@ int luaG_new_require( lua_State* L) //char const* modname = luaL_checkstring( L, 1); STACK_GROW( L, args + 1); - STACK_CHECK( L); + STACK_CHECK( L, 0); lua_pushvalue( L, lua_upvalueindex( 1)); for( i = 1; i <= args; ++ i) @@ -2041,7 +2052,7 @@ int luaG_new_require( lua_State* L) void serialize_require( DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L) { STACK_GROW( L, 1); - STACK_CHECK( L); + STACK_CHECK( L, 0); DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "serializing require()\n" INDENT_END)); // Check 'require' is there and not already wrapped; if not, do nothing diff --git a/src/tools.h b/src/tools.h index 84e323c..ca0b9fc 100644 --- a/src/tools.h +++ b/src/tools.h @@ -18,7 +18,9 @@ typedef struct s_Universe Universe; #define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d)) #define luaG_tounsigned(L,i) ((uint_t) lua_tointeger(L,i)) -void luaG_dump( lua_State* L ); +#ifdef _DEBUG +void luaG_dump( lua_State* L); +#endif // _DEBUG lua_State* luaG_newstate( Universe* U, lua_State* _from, char const* libs); @@ -39,7 +41,10 @@ void call_on_state_create( Universe* U, lua_State* L, lua_State* from_, LookupMo // ################################################################################################ -extern char const* const CONFIG_REGKEY; -extern char const* const LOOKUP_REGKEY; +// crc64/we of string "CONFIG_REGKEY" generated at http://www.nitrxgen.net/hashgen/ +static DECLARE_CONST_UNIQUE_KEY( CONFIG_REGKEY, 0x31cd24894eae8624); // 'cancel_error' sentinel + +// crc64/we of string "LOOKUP_REGKEY" generated at http://www.nitrxgen.net/hashgen/ +static DECLARE_CONST_UNIQUE_KEY( LOOKUP_REGKEY, 0x5051ed67ee7b51a1); // 'cancel_error' sentinel #endif // __LANES_TOOLS_H__ diff --git a/src/universe.c b/src/universe.c index 4689a09..d531bf2 100644 --- a/src/universe.c +++ b/src/universe.c @@ -29,6 +29,7 @@ THE SOFTWARE. */ #include +#include #include "universe.h" #include "compat.h" @@ -44,9 +45,9 @@ Universe* universe_create( lua_State* L) { Universe* U = (Universe*) lua_newuserdata( L, sizeof(Universe)); // universe memset( U, 0, sizeof( Universe)); - push_unique_key( L, UNIVERSE_REGKEY); // universe UNIVERSE_REGKEY - lua_pushvalue( L, -2); // universe UNIVERSE_REGKEY universe - lua_rawset( L, LUA_REGISTRYINDEX); // universe + STACK_CHECK( L, 1); + REGISTRY_SET( L, UNIVERSE_REGKEY, lua_pushvalue(L, -2)); // universe + STACK_END( L, 1); return U; } @@ -54,17 +55,8 @@ Universe* universe_create( lua_State* L) void universe_store( lua_State* L, Universe* U) { - STACK_CHECK( L); - push_unique_key( L, UNIVERSE_REGKEY); - if( NULL != U) - { - lua_pushlightuserdata( L, U); - } - else - { - lua_pushnil( L); - } - lua_rawset( L, LUA_REGISTRYINDEX); + STACK_CHECK( L, 0); + REGISTRY_SET( L, UNIVERSE_REGKEY, (NULL != U) ? lua_pushlightuserdata( L, U) : lua_pushnil( L)); STACK_END( L, 0); } @@ -74,9 +66,8 @@ Universe* universe_get( lua_State* L) { Universe* universe; STACK_GROW( L, 2); - STACK_CHECK( L); - push_unique_key( L, UNIVERSE_REGKEY); - lua_rawget( L, LUA_REGISTRYINDEX); + STACK_CHECK( L, 0); + REGISTRY_GET( L, UNIVERSE_REGKEY); universe = lua_touserdata( L, -1); // NULL if nil lua_pop( L, 1); STACK_END( L, 0); -- cgit v1.2.3-55-g6feb