From bbb4f99918d00308b52af3289c29624bfeb0066b Mon Sep 17 00:00:00 2001 From: Benoit Germain <benoit.germain@ubisoft.com> Date: Tue, 16 Apr 2024 18:06:02 +0200 Subject: some dead code elimination and other trifles --- src/cancel.cpp | 38 +-- src/cancel.h | 12 +- src/compat.cpp | 39 ++- src/deep.cpp | 56 ++--- src/deep.h | 2 +- src/keeper.cpp | 60 ++--- src/lanes.cpp | 329 +++++++++++------------- src/lanes_private.h | 2 +- src/macros_and_utils.h | 4 +- src/state.cpp | 36 ++- src/state.h | 4 +- src/threading.cpp | 20 +- src/threading.h | 18 +- src/tools.cpp | 669 ++++++++++++++++++++++--------------------------- src/tools.h | 48 ++-- src/uniquekey.h | 2 + src/universe.cpp | 10 +- src/universe.h | 13 +- 18 files changed, 634 insertions(+), 728 deletions(-) (limited to 'src') diff --git a/src/cancel.cpp b/src/cancel.cpp index b3e52b6..fe1f3e6 100644 --- a/src/cancel.cpp +++ b/src/cancel.cpp @@ -39,8 +39,8 @@ THE SOFTWARE. #include "threading.h" #include "tools.h" -// ################################################################################################ -// ################################################################################################ +// ################################################################################################# +// ################################################################################################# /* * Check if the thread in question ('L') has been signalled for cancel. @@ -58,7 +58,7 @@ THE SOFTWARE. return lane ? lane->cancel_request : CancelRequest::None; } -// ################################################################################################ +// ################################################################################################# //--- // bool = cancel_test() @@ -66,15 +66,15 @@ THE SOFTWARE. // Available inside the global namespace of lanes // returns a boolean saying if a cancel request is pending // -LUAG_FUNC( cancel_test) +LUAG_FUNC(cancel_test) { CancelRequest test{ cancel_test(L) }; lua_pushboolean(L, test != CancelRequest::None); return 1; } -// ################################################################################################ -// ################################################################################################ +// ################################################################################################# +// ################################################################################################# [[nodiscard]] static void cancel_hook(lua_State* L, [[maybe_unused]] lua_Debug* ar) { @@ -86,8 +86,8 @@ LUAG_FUNC( cancel_test) } } -// ################################################################################################ -// ################################################################################################ +// ################################################################################################# +// ################################################################################################# //--- // = thread_cancel( lane_ud [,timeout_secs=0.0] [,wake_lindas_bool=false] ) @@ -106,7 +106,7 @@ LUAG_FUNC( cancel_test) // false if the cancellation timed out, or a kill was needed. // -// ################################################################################################ +// ################################################################################################# [[nodiscard]] static CancelResult thread_cancel_soft(Lane* lane_, lua_Duration duration_, bool wake_lane_) { @@ -124,7 +124,7 @@ LUAG_FUNC( cancel_test) return lane_->waitForCompletion(duration_) ? CancelResult::Cancelled : CancelResult::Timeout; } -// ################################################################################################ +// ################################################################################################# [[nodiscard]] static CancelResult thread_cancel_hard(Lane* lane_, lua_Duration duration_, bool wake_lane_) { @@ -143,7 +143,7 @@ LUAG_FUNC( cancel_test) return result; } -// ################################################################################################ +// ################################################################################################# CancelResult thread_cancel(Lane* lane_, CancelOp op_, int hook_count_, lua_Duration duration_, bool wake_lane_) { @@ -169,8 +169,8 @@ CancelResult thread_cancel(Lane* lane_, CancelOp op_, int hook_count_, lua_Durat return thread_cancel_hard(lane_, duration_, wake_lane_); } -// ################################################################################################ -// ################################################################################################ +// ################################################################################################# +// ################################################################################################# CancelOp which_cancel_op(char const* op_string_) { @@ -202,7 +202,7 @@ CancelOp which_cancel_op(char const* op_string_) return op; } -// ################################################################################################ +// ################################################################################################# [[nodiscard]] static CancelOp which_cancel_op(lua_State* L, int idx_) { @@ -220,12 +220,12 @@ CancelOp which_cancel_op(char const* op_string_) return CancelOp::Hard; } -// ################################################################################################ +// ################################################################################################# // bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, wake_lindas]) LUAG_FUNC(thread_cancel) { - Lane* const lane{ lua_toLane(L, 1) }; + Lane* const lane{ ToLane(L, 1) }; CancelOp const op{ which_cancel_op(L, 2) }; // this removes the op string from the stack int hook_count{ 0 }; @@ -235,7 +235,7 @@ LUAG_FUNC(thread_cancel) lua_remove(L, 2); // argument is processed, remove it if (hook_count < 1) { - return luaL_error(L, "hook count cannot be < 1"); + return luaL_error(L, "hook count cannot be < 1"); // doesn't return } } @@ -246,7 +246,7 @@ LUAG_FUNC(thread_cancel) lua_remove(L, 2); // argument is processed, remove it if (wait_timeout.count() < 0.0) { - return luaL_error(L, "cancel timeout cannot be < 0"); + return luaL_error(L, "cancel timeout cannot be < 0"); // doesn't return } } // we wake by default in "hard" mode (remember that hook is hard too), but this can be turned off if desired @@ -255,7 +255,7 @@ LUAG_FUNC(thread_cancel) { if (!lua_isboolean(L, 2)) { - return luaL_error(L, "wake_lindas parameter is not a boolean"); + return luaL_error(L, "wake_lindas parameter is not a boolean"); // doesn't return } wake_lane = lua_toboolean(L, 2); lua_remove(L, 2); // argument is processed, remove it diff --git a/src/cancel.h b/src/cancel.h index 10a9804..8cff1c9 100644 --- a/src/cancel.h +++ b/src/cancel.h @@ -10,12 +10,10 @@ extern "C" { } #endif // __cplusplus -#include "uniquekey.h" #include "macros_and_utils.h" +#include "uniquekey.h" -#include <chrono> - -// ################################################################################################ +// ################################################################################################# class Lane; // forward @@ -59,10 +57,10 @@ static constexpr UniqueKey CANCEL_ERROR{ 0xe97d41626cc97577ull, "lanes.cancel_er raise_lua_error(L); // doesn't return } -// ################################################################################################ -// ################################################################################################ +// ################################################################################################# +// ################################################################################################# LUAG_FUNC(cancel_test); LUAG_FUNC(thread_cancel); -// ################################################################################################ +// ################################################################################################# diff --git a/src/compat.cpp b/src/compat.cpp index 73d0f6b..9f652a7 100644 --- a/src/compat.cpp +++ b/src/compat.cpp @@ -1,20 +1,17 @@ -/* - * ############################################################################################### - * ####################################### Lua 5.1/5.2/5.3 ####################################### - * ############################################################################################### - */ +// ################################################################################################# +// ###################################### Lua 5.1 / 5.2 / 5.3 ###################################### +// ################################################################################################# + #include "compat.h" #include "macros_and_utils.h" -/* -** Copied from Lua 5.2 loadlib.c -*/ -// ################################################################################################ -// ################################################################################################ +// ################################################################################################# +// ################################################################################################# #if LUA_VERSION_NUM == 501 -// ################################################################################################ -// ################################################################################################ +// ################################################################################################# +// ################################################################################################# +// Copied from Lua 5.2 loadlib.c static int luaL_getsubtable(lua_State* L, int idx, const char* fname) { lua_getfield(L, idx, fname); @@ -31,7 +28,7 @@ static int luaL_getsubtable(lua_State* L, int idx, const char* fname) } } -// ################################################################################################ +// ################################################################################################# void luaL_requiref(lua_State *L, const char *modname, lua_CFunction openf, int glb) { @@ -50,11 +47,11 @@ void luaL_requiref(lua_State *L, const char *modname, lua_CFunction openf, int g } #endif // LUA_VERSION_NUM -// ################################################################################################ -// ################################################################################################ +// ################################################################################################# +// ################################################################################################# #if LUA_VERSION_NUM < 504 -// ################################################################################################ -// ################################################################################################ +// ################################################################################################# +// ################################################################################################# void* lua_newuserdatauv( lua_State* L, size_t sz, int nuvalue) { @@ -62,13 +59,13 @@ void* lua_newuserdatauv( lua_State* L, size_t sz, int nuvalue) return lua_newuserdata(L, sz); } -// ################################################################################################ +// ################################################################################################# // push on stack uservalue #n of full userdata at idx int lua_getiuservalue(lua_State* L, int idx, int n) { // full userdata can have only 1 uservalue before 5.4 - if( n > 1) + if (n > 1) { lua_pushnil(L); return LUA_TNONE; @@ -91,13 +88,13 @@ int lua_getiuservalue(lua_State* L, int idx, int n) return lua_type(L, -1); } -// ################################################################################################ +// ################################################################################################# // Pops a value from the stack and sets it as the new n-th user value associated to the full userdata at the given index. // Returns 0 if the userdata does not have that value. int lua_setiuservalue(lua_State* L, int idx, int n) { - if( n > 1 + if (n > 1 #if LUA_VERSION_NUM == 501 || lua_type(L, -1) != LUA_TTABLE #endif diff --git a/src/deep.cpp b/src/deep.cpp index 3eb38dc..3326f98 100644 --- a/src/deep.cpp +++ b/src/deep.cpp @@ -81,7 +81,7 @@ static void set_deep_lookup(lua_State* L) STACK_CHECK( L, 0); } -// ################################################################################################ +// ################################################################################################# /* * Pops the key (metatable or factory) off the stack, and replaces with the @@ -92,7 +92,7 @@ static void get_deep_lookup(lua_State* L) STACK_GROW( L, 1); STACK_CHECK_START_REL(L, 1); // a DEEP_LOOKUP_KEY.pushValue(L); // a {} - if( !lua_isnil( L, -1)) + if (!lua_isnil( L, -1)) { lua_insert( L, -2); // {} a lua_rawget( L, -2); // {} b @@ -101,7 +101,7 @@ static void get_deep_lookup(lua_State* L) STACK_CHECK( L, 1); } -// ################################################################################################ +// ################################################################################################# /* * Return the registered factory for 'index' (deep userdata proxy), @@ -124,7 +124,7 @@ static void get_deep_lookup(lua_State* L) STACK_GROW( L, 1); STACK_CHECK_START_REL(L, 0); - if( !lua_getmetatable( L, index)) // deep ... metatable? + if (!lua_getmetatable( L, index)) // deep ... metatable? { return nullptr; // no metatable: can't be a deep userdata object! } @@ -139,7 +139,7 @@ static void get_deep_lookup(lua_State* L) } } -// ################################################################################################ +// ################################################################################################# void DeepFactory::DeleteDeepObject(lua_State* L, DeepPrelude* o_) { @@ -148,7 +148,7 @@ void DeepFactory::DeleteDeepObject(lua_State* L, DeepPrelude* o_) STACK_CHECK(L, 0); } -// ################################################################################################ +// ################################################################################################# /* * void= mt.__gc( proxy_ud ) @@ -169,7 +169,7 @@ void DeepFactory::DeleteDeepObject(lua_State* L, DeepPrelude* o_) { // retrieve wrapped __gc lua_pushvalue( L, lua_upvalueindex( 1)); // self __gc? - if( !lua_isnil( L, -1)) + if (!lua_isnil( L, -1)) { lua_insert( L, -2); // __gc self lua_call( L, 1, 0); // @@ -180,7 +180,7 @@ void DeepFactory::DeleteDeepObject(lua_State* L, DeepPrelude* o_) return 0; } -// ################################################################################################ +// ################################################################################################# /* * Push a proxy userdata on the stack. @@ -194,25 +194,25 @@ void DeepFactory::DeleteDeepObject(lua_State* L, DeepPrelude* o_) char const* DeepFactory::PushDeepProxy(Dest L, DeepPrelude* prelude, int nuv_, LookupMode mode_) { // Check if a proxy already exists - push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC - lua_pushlightuserdata( L, prelude); // DPC deep - lua_rawget( L, -2); // DPC proxy - if ( !lua_isnil( L, -1)) + push_registry_subtable_mode(L, DEEP_PROXY_CACHE_KEY, "v"); // DPC + lua_pushlightuserdata(L, prelude); // DPC deep + lua_rawget(L, -2); // DPC proxy + if (!lua_isnil(L, -1)) { - lua_remove( L, -2); // proxy + lua_remove(L, -2); // proxy return nullptr; } else { - lua_pop( L, 1); // DPC + lua_pop(L, 1); // DPC } - STACK_GROW( L, 7); + STACK_GROW(L, 7); STACK_CHECK_START_REL(L, 0); // a new full userdata, fitted with the specified number of uservalue slots (always 1 for Lua < 5.4) - DeepPrelude** proxy = (DeepPrelude**) lua_newuserdatauv(L, sizeof(DeepPrelude*), nuv_); // DPC proxy - ASSERT_L( proxy); + DeepPrelude** const proxy{ lua_newuserdatauv<DeepPrelude*>(L, nuv_) }; // DPC proxy + ASSERT_L(proxy); *proxy = prelude; prelude->m_refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data @@ -221,7 +221,7 @@ char const* DeepFactory::PushDeepProxy(Dest L, DeepPrelude* prelude, int nuv_, L lua_pushlightuserdata( L, std::bit_cast<void*>(&factory)); // DPC proxy factory get_deep_lookup( L); // DPC proxy metatable? - if( lua_isnil( L, -1)) // // No metatable yet. + if (lua_isnil( L, -1)) // // No metatable yet. { lua_pop(L, 1); // DPC proxy int const oldtop{ lua_gettop(L) }; @@ -245,7 +245,7 @@ char const* DeepFactory::PushDeepProxy(Dest L, DeepPrelude* prelude, int nuv_, L 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 @@ -269,22 +269,22 @@ char const* DeepFactory::PushDeepProxy(Dest L, DeepPrelude* prelude, int nuv_, L // L.registry._LOADED exists without having registered the 'package' library. lua_getglobal( L, "require"); // DPC proxy metatable require() // check that the module is already loaded (or being loaded, we are happy either way) - if( lua_isfunction( L, -1)) + if (lua_isfunction( L, -1)) { lua_pushstring( L, modname); // DPC proxy metatable require() "module" lua_getfield( L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); // DPC proxy metatable require() "module" _R._LOADED - if( lua_istable( L, -1)) + if (lua_istable( L, -1)) { lua_pushvalue( L, -2); // DPC proxy metatable require() "module" _R._LOADED "module" lua_rawget( L, -2); // DPC proxy metatable require() "module" _R._LOADED module int const alreadyloaded = lua_toboolean( L, -1); - if( !alreadyloaded) // not loaded + if (!alreadyloaded) // not loaded { int require_result; lua_pop( L, 2); // DPC proxy metatable require() "module" // require "modname" require_result = lua_pcall( L, 1, 0, 0); // DPC proxy metatable error? - if( require_result != LUA_OK) + if (require_result != LUA_OK) { // failed, return the error message lua_pushfstring( L, "error while requiring '%s' identified by DeepFactory::moduleName: ", modname); @@ -326,7 +326,7 @@ char const* DeepFactory::PushDeepProxy(Dest L, DeepPrelude* prelude, int nuv_, L return nullptr; } -// ################################################################################################ +// ################################################################################################# /* * Create a deep userdata @@ -354,7 +354,7 @@ int DeepFactory::pushDeepUserdata(Dest L, int nuv_) const return luaL_error( L, "DeepFactory::newDeepObjectInternal failed to create deep userdata (out of memory)"); } - if( prelude->m_magic != DEEP_VERSION) + if (prelude->m_magic != DEEP_VERSION) { // just in case, don't leak the newly allocated deep userdata object deleteDeepObjectInternal(L, prelude); @@ -364,7 +364,7 @@ int DeepFactory::pushDeepUserdata(Dest L, int nuv_) const ASSERT_L(prelude->m_refcount.load(std::memory_order_relaxed) == 0); // 'DeepFactory::PushDeepProxy' will lift it to 1 ASSERT_L(&prelude->m_factory == this); - if( lua_gettop( L) - oldtop != 0) + if (lua_gettop( L) - oldtop != 0) { // just in case, don't leak the newly allocated deep userdata object deleteDeepObjectInternal(L, prelude); @@ -380,7 +380,7 @@ int DeepFactory::pushDeepUserdata(Dest L, int nuv_) const return 1; } -// ################################################################################################ +// ################################################################################################# /* * Access deep userdata through a proxy. @@ -402,7 +402,7 @@ DeepPrelude* DeepFactory::toDeep(lua_State* L, int index) const return *proxy; } -// ################################################################################################ +// ################################################################################################# /* * Copy deep userdata between two separate Lua states (from L to L2) diff --git a/src/deep.h b/src/deep.h index 27aed8f..3256e6e 100644 --- a/src/deep.h +++ b/src/deep.h @@ -28,7 +28,7 @@ enum class LookupMode FromKeeper // send a function from a keeper state to a lane }; -// ################################################################################################ +// ################################################################################################# // xxh64 of string "DEEP_VERSION_3" generated at https://www.pelock.com/products/hash-calculator static constexpr UniqueKey DEEP_VERSION{ 0xB2CC0FD9C0AE9674ull, "DEEP_VERSION_3" }; diff --git a/src/keeper.cpp b/src/keeper.cpp index 3e26d5e..5d94944 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp @@ -48,9 +48,9 @@ #include <algorithm> #include <cassert> -// ################################################################################### +// ################################################################################################# // Keeper implementation -// ################################################################################### +// ################################################################################################# class keeper_fifo { @@ -74,7 +74,7 @@ class keeper_fifo static constexpr int CONTENTS_TABLE{ 1 }; -// ################################################################################################## +// ################################################################################################# // replaces the fifo ud by its uservalue on the stack [[nodiscard]] static keeper_fifo* prepare_fifo_access(lua_State* L, int idx_) @@ -91,7 +91,7 @@ static constexpr int CONTENTS_TABLE{ 1 }; return fifo; } -// ################################################################################################## +// ################################################################################################# // in: nothing // out: { first = 1, count = 0, limit = -1} @@ -107,7 +107,7 @@ static constexpr int CONTENTS_TABLE{ 1 }; return fifo; } -// ################################################################################################## +// ################################################################################################# // in: expect fifo ... on top of the stack // out: nothing, removes all pushed values from the stack @@ -124,7 +124,7 @@ static void fifo_push(lua_State* L, keeper_fifo* fifo_, int count_) fifo_->count += count_; } -// ################################################################################################## +// ################################################################################################# // in: fifo // out: ...|nothing @@ -140,7 +140,7 @@ static void fifo_peek(lua_State* L, keeper_fifo* fifo_, int count_) } } -// ################################################################################################## +// ################################################################################################# // in: fifo // out: remove the fifo from the stack, push as many items as required on the stack (function assumes they exist in sufficient number) @@ -177,7 +177,7 @@ static void fifo_pop( lua_State* L, keeper_fifo* fifo_, int count_) } } -// ################################################################################################## +// ################################################################################################# // in: linda_ud expected at stack slot idx // out: fifos[ud] @@ -205,7 +205,7 @@ static void push_table(lua_State* L, int idx_) STACK_CHECK(L, 1); } -// ################################################################################################## +// ################################################################################################# int keeper_push_linda_storage(Universe* U, Dest L, void* ptr_, uintptr_t magic_) { @@ -258,7 +258,7 @@ int keeper_push_linda_storage(Universe* U, Dest L, void* ptr_, uintptr_t magic_) return 1; } -// ################################################################################################## +// ################################################################################################# // in: linda_ud int keepercall_clear(lua_State* L) @@ -274,7 +274,7 @@ int keepercall_clear(lua_State* L) return 0; } -// ################################################################################################## +// ################################################################################################# // in: linda_ud, key, ... // out: true|false @@ -285,7 +285,7 @@ int keepercall_send(lua_State* L) // get the fifo associated to this key in this linda, create it if it doesn't exist lua_pushvalue(L, 2); // ud key ... fifos key lua_rawget(L, -2); // ud key ... fifos fifo - if( lua_isnil(L, -1)) + if (lua_isnil(L, -1)) { lua_pop(L, 1); // ud key ... fifos std::ignore = fifo_new(L); // ud key ... fifos fifo @@ -311,7 +311,7 @@ int keepercall_send(lua_State* L) return 1; } -// ################################################################################################## +// ################################################################################################# // in: linda_ud, key [, key]? // out: (key, val) or nothing @@ -347,13 +347,13 @@ int keepercall_receive(lua_State* L) return 0; } -// ################################################################################################## +// ################################################################################################# // in: linda_ud key mincount [maxcount] int keepercall_receive_batched(lua_State* L) { int const min_count{ static_cast<int>(lua_tointeger(L, 3)) }; - if( min_count > 0) + if (min_count > 0) { int const max_count{ static_cast<int>(luaL_optinteger(L, 4, min_count)) }; lua_settop(L, 2); // ud key @@ -364,7 +364,7 @@ int keepercall_receive_batched(lua_State* L) lua_rawget(L, 2); // key fifos fifo lua_remove(L, 2); // key fifo keeper_fifo* const fifo{ prepare_fifo_access(L, 2) }; // key fifotbl - if( fifo != nullptr && fifo->count >= min_count) + if (fifo != nullptr && fifo->count >= min_count) { fifo_pop(L, fifo, std::min( max_count, fifo->count)); // key ... } @@ -380,7 +380,7 @@ int keepercall_receive_batched(lua_State* L) } } -// ################################################################################################## +// ################################################################################################# // in: linda_ud key n // out: true or nil @@ -403,7 +403,7 @@ int keepercall_limit(lua_State* L) lua_settop(L, 0); // return true if we decide that blocked threads waiting to write on that key should be awakened // this is the case if we detect the key was full but it is no longer the case - if( + if ( ((fifo->limit >= 0) && (fifo->count >= fifo->limit)) // the key was full if limited and count exceeded the previous limit && ((limit < 0) || (fifo->count < limit)) // the key is not full if unlimited or count is lower than the new limit ) @@ -416,7 +416,7 @@ int keepercall_limit(lua_State* L) return lua_gettop(L); } -// ################################################################################################## +// ################################################################################################# // in: linda_ud key [[val] ...] //out: true if the linda was full but it's no longer the case, else nothing @@ -462,7 +462,7 @@ int keepercall_set(lua_State* L) lua_pushvalue(L, 2); // fifos key [val [, ...]] key lua_rawget(L, 1); // fifos key [val [, ...]] fifo|nil keeper_fifo* fifo{ keeper_fifo::getPtr(L, -1) }; - if( fifo == nullptr) // can be nullptr if we store a value at a new key + if (fifo == nullptr) // can be nullptr if we store a value at a new key { // fifos key [val [, ...]] nil // no need to wake writers in that case, because a writer can't wait on an inexistent key lua_pop(L, 1); // fifos key [val [, ...]] @@ -489,7 +489,7 @@ int keepercall_set(lua_State* L) return should_wake_writers ? (lua_pushboolean(L, 1), 1) : 0; } -// ################################################################################################## +// ################################################################################################# // in: linda_ud key [count] // out: at most <count> values @@ -517,7 +517,7 @@ int keepercall_get(lua_State* L) return 0; } -// ################################################################################################## +// ################################################################################################# // in: linda_ud [, key [, ...]] int keepercall_count(lua_State* L) @@ -586,9 +586,9 @@ int keepercall_count(lua_State* L) return 1; } -//################################################################################### +// ################################################################################################# // Keeper API, accessed from linda methods -//################################################################################### +// ################################################################################################# /*---=== Keeper states ===--- */ @@ -636,7 +636,7 @@ void close_keepers(Universe* U) } } -// ################################################################################################## +// ################################################################################################# /* * Initialize keeper states @@ -746,7 +746,7 @@ void init_keepers(Universe* U, lua_State* L) STACK_CHECK(L, 0); } -// ################################################################################################## +// ################################################################################################# // should be called only when inside a keeper_acquire/keeper_release pair (see Linda::ProtectedCall) Keeper* which_keeper(Keepers* keepers_, uintptr_t magic_) @@ -760,7 +760,7 @@ Keeper* which_keeper(Keepers* keepers_, uintptr_t magic_) return nullptr; } -// ################################################################################################## +// ################################################################################################# Keeper* keeper_acquire(Keepers* keepers_, uintptr_t magic_) { @@ -784,7 +784,7 @@ Keeper* keeper_acquire(Keepers* keepers_, uintptr_t magic_) return nullptr; } -// ################################################################################################## +// ################################################################################################# void keeper_release(Keeper* K) { @@ -795,7 +795,7 @@ void keeper_release(Keeper* K) } } -// ################################################################################################## +// ################################################################################################# void keeper_toggle_nil_sentinels(lua_State* L, int val_i_, LookupMode const mode_) { @@ -821,7 +821,7 @@ void keeper_toggle_nil_sentinels(lua_State* L, int val_i_, LookupMode const mode } } -// ################################################################################################## +// ################################################################################################# /* * Call a function ('func_name') in the keeper state, and pass on the returned diff --git a/src/lanes.cpp b/src/lanes.cpp index 17d4f67..3aa3365 100644 --- a/src/lanes.cpp +++ b/src/lanes.cpp @@ -101,8 +101,63 @@ THE SOFTWARE. #include <atomic> -// forwarding (will do things better later) -static void tracking_add(Lane* lane_); +// ################################################################################################# + +#if HAVE_LANE_TRACKING() + +// The chain is ended by '(Lane*)(-1)', not nullptr: +// 'tracking_first -> ... -> ... -> (-1)' +#define TRACKING_END ((Lane *)(-1)) + +/* + * Add the lane to tracking chain; the ones still running at the end of the + * whole process will be cancelled. + */ +static void tracking_add(Lane* lane_) +{ + std::lock_guard<std::mutex> guard{ lane_->U->tracking_cs }; + assert(lane_->tracking_next == nullptr); + + lane_->tracking_next = lane_->U->tracking_first; + lane_->U->tracking_first = lane_; +} + +// ################################################################################################# + +/* + * A free-running lane has ended; remove it from tracking chain + */ +[[nodiscard]] static bool tracking_remove(Lane* lane_) +{ + bool found{ false }; + std::lock_guard<std::mutex> guard{ lane_->U->tracking_cs }; + // Make sure (within the MUTEX) that we actually are in the chain + // still (at process exit they will remove us from chain and then + // cancel/kill). + // + if (lane_->tracking_next != nullptr) + { + Lane** ref = (Lane**) &lane_->U->tracking_first; + + while( *ref != TRACKING_END) + { + if (*ref == lane_) + { + *ref = lane_->tracking_next; + lane_->tracking_next = nullptr; + found = true; + break; + } + ref = (Lane**) &((*ref)->tracking_next); + } + assert( found); + } + return found; +} + +#endif // HAVE_LANE_TRACKING() + +// ################################################################################################# Lane::Lane(Universe* U_, lua_State* L_) : U{ U_ } @@ -180,114 +235,44 @@ static constexpr UniqueKey FINALIZER_REGKEY{ 0x188fccb8bf348e09ull }; // ################################################################################################# -/* -* Push a table stored in registry onto Lua stack. -* -* If there is no existing table, create one if 'create' is true. -* -* Returns: true if a table was pushed -* false if no table found, not created, and nothing pushed -*/ -[[nodiscard]] static bool push_registry_table(lua_State* L, UniqueKey key, bool create) +Lane::~Lane() { - STACK_GROW(L, 3); - STACK_CHECK_START_REL(L, 0); - - key.pushValue(L); // ? - if (lua_isnil(L, -1)) // nil? + // Clean up after a (finished) thread + // +#if HAVE_LANE_TRACKING() + if (U->tracking_first != nullptr) { - lua_pop(L, 1); // - STACK_CHECK(L, 0); - - if (!create) - { - return false; - } - - lua_newtable(L); // t - key.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); + // Lane was cleaned up, no need to handle at process termination + std::ignore = tracking_remove(this); } - STACK_CHECK(L, 1); - return true; // table pushed +#endif // HAVE_LANE_TRACKING() } // ################################################################################################# +// ########################################## Finalizer ############################################ +// ################################################################################################# -#if HAVE_LANE_TRACKING() -// The chain is ended by '(Lane*)(-1)', not nullptr: -// 'tracking_first -> ... -> ... -> (-1)' -#define TRACKING_END ((Lane *)(-1)) - -/* - * Add the lane to tracking chain; the ones still running at the end of the - * whole process will be cancelled. - */ -static void tracking_add(Lane* lane_) +// Push the finalizers table on the stack. +// If there is no existing table, create ti. +static void push_finalizers_table(lua_State* L) { - std::lock_guard<std::mutex> guard{ lane_->U->tracking_cs }; - assert(lane_->tracking_next == nullptr); - - lane_->tracking_next = lane_->U->tracking_first; - lane_->U->tracking_first = lane_; -} - -// ################################################################################################# + STACK_GROW(L, 3); + STACK_CHECK_START_REL(L, 0); -/* - * A free-running lane has ended; remove it from tracking chain - */ -[[nodiscard]] static bool tracking_remove(Lane* lane_) -{ - bool found{ false }; - std::lock_guard<std::mutex> guard{ lane_->U->tracking_cs }; - // Make sure (within the MUTEX) that we actually are in the chain - // still (at process exit they will remove us from chain and then - // cancel/kill). - // - if (lane_->tracking_next != nullptr) + FINALIZER_REGKEY.pushValue(L); // ? + if (lua_isnil(L, -1)) // nil? { - Lane** ref = (Lane**) &lane_->U->tracking_first; - - while( *ref != TRACKING_END) - { - if (*ref == lane_) - { - *ref = lane_->tracking_next; - lane_->tracking_next = nullptr; - found = true; - break; - } - ref = (Lane**) &((*ref)->tracking_next); - } - assert( found); + lua_pop(L, 1); // + // store a newly created table in the registry, but leave it on the stack too + lua_newtable(L); // t + FINALIZER_REGKEY.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); // t } - return found; + STACK_CHECK(L, 1); } -#endif // HAVE_LANE_TRACKING() - // ################################################################################################# -Lane::~Lane() -{ - // Clean up after a (finished) thread - // -#if HAVE_LANE_TRACKING() - if (U->tracking_first != nullptr) - { - // Lane was cleaned up, no need to handle at process termination - std::ignore = tracking_remove(this); - } -#endif // HAVE_LANE_TRACKING() -} - -/* - * ############################################################################################### - * ########################################## Finalizer ########################################## - * ############################################################################################### - */ - //--- // void= finalizer( finalizer_func ) // @@ -296,12 +281,12 @@ Lane::~Lane() // Add a function that will be called when exiting the lane, either via // normal return or an error. // -LUAG_FUNC( set_finalizer) +LUAG_FUNC(set_finalizer) { luaL_argcheck(L, lua_isfunction(L, 1), 1, "finalizer should be a function"); luaL_argcheck(L, lua_gettop( L) == 1, 1, "too many arguments"); // Get the current finalizer table (if any), create one if it doesn't exist - std::ignore = push_registry_table(L, FINALIZER_REGKEY, true); // finalizer {finalisers} + push_finalizers_table(L); // finalizer {finalisers} STACK_GROW(L, 2); lua_pushinteger(L, lua_rawlen(L, -1) + 1); // finalizer {finalisers} idx lua_pushvalue(L, 1); // finalizer {finalisers} idx finalizer @@ -310,7 +295,44 @@ LUAG_FUNC( set_finalizer) return 0; } +// ################################################################################################# + +static void push_stack_trace(lua_State* L, int rc_, int stk_base_) +{ + // Lua 5.1 error handler is limited to one return value; it stored the stack trace in the registry + switch(rc_) + { + case LUA_OK: // no error, body return values are on the stack + break; + case LUA_ERRRUN: // cancellation or a runtime error +#if ERROR_FULL_STACK // when ERROR_FULL_STACK, we installed a handler + { + STACK_CHECK_START_REL(L, 0); + // fetch the call stack table from the registry where the handler stored it + STACK_GROW(L, 1); + // yields nil if no stack was generated (in case of cancellation for example) + STACKTRACE_REGKEY.pushValue(L); // err trace|nil + STACK_CHECK(L, 1); + + // For cancellation the error message is CANCEL_ERROR, and a stack trace isn't placed + // For other errors, the message can be whatever was thrown, and we should have a stack trace table + ASSERT_L(lua_type(L, 1 + stk_base_) == (CANCEL_ERROR.equals(L, stk_base_) ? LUA_TNIL : LUA_TTABLE)); + // Just leaving the stack trace table on the stack is enough to get it through to the master. + break; + } +#endif // fall through if not ERROR_FULL_STACK + + case LUA_ERRMEM: // memory allocation error (handler not called) + case LUA_ERRERR: // error while running the error handler (if any, for example an out-of-memory condition) + default: + // we should have a single value which is either a string (the error message) or CANCEL_ERROR + ASSERT_L((lua_gettop(L) == stk_base_) && ((lua_type(L, stk_base_) == LUA_TSTRING) || CANCEL_ERROR.equals(L, stk_base_))); + break; + } +} + +// ################################################################################################# //--- // Run finalizers - if any - with the given parameters // @@ -324,43 +346,37 @@ LUAG_FUNC( set_finalizer) // // TBD: should we add stack trace on failing finalizer, wouldn't be hard.. // -static void push_stack_trace( lua_State* L, int rc_, int stk_base_); -[[nodiscard]] static int run_finalizers(lua_State* L, int lua_rc) +[[nodiscard]] static int run_finalizers(lua_State* L, int lua_rc_) { - int finalizers_index; - int n; - int err_handler_index = 0; - int rc = LUA_OK; // ... - if (!push_registry_table(L, FINALIZER_REGKEY, false)) // ... finalizers? + FINALIZER_REGKEY.pushValue(L); // ... finalizers? + if (lua_isnil(L, -1)) { + lua_pop(L, 1); return 0; // no finalizers } STACK_GROW(L, 5); - finalizers_index = lua_gettop( L); - -#if ERROR_FULL_STACK - lua_pushcfunction(L, lane_error); // ... finalizers lane_error - err_handler_index = lua_gettop( L); -#endif // ERROR_FULL_STACK + int const finalizers_index{ lua_gettop(L) }; + int const err_handler_index{ ERROR_FULL_STACK ? (lua_pushcfunction(L, lane_error), lua_gettop(L)) : 0 }; - for( n = (int) lua_rawlen(L, finalizers_index); n > 0; -- n) + int rc{ LUA_OK }; + for (int n = static_cast<int>(lua_rawlen(L, finalizers_index)); n > 0; --n) { int args = 0; lua_pushinteger(L, n); // ... finalizers lane_error n lua_rawget(L, finalizers_index); // ... finalizers lane_error finalizer - ASSERT_L( lua_isfunction(L, -1)); - if (lua_rc != LUA_OK) // we have an error message and an optional stack trace at the bottom of the stack + ASSERT_L(lua_isfunction(L, -1)); + if (lua_rc_ != LUA_OK) // we have an error message and an optional stack trace at the bottom of the stack { ASSERT_L( finalizers_index == 2 || finalizers_index == 3); //char const* err_msg = lua_tostring(L, 1); - lua_pushvalue(L, 1); // ... finalizers lane_error finalizer err_msg + lua_pushvalue(L, 1); // ... finalizers lane_error finalizer err_msg // note we don't always have a stack trace for example when CANCEL_ERROR, or when we got an error that doesn't call our handler, such as LUA_ERRMEM if (finalizers_index == 3) { - lua_pushvalue(L, 2); // ... finalizers lane_error finalizer err_msg stack_trace + lua_pushvalue(L, 2); // ... finalizers lane_error finalizer err_msg stack_trace } args = finalizers_index - 1; } @@ -369,21 +385,21 @@ static void push_stack_trace( lua_State* L, int rc_, int stk_base_); rc = lua_pcall(L, args, 0, err_handler_index); // ... finalizers lane_error err_msg2? if (rc != LUA_OK) { - push_stack_trace(L, rc, lua_gettop( L)); + push_stack_trace(L, rc, lua_gettop(L)); // If one finalizer fails, don't run the others. Return this // as the 'real' error, replacing what we could have had (or not) // from the actual code. break; } - // no error, proceed to next finalizer // ... finalizers lane_error + // no error, proceed to next finalizer // ... finalizers lane_error } if (rc != LUA_OK) { // ERROR_FULL_STACK accounts for the presence of lane_error on the stack - int nb_err_slots = lua_gettop( L) - finalizers_index - ERROR_FULL_STACK; + int const nb_err_slots{ lua_gettop(L) - finalizers_index - ERROR_FULL_STACK }; // a finalizer generated an error, this is what we leave of the stack - for( n = nb_err_slots; n > 0; -- n) + for (int n = nb_err_slots; n > 0; --n) { lua_replace(L, n); } @@ -399,9 +415,9 @@ static void push_stack_trace( lua_State* L, int rc_, int stk_base_); } /* - * ############################################################################################### - * ########################################### Threads ########################################### - * ############################################################################################### + * ################################################################################################ + * ########################################### Threads ############################################ + * ################################################################################################ */ // @@ -425,7 +441,7 @@ static void selfdestruct_add(Lane* lane_) lane_->U->selfdestruct_first = lane_; } -// ############################################################################################### +// ################################################################################################# /* * A free-running lane has ended; remove it from selfdestruct chain @@ -460,7 +476,7 @@ static void selfdestruct_add(Lane* lane_) return found; } -// ############################################################################################### +// ################################################################################################# /* * Process end; cancel any still free-running threads @@ -567,7 +583,7 @@ static void selfdestruct_add(Lane* lane_) return 0; } -// ############################################################################################### +// ################################################################################################# //--- // = _single( [cores_uint=1] ) @@ -597,7 +613,7 @@ LUAG_FUNC( set_singlethreaded) #endif } -// ############################################################################################### +// ################################################################################################# /* * str= lane_error( error_val|str ) @@ -710,41 +726,6 @@ LUAG_FUNC( set_error_reporting) } #endif // ERROR_FULL_STACK -static void push_stack_trace( lua_State* L, int rc_, int stk_base_) -{ - // Lua 5.1 error handler is limited to one return value; it stored the stack trace in the registry - switch( rc_) - { - case LUA_OK: // no error, body return values are on the stack - break; - - case LUA_ERRRUN: // cancellation or a runtime error -#if ERROR_FULL_STACK // when ERROR_FULL_STACK, we installed a handler - { - STACK_CHECK_START_REL(L, 0); - // fetch the call stack table from the registry where the handler stored it - STACK_GROW(L, 1); - // yields nil if no stack was generated (in case of cancellation for example) - STACKTRACE_REGKEY.pushValue(L); // err trace|nil - STACK_CHECK(L, 1); - - // For cancellation the error message is CANCEL_ERROR, and a stack trace isn't placed - // For other errors, the message can be whatever was thrown, and we should have a stack trace table - ASSERT_L(lua_type(L, 1 + stk_base_) == (CANCEL_ERROR.equals(L, stk_base_) ? LUA_TNIL : LUA_TTABLE)); - // Just leaving the stack trace table on the stack is enough to get it through to the master. - break; - } -#endif // fall through if not ERROR_FULL_STACK - - case LUA_ERRMEM: // memory allocation error (handler not called) - case LUA_ERRERR: // error while running the error handler (if any, for example an out-of-memory condition) - default: - // we should have a single value which is either a string (the error message) or CANCEL_ERROR - ASSERT_L((lua_gettop(L) == stk_base_) && ((lua_type(L, stk_base_) == LUA_TSTRING) || CANCEL_ERROR.equals(L, stk_base_))); - break; - } -} - // ################################################################################################# LUAG_FUNC(set_debug_threadname) @@ -772,7 +753,7 @@ LUAG_FUNC(set_debug_threadname) LUAG_FUNC(get_debug_threadname) { - Lane* const lane{ lua_toLane(L, 1) }; + Lane* const lane{ ToLane(L, 1) }; luaL_argcheck(L, lua_gettop(L) == 1, 2, "too many arguments"); lua_pushstring(L, lane->debug_name); return 1; @@ -828,8 +809,7 @@ static struct errcode_name s_errcodes[] = }; static char const* get_errcode_name( int _code) { - int i; - for( i = 0; i < 7; ++ i) + for (int i{ 0 }; i < 7; ++i) { if (s_errcodes[i].code == _code) { @@ -891,7 +871,6 @@ static void lane_main(Lane* lane) push_stack_trace(L, rc, 1); // retvals|error [trace] DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END, L, get_errcode_name(rc), CANCEL_ERROR.equals(L, 1) ? "cancelled" : lua_typename(L, lua_type(L, 1)))); - // STACK_DUMP(L); // Call finalizers, if the script has set them up. // int rc2{ run_finalizers(L, rc) }; @@ -1295,7 +1274,7 @@ LUAG_FUNC(lane_new) [[nodiscard]] static int lane_gc(lua_State* L) { bool have_gc_cb{ false }; - Lane* const lane{ lua_toLane(L, 1) }; // ud + Lane* const lane{ ToLane(L, 1) }; // ud // if there a gc callback? lua_getiuservalue(L, 1, 1); // ud uservalue @@ -1393,7 +1372,7 @@ void push_thread_status(lua_State* L, Lane* lane_) // LUAG_FUNC(thread_join) { - Lane* const lane{ lua_toLane(L, 1) }; + Lane* const lane{ ToLane(L, 1) }; lua_Duration const duration{ luaL_optnumber(L, 2, -1.0) }; lua_State* const L2{ lane->L }; @@ -1474,7 +1453,7 @@ LUAG_FUNC(thread_index) static constexpr int UD{ 1 }; static constexpr int KEY{ 2 }; static constexpr int USR{ 3 }; - Lane* const lane{ lua_toLane(L, UD) }; + Lane* const lane{ ToLane(L, UD) }; ASSERT_L(lua_gettop(L) == 2); STACK_GROW(L, 8); // up to 8 positions are needed in case of error propagation @@ -1647,11 +1626,9 @@ LUAG_FUNC(threads) } #endif // HAVE_LANE_TRACKING() -/* - * ############################################################################################### - * ######################################## Timer support ######################################## - * ############################################################################################### - */ +// ################################################################################################# +// ######################################## Timer support ########################################## +// ################################################################################################# /* * secs = now_secs() @@ -1722,11 +1699,9 @@ LUAG_FUNC(wakeup_conv) return 1; } -/* - * ############################################################################################### - * ######################################## Module linkage ####################################### - * ############################################################################################### - */ +// ################################################################################################# +// ######################################## Module linkage ######################################### +// ################################################################################################# extern int LG_linda(lua_State* L); static struct luaL_Reg const lanes_functions[] = diff --git a/src/lanes_private.h b/src/lanes_private.h index 18e55fd..5e6160d 100644 --- a/src/lanes_private.h +++ b/src/lanes_private.h @@ -98,7 +98,7 @@ static constexpr UniqueKey LANE_POINTER_REGKEY{ 0xB3022205633743BCull }; // used // 'Lane' are malloc/free'd and the handle only carries a pointer. // This is not deep userdata since the handle's not portable among lanes. // -[[nodiscard]] inline Lane* lua_toLane(lua_State* L, int i_) +[[nodiscard]] inline Lane* ToLane(lua_State* L, int i_) { return *(static_cast<Lane**>(luaL_checkudata(L, i_, "Lane"))); } diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h index 073e940..c01363a 100644 --- a/src/macros_and_utils.h +++ b/src/macros_and_utils.h @@ -35,7 +35,6 @@ using namespace std::chrono_literals; #ifdef NDEBUG #define _ASSERT_L(lua,c) //nothing -#define STACK_DUMP(L) //nothing #define STACK_CHECK_START_REL(L, offset_) #define STACK_CHECK_START_ABS(L, offset_) @@ -45,8 +44,7 @@ using namespace std::chrono_literals; #else // NDEBUG -#define _ASSERT_L(L, cond_) if( (cond_) == 0) { (void) luaL_error(L, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #cond_);} -#define STACK_DUMP(L) luaG_dump(L) +#define _ASSERT_L(L, cond_) if ((cond_) == 0) { (void) luaL_error(L, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #cond_);} class StackChecker { diff --git a/src/state.cpp b/src/state.cpp index 1ba5a77..9ad237d 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -37,7 +37,7 @@ THE SOFTWARE. #include "tools.h" #include "universe.h" -// ################################################################################################ +// ################################################################################################# /*---=== Serialize require ===--- */ @@ -71,7 +71,7 @@ THE SOFTWARE. // the required module (or an error message) is left on the stack as returned value by original require function - if( rc != LUA_OK) // LUA_ERRRUN / LUA_ERRMEM ? + if (rc != LUA_OK) // LUA_ERRRUN / LUA_ERRMEM ? { raise_lua_error(L); } @@ -108,7 +108,7 @@ void serialize_require(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L) STACK_CHECK(L, 0); } -// ################################################################################################ +// ################################################################################################# /*---=== luaG_newstate ===---*/ @@ -161,10 +161,9 @@ static luaL_Reg const libs[] = static void open1lib(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, char const* name_, size_t len_) { - int i; - for( i = 0; libs[i].name; ++ i) + for (int i{ 0 }; libs[i].name; ++i) { - if( strncmp( name_, libs[i].name, len_) == 0) + if (strncmp( name_, libs[i].name, len_) == 0) { lua_CFunction libfunc = libs[i].func; name_ = libs[i].name; // note that the provided name_ doesn't necessarily ends with '\0', hence len_ @@ -176,7 +175,7 @@ static void open1lib(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, char const // 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 - if( isLanesCore == true) + if (isLanesCore == true) { populate_func_lookup_table( L, -1, name_); } @@ -220,7 +219,7 @@ void initialize_on_state_create( Universe* U, lua_State* L) { STACK_CHECK_START_REL(L, 1); // settings lua_getfield(L, -1, "on_state_create"); // settings on_state_create|nil - if( !lua_isnil(L, -1)) + if (!lua_isnil(L, -1)) { // store C function pointer in an internal variable U->on_state_create_func = lua_tocfunction(L, -1); // settings on_state_create @@ -371,7 +370,7 @@ lua_State* luaG_newstate(Universe* U, Source from_, char const* libs_) { // special "*" case (mainly to help with LuaJIT compatibility) // as we are called from luaopen_lanes_core() already, and that would deadlock - if( libs_[0] == '*' && libs_[1] == 0) + if (libs_[0] == '*' && libs_[1] == 0) { DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); luaL_openlibs( L); @@ -396,26 +395,25 @@ lua_State* luaG_newstate(Universe* U, Source from_, char const* libs_) STACK_CHECK(L, 0); // scan all libraries, open them one by one - if( libs_) + if (libs_) { - char const* p; - unsigned int len = 0; - for( p = libs_; *p; p += len) + unsigned int len{ 0 }; + for (char const* p{ libs_ }; *p; p += len) { // skip delimiters ('.' can be part of name for "lanes.core") - while( *p && !isalnum( *p) && *p != '.') + while( *p && !isalnum(*p) && *p != '.') ++ p; // skip name len = 0; - while( isalnum( p[len]) || p[len] == '.') + while( isalnum(p[len]) || p[len] == '.') ++ len; // open library - open1lib( DEBUGSPEW_PARAM_COMMA( U) L, p, len); + open1lib(DEBUGSPEW_PARAM_COMMA( U) L, p, len); } } - lua_gc( L, LUA_GCRESTART, 0); + lua_gc(L, LUA_GCRESTART, 0); - serialize_require( DEBUGSPEW_PARAM_COMMA( U) L); + serialize_require(DEBUGSPEW_PARAM_COMMA( U) L); // call this after the base libraries are loaded and GC is restarted // will raise an error in from_ in case of problem @@ -423,7 +421,7 @@ lua_State* luaG_newstate(Universe* U, Source from_, char const* libs_) 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 + lua_pushglobaltable(L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack STACK_CHECK(L, 1); populate_func_lookup_table(L, -1, nullptr); diff --git a/src/state.h b/src/state.h index e1c311a..059e163 100644 --- a/src/state.h +++ b/src/state.h @@ -8,12 +8,12 @@ class Universe; void serialize_require(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L); -// ################################################################################################ +// ################################################################################################# [[nodiscard]] lua_State* create_state(Universe* U, lua_State* from_); [[nodiscard]] lua_State* luaG_newstate(Universe* U, Source _from, char const* libs); -// ################################################################################################ +// ################################################################################################# void initialize_on_state_create(Universe* U, lua_State* L); void call_on_state_create(Universe* U, lua_State* L, lua_State* from_, LookupMode mode_); diff --git a/src/threading.cpp b/src/threading.cpp index 259693a..c7928c1 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -105,8 +105,8 @@ THE SOFTWARE. /*---=== Threading ===---*/ -// ################################################################################################## -// ################################################################################################## +// ################################################################################################# +// ################################################################################################# #if THREADAPI == THREADAPI_WINDOWS static int const gs_prio_remap[] = @@ -120,7 +120,7 @@ static int const gs_prio_remap[] = THREAD_PRIORITY_TIME_CRITICAL }; -// ############################################################################################### +// ################################################################################################# void THREAD_SET_PRIORITY(int prio_, [[maybe_unused]] bool sudo_) { @@ -131,7 +131,7 @@ void THREAD_SET_PRIORITY(int prio_, [[maybe_unused]] bool sudo_) } } -// ############################################################################################### +// ################################################################################################# void JTHREAD_SET_PRIORITY(std::jthread& thread_, int prio_, [[maybe_unused]] bool sudo_) { @@ -142,7 +142,7 @@ void JTHREAD_SET_PRIORITY(std::jthread& thread_, int prio_, [[maybe_unused]] boo } } -// ############################################################################################### +// ################################################################################################# void THREAD_SET_AFFINITY(unsigned int aff) { @@ -152,7 +152,7 @@ void THREAD_SET_AFFINITY(unsigned int aff) } } -// ############################################################################################### +// ################################################################################################# #if !defined __GNUC__ //see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx @@ -187,11 +187,11 @@ void THREAD_SETNAME(char const* _name) #endif // !__GNUC__ } -// ################################################################################################## -// ################################################################################################## +// ################################################################################################# +// ################################################################################################# #else // THREADAPI == THREADAPI_PTHREAD -// ################################################################################################## -// ################################################################################################## +// ################################################################################################# +// ################################################################################################# // PThread (Linux, OS X, ...) // diff --git a/src/threading.h b/src/threading.h index fc35730..e13932b 100644 --- a/src/threading.h +++ b/src/threading.h @@ -7,7 +7,7 @@ #define THREADAPI_WINDOWS 1 #define THREADAPI_PTHREAD 2 -#if( defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)) +#if (defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)) //#pragma message ( "THREADAPI_WINDOWS" ) #define THREADAPI THREADAPI_WINDOWS #else // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) @@ -17,8 +17,8 @@ static constexpr int THREAD_PRIO_DEFAULT{ -999 }; -// ################################################################################################## -// ################################################################################################## +// ################################################################################################# +// ################################################################################################# #if THREADAPI == THREADAPI_WINDOWS #if defined(PLATFORM_XBOX) @@ -43,11 +43,11 @@ static constexpr int THREAD_PRIO_DEFAULT{ -999 }; static constexpr int THREAD_PRIO_MIN{ -3 }; static constexpr int THREAD_PRIO_MAX{ +3 }; -// ################################################################################################## -// ################################################################################################## +// ################################################################################################# +// ################################################################################################# #else // THREADAPI == THREADAPI_PTHREAD -// ################################################################################################## -// ################################################################################################## +// ################################################################################################# +// ################################################################################################# // PThread (Linux, OS X, ...) @@ -65,8 +65,8 @@ static constexpr int THREAD_PRIO_MIN{ -3 }; static constexpr int THREAD_PRIO_MAX{ +3 }; #endif // THREADAPI == THREADAPI_PTHREAD -// ################################################################################################## -// ################################################################################################## +// ################################################################################################# +// ################################################################################################# void THREAD_SETNAME(char const* _name); void THREAD_SET_PRIORITY(int prio_, bool sudo_); diff --git a/src/tools.cpp b/src/tools.cpp index ad706be..cd25eda 100644 --- a/src/tools.cpp +++ b/src/tools.cpp @@ -35,13 +35,12 @@ THE SOFTWARE. #include "universe.h" -// functions implemented in deep.c -extern void push_registry_subtable( lua_State* L, UniqueKey key_); - DEBUGSPEW_CODE(char const* const DebugSpewIndentScope::debugspew_indent = "----+----!----+----!----+----!----+----!----+----!----+----!----+----!----+"); +// crc64/we of string "LOOKUPCACHE_REGKEY" generated at http://www.nitrxgen.net/hashgen/ +static constexpr UniqueKey LOOKUPCACHE_REGKEY{ 0x837a68dfc6fcb716ull }; -// ################################################################################################ +// ################################################################################################# /* * Does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it @@ -76,7 +75,7 @@ void push_registry_subtable_mode( lua_State* L, UniqueKey key_, const char* mode ASSERT_L(lua_istable(L, -1)); } -// ################################################################################################ +// ################################################################################################# /* * Push a registry subtable (keyed by unique 'key_') onto the stack. @@ -87,60 +86,7 @@ void push_registry_subtable( lua_State* L, UniqueKey key_) push_registry_subtable_mode(L, key_, nullptr); } -// ################################################################################################ - -/*---=== luaG_dump ===---*/ -#ifdef _DEBUG -void luaG_dump( lua_State* L) -{ - int top = lua_gettop( L); - int i; - - fprintf( stderr, "\n\tDEBUG STACK:\n"); - - if( top == 0) - fprintf( stderr, "\t(none)\n"); - - for( i = 1; i <= top; ++ i) - { - LuaType type{ lua_type_as_enum(L, i) }; - - fprintf( stderr, "\t[%d]= (%s) ", i, lua_typename( L, type)); - - // Print item contents here... - // - // Note: this requires 'tostring()' to be defined. If it is NOT, - // enable it for more debugging. - // - STACK_CHECK_START_REL(L, 0); - STACK_GROW( L, 2); - - lua_getglobal( L, "tostring"); - // - // [-1]: tostring function, or nil - - if( !lua_isfunction( L, -1)) - { - fprintf( stderr, "('tostring' not available)"); - } - else - { - lua_pushvalue( L, i); - lua_call( L, 1 /*args*/, 1 /*retvals*/); - - // Don't trust the string contents - // - fprintf( stderr, "%s", lua_tostring( L, -1)); - } - lua_pop( L, 1); - STACK_CHECK( L, 0); - fprintf( stderr, "\n"); - } - fprintf( stderr, "\n"); -} -#endif // _DEBUG - -// ################################################################################################ +// ################################################################################################# // same as PUC-Lua l_alloc extern "C" [[nodiscard]] static void* libc_lua_Alloc([[maybe_unused]] void* ud, [[maybe_unused]] void* ptr_, [[maybe_unused]] size_t osize_, size_t nsize_) @@ -231,7 +177,7 @@ void initialize_allocator_function(Universe* U, lua_State* L) STACK_CHECK(L, 1); } -// ################################################################################################ +// ################################################################################################# [[nodiscard]] static int dummy_writer(lua_State* L, void const* p, size_t sz, void* ud) { @@ -239,7 +185,6 @@ void initialize_allocator_function(Universe* U, lua_State* L) return 666; } - /* * differentiation between C, bytecode and JIT-fast functions * @@ -262,25 +207,25 @@ enum FuncSubType FST_FastJIT } ; -FuncSubType luaG_getfuncsubtype( lua_State *L, int _i) +FuncSubType luaG_getfuncsubtype(lua_State* L, int _i) { - if( lua_tocfunction( L, _i)) + if (lua_tocfunction(L, _i)) // nullptr for LuaJIT-fast && bytecode functions { return FST_Native; } { - int mustpush = 0, dumpres; - if( lua_absindex( L, _i) != lua_gettop( L)) + int mustpush{ 0 }; + if (lua_absindex(L, _i) != lua_gettop(L)) { - lua_pushvalue( L, _i); + lua_pushvalue(L, _i); mustpush = 1; } // the provided writer fails with code 666 // therefore, anytime we get 666, this means that lua_dump() attempted a dump // all other cases mean this is either a C or LuaJIT-fast function - dumpres = lua504_dump(L, dummy_writer, nullptr, 0); - lua_pop( L, mustpush); - if( dumpres == 666) + int const dumpres{ lua504_dump(L, dummy_writer, nullptr, 0) }; + lua_pop(L, mustpush); + if (dumpres == 666) { return FST_Bytecode; } @@ -290,40 +235,28 @@ FuncSubType luaG_getfuncsubtype( lua_State *L, int _i) // ################################################################################################# -[[nodiscard]] static lua_CFunction luaG_tocfunction(lua_State* L, int _i, FuncSubType* _out) -{ - lua_CFunction p = lua_tocfunction( L, _i); - *_out = luaG_getfuncsubtype( L, _i); - return p; -} - -// crc64/we of string "LOOKUPCACHE_REGKEY" generated at http://www.nitrxgen.net/hashgen/ -static constexpr UniqueKey LOOKUPCACHE_REGKEY{ 0x837a68dfc6fcb716ull }; - -// ################################################################################################# - // inspired from tconcat() in ltablib.c [[nodiscard]] static char const* luaG_pushFQN(lua_State* L, int t, int last, size_t* length) { - int i = 1; luaL_Buffer b; STACK_CHECK_START_REL(L, 0); // Lua 5.4 pushes &b as light userdata on the stack. be aware of it... - luaL_buffinit( L, &b); // ... {} ... &b? - for( ; i < last; ++ i) + luaL_buffinit(L, &b); // ... {} ... &b? + int i = 1; + for (; i < last; ++i) { lua_rawgeti( L, t, i); luaL_addvalue( &b); luaL_addlstring(&b, "/", 1); } - if( i == last) // add last value (if interval was not empty) + if (i == last) // add last value (if interval was not empty) { - lua_rawgeti( L, t, i); - luaL_addvalue( &b); + lua_rawgeti(L, t, i); + luaL_addvalue(&b); } // &b is popped at that point (-> replaced by the result) - luaL_pushresult( &b); // ... {} ... "<result>" - STACK_CHECK( L, 1); + luaL_pushresult(&b); // ... {} ... "<result>" + STACK_CHECK(L, 1); return lua_tolstring( L, -1, length); } @@ -337,12 +270,12 @@ static constexpr UniqueKey LOOKUPCACHE_REGKEY{ 0x837a68dfc6fcb716ull }; * if we already had an entry of type [o] = ..., replace the name if the new one is shorter * pops the processed object from the stack */ -static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L, int _ctx_base, int _depth) +static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, int _ctx_base, int _depth) { // slot 1 in the stack contains the table that receives everything we found - int const dest = _ctx_base; + int const dest{ _ctx_base }; // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i - int const fqn = _ctx_base + 1; + int const fqn{ _ctx_base + 1 }; size_t prevNameLength, newNameLength; char const* prevName; @@ -352,16 +285,16 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L STACK_CHECK_START_REL(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? + lua_pushvalue(L, -1); // ... {bfc} k o o + lua_rawget(L, dest); // ... {bfc} k o name? prevName = lua_tolstring( L, -1, &prevNameLength); // nullptr if we got nil (first encounter of this object) // push name in fqn stack (note that concatenation will crash if name is a not string or a number) - lua_pushvalue( L, -3); // ... {bfc} k o name? k - ASSERT_L( lua_type( L, -1) == LUA_TNUMBER || lua_type( L, -1) == LUA_TSTRING); - ++ _depth; - lua_rawseti( L, fqn, _depth); // ... {bfc} k o name? + lua_pushvalue(L, -3); // ... {bfc} k o name? k + ASSERT_L(lua_type(L, -1) == LUA_TNUMBER || lua_type(L, -1) == LUA_TSTRING); + ++_depth; + lua_rawseti(L, fqn, _depth); // ... {bfc} k o name? // generate name - DEBUGSPEW_OR_NOT(newName, std::ignore) = luaG_pushFQN(L, fqn, _depth, &newNameLength);// ... {bfc} k o name? "f.q.n" + DEBUGSPEW_OR_NOT(newName, std::ignore) = luaG_pushFQN(L, fqn, _depth, &newNameLength); // ... {bfc} k o name? "f.q.n" // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order // on different VMs even when the tables are populated the exact same way. // When Lua is built with compatibility options (such as LUA_COMPAT_ALL), @@ -375,36 +308,36 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L { DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -3)), newName, prevName)); // the previous name is 'smaller' than the one we just generated: keep it! - lua_pop( L, 3); // ... {bfc} k + lua_pop(L, 3); // ... {bfc} k } else { // the name we generated is either the first one, or a better fit for our purposes - if( prevName) + if (prevName) { // clear the previous name for the database to avoid clutter - lua_insert( L, -2); // ... {bfc} k o "f.q.n" prevName + lua_insert(L, -2); // ... {bfc} k o "f.q.n" prevName // t[prevName] = nil - lua_pushnil( L); // ... {bfc} k o "f.q.n" prevName nil - lua_rawset( L, dest); // ... {bfc} k o "f.q.n" + lua_pushnil(L); // ... {bfc} k o "f.q.n" prevName nil + lua_rawset(L, dest); // ... {bfc} k o "f.q.n" } else { - lua_remove( L, -2); // ... {bfc} k o "f.q.n" + lua_remove(L, -2); // ... {bfc} k o "f.q.n" } - DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -2)), newName)); + DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END, lua_typename(L, lua_type( L, -2)), newName)); // prepare the stack for database feed - lua_pushvalue( L, -1); // ... {bfc} k o "f.q.n" "f.q.n" - lua_pushvalue( L, -3); // ... {bfc} k o "f.q.n" "f.q.n" o - ASSERT_L( lua_rawequal( L, -1, -4)); - ASSERT_L( lua_rawequal( L, -2, -3)); + lua_pushvalue(L, -1); // ... {bfc} k o "f.q.n" "f.q.n" + lua_pushvalue(L, -3); // ... {bfc} k o "f.q.n" "f.q.n" o + ASSERT_L(lua_rawequal(L, -1, -4)); + ASSERT_L(lua_rawequal(L, -2, -3)); // t["f.q.n"] = o - lua_rawset( L, dest); // ... {bfc} k o "f.q.n" + lua_rawset(L, dest); // ... {bfc} k o "f.q.n" // t[o] = "f.q.n" - lua_rawset( L, dest); // ... {bfc} k + lua_rawset(L, dest); // ... {bfc} k // remove table name from fqn stack - lua_pushnil( L); // ... {bfc} k nil - lua_rawseti( L, fqn, _depth); // ... {bfc} k + lua_pushnil(L); // ... {bfc} k nil + lua_rawseti(L, fqn, _depth); // ... {bfc} k } -- _depth; STACK_CHECK(L, -1); @@ -414,122 +347,121 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, int _ctx_base, int _i, int _depth) { - lua_Integer visit_count; // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i int const fqn = _ctx_base + 1; // slot 3 contains a cache that stores all already visited tables to avoid infinite recursion loops int const cache = _ctx_base + 2; // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search) - int const breadth_first_cache = lua_gettop( L) + 1; + int const breadth_first_cache = lua_gettop(L) + 1; DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "populate_func_lookup_table_recur()\n" INDENT_END)); DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); - STACK_GROW( L, 6); + STACK_GROW(L, 6); // slot _i contains a table where we search for functions (or a full userdata with a metatable) - STACK_CHECK_START_REL(L, 0); // ... {_i} + STACK_CHECK_START_REL(L, 0); // ... {_i} // if object is a userdata, replace it by its metatable - if( lua_type( L, _i) == LUA_TUSERDATA) + if (lua_type(L, _i) == LUA_TUSERDATA) { - lua_getmetatable( L, _i); // ... {_i} mt - lua_replace( L, _i); // ... {_i} + lua_getmetatable(L, _i); // ... {_i} mt + lua_replace(L, _i); // ... {_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_CHECK( L, 0); - if( visit_count > 0) + lua_pushvalue(L, _i); // ... {_i} {} + lua_rawget(L, cache); // ... {_i} nil|n + lua_Integer visit_count{ lua_tointeger(L, -1) }; // 0 if nil, else n + lua_pop(L, 1); // ... {_i} + STACK_CHECK(L, 0); + if (visit_count > 0) { DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "already visited\n" INDENT_END)); return; } // remember we visited this table (1-visit count) - lua_pushvalue( L, _i); // ... {_i} {} - lua_pushinteger( L, visit_count + 1); // ... {_i} {} 1 - lua_rawset( L, cache); // ... {_i} - STACK_CHECK( L, 0); + lua_pushvalue(L, _i); // ... {_i} {} + lua_pushinteger(L, visit_count + 1); // ... {_i} {} 1 + lua_rawset(L, cache); // ... {_i} + STACK_CHECK(L, 0); // this table is at breadth_first_cache index - lua_newtable( L); // ... {_i} {bfc} - ASSERT_L( lua_gettop( L) == breadth_first_cache); + lua_newtable(L); // ... {_i} {bfc} + ASSERT_L( lua_gettop(L) == breadth_first_cache); // iterate over all entries in the processed table - lua_pushnil( L); // ... {_i} {bfc} nil - while( lua_next( L, _i) != 0) // ... {_i} {bfc} k v + lua_pushnil(L); // ... {_i} {bfc} nil + 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 {} + if (lua_istable(L, -1)) // ... {_i} {bfc} k {} { // increment visit count to make sure we will actually scan it at this recursive level - lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} - lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} {} - lua_rawget( L, cache); // ... {_i} {bfc} k {} {} n? - visit_count = lua_tointeger( L, -1) + 1; // 1 if we got nil, else n+1 - lua_pop( L, 1); // ... {_i} {bfc} k {} {} - lua_pushinteger( L, visit_count); // ... {_i} {bfc} k {} {} n - lua_rawset( L, cache); // ... {_i} {bfc} k {} + lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {} + lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {} {} + lua_rawget(L, cache); // ... {_i} {bfc} k {} {} n? + visit_count = lua_tointeger(L, -1) + 1; // 1 if we got nil, else n+1 + lua_pop(L, 1); // ... {_i} {bfc} k {} {} + lua_pushinteger(L, visit_count); // ... {_i} {bfc} k {} {} n + lua_rawset(L, cache); // ... {_i} {bfc} k {} // store the table in the breadth-first cache - lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k - lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k {} - lua_rawset( L, breadth_first_cache); // ... {_i} {bfc} k {} + lua_pushvalue(L, -2); // ... {_i} {bfc} k {} k + lua_pushvalue(L, -2); // ... {_i} {bfc} k {} k {} + lua_rawset(L, breadth_first_cache); // ... {_i} {bfc} k {} // generate a name, and if we already had one name, keep whichever is the shorter - update_lookup_entry( DEBUGSPEW_PARAM_COMMA( U) L, _ctx_base, _depth); // ... {_i} {bfc} k + update_lookup_entry( DEBUGSPEW_PARAM_COMMA(U) L, _ctx_base, _depth); // ... {_i} {bfc} k } - else if( lua_isfunction( L, -1) && (luaG_getfuncsubtype( L, -1) != FST_Bytecode)) // ... {_i} {bfc} k func + else if (lua_isfunction(L, -1) && (luaG_getfuncsubtype(L, -1) != FST_Bytecode)) // ... {_i} {bfc} k func { // generate a name, and if we already had one name, keep whichever is the shorter - update_lookup_entry( DEBUGSPEW_PARAM_COMMA( U) L, _ctx_base, _depth); // ... {_i} {bfc} k + update_lookup_entry( DEBUGSPEW_PARAM_COMMA(U) L, _ctx_base, _depth); // ... {_i} {bfc} k } else { - lua_pop( L, 1); // ... {_i} {bfc} k + lua_pop(L, 1); // ... {_i} {bfc} k } - STACK_CHECK( L, 2); + STACK_CHECK(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 {} + 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(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(DebugSpewIndentScope scope{ U }); // 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 - ASSERT_L( lua_type( L, -1) == LUA_TNUMBER); - visit_count = lua_tointeger( L, -1) - 1; - lua_pop( L, 1); // ... {_i} {bfc} k {} - lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} - if( visit_count > 0) + lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {} + lua_rawget(L, cache); // ... {_i} {bfc} k {} n + ASSERT_L(lua_type(L, -1) == LUA_TNUMBER); + visit_count = lua_tointeger(L, -1) - 1; + lua_pop(L, 1); // ... {_i} {bfc} k {} + lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {} + if (visit_count > 0) { - lua_pushinteger( L, visit_count); // ... {_i} {bfc} k {} {} n + lua_pushinteger(L, visit_count); // ... {_i} {bfc} k {} {} n } else { - lua_pushnil( L); // ... {_i} {bfc} k {} {} nil + lua_pushnil(L); // ... {_i} {bfc} k {} {} nil } - lua_rawset( L, cache); // ... {_i} {bfc} k {} + lua_rawset(L, cache); // ... {_i} {bfc} k {} // push table name in fqn stack (note that concatenation will crash if name is a not string!) - lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k - lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k {} - populate_func_lookup_table_recur( DEBUGSPEW_PARAM_COMMA( U) L, _ctx_base, lua_gettop( L), _depth); - lua_pop( L, 1); // ... {_i} {bfc} k - STACK_CHECK( L, 2); + lua_pushvalue(L, -2); // ... {_i} {bfc} k {} k + lua_rawseti(L, fqn, _depth); // ... {_i} {bfc} k {} + populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U) L, _ctx_base, lua_gettop(L), _depth); + lua_pop(L, 1); // ... {_i} {bfc} k + STACK_CHECK(L, 2); } // remove table name from fqn stack - lua_pushnil( L); // ... {_i} {bfc} nil - lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} + lua_pushnil(L); // ... {_i} {bfc} nil + lua_rawseti(L, fqn, _depth); // ... {_i} {bfc} -- _depth; // we are done with our cache - lua_pop( L, 1); // ... {_i} - STACK_CHECK( L, 0); - // we are done // ... {_i} {bfc} + lua_pop(L, 1); // ... {_i} + STACK_CHECK(L, 0); + // we are done // ... {_i} {bfc} } // ################################################################################################# @@ -542,59 +474,59 @@ 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 start_depth = 0; - DEBUGSPEW_CODE( Universe* U = universe_get( L)); - DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "nullptr")); + DEBUGSPEW_CODE(Universe* U = universe_get(L)); + DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "nullptr")); DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); STACK_GROW(L, 3); STACK_CHECK_START_REL(L, 0); - LOOKUP_REGKEY.pushValue(L); // {} - STACK_CHECK( 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 + LOOKUP_REGKEY.pushValue(L); // {} + STACK_CHECK(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 { name_ = name_ ? name_ : "nullptr"; - lua_pushvalue( L, in_base); // {} f - lua_pushstring( L, name_); // {} f _name - lua_rawset( L, -3); // {} - lua_pushstring( L, name_); // {} _name - lua_pushvalue( L, in_base); // {} _name f - lua_rawset( L, -3); // {} - lua_pop( L, 1); // - } - else if( lua_type( L, in_base) == LUA_TTABLE) - { - lua_newtable(L); // {} {fqn} - if( name_) + lua_pushvalue(L, in_base); // {} f + lua_pushstring(L, name_); // {} f _name + lua_rawset(L, -3); // {} + lua_pushstring(L, name_); // {} _name + lua_pushvalue(L, in_base); // {} _name f + lua_rawset(L, -3); // {} + lua_pop(L, 1); // + } + else if (lua_type(L, in_base) == LUA_TTABLE) + { + lua_newtable(L); // {} {fqn} + if (name_) { - STACK_CHECK( L, 2); - lua_pushstring( L, name_); // {} {fqn} "name" + STACK_CHECK(L, 2); + lua_pushstring(L, name_); // {} {fqn} "name" // generate a name, and if we already had one name, keep whichever is the shorter - lua_pushvalue( L, in_base); // {} {fqn} "name" t - update_lookup_entry( DEBUGSPEW_PARAM_COMMA( U) L, ctx_base, start_depth); // {} {fqn} "name" + lua_pushvalue(L, in_base); // {} {fqn} "name" t + update_lookup_entry(DEBUGSPEW_PARAM_COMMA(U) L, ctx_base, start_depth); // {} {fqn} "name" // don't forget to store the name at the bottom of the fqn stack ++ start_depth; - lua_rawseti( L, -2, start_depth); // {} {fqn} - STACK_CHECK( L, 2); + lua_rawseti(L, -2, start_depth); // {} {fqn} + STACK_CHECK(L, 2); } // retrieve the cache, create it if we haven't done it yet LOOKUPCACHE_REGKEY.pushValue(L); // {} {fqn} {cache}? - if( lua_isnil( L, -1)) + if (lua_isnil(L, -1)) { - lua_pop( L, 1); // {} {fqn} - lua_newtable( L); // {} {fqn} {cache} + lua_pop(L, 1); // {} {fqn} + lua_newtable(L); // {} {fqn} {cache} LOOKUPCACHE_REGKEY.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); - STACK_CHECK( L, 3); + STACK_CHECK(L, 3); } // process everything we find in that table, filling in lookup data for all functions and tables we see there - populate_func_lookup_table_recur( DEBUGSPEW_PARAM_COMMA( U) L, ctx_base, in_base, start_depth); - lua_pop( L, 3); + populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U) L, ctx_base, in_base, start_depth); + lua_pop(L, 3); } else { - lua_pop( L, 1); // - (void) luaL_error( L, "unsupported module type %s", lua_typename( L, lua_type( L, in_base))); + lua_pop(L, 1); // + luaL_error(L, "unsupported module type %s", lua_typename(L, lua_type(L, in_base))); // doesn't return } - STACK_CHECK( L, 0); + STACK_CHECK(L, 0); } // ################################################################################################# @@ -609,38 +541,34 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; */ [[nodiscard]] static lua_Integer get_mt_id(Universe* U, lua_State* L, int i) { - lua_Integer id; + i = lua_absindex(L, i); - i = lua_absindex( L, i); - - STACK_GROW( L, 3); + STACK_GROW(L, 3); STACK_CHECK_START_REL(L, 0); - push_registry_subtable( L, REG_MTID); // ... _R[REG_MTID] - lua_pushvalue( L, i); // ... _R[REG_MTID] {mt} - lua_rawget( L, -2); // ... _R[REG_MTID] mtk? + push_registry_subtable(L, REG_MTID); // ... _R[REG_MTID] + lua_pushvalue(L, i); // ... _R[REG_MTID] {mt} + lua_rawget(L, -2); // ... _R[REG_MTID] mtk? - id = lua_tointeger( L, -1); // 0 for nil - lua_pop( L, 1); // ... _R[REG_MTID] - STACK_CHECK( L, 1); + lua_Integer id{ lua_tointeger(L, -1) }; // 0 for nil + lua_pop(L, 1); // ... _R[REG_MTID] + STACK_CHECK(L, 1); - if( id == 0) + if (id == 0) { id = U->next_mt_id.fetch_add(1, std::memory_order_relaxed); - /* Create two-way references: id_uint <-> table - */ - lua_pushvalue( L, i); // ... _R[REG_MTID] {mt} - lua_pushinteger( L, id); // ... _R[REG_MTID] {mt} id - lua_rawset( L, -3); // ... _R[REG_MTID] + // Create two-way references: id_uint <-> table + lua_pushvalue(L, i); // ... _R[REG_MTID] {mt} + lua_pushinteger(L, id); // ... _R[REG_MTID] {mt} id + lua_rawset(L, -3); // ... _R[REG_MTID] - lua_pushinteger( L, id); // ... _R[REG_MTID] id - lua_pushvalue( L, i); // ... _R[REG_MTID] id {mt} - lua_rawset( L, -3); // ... _R[REG_MTID] + lua_pushinteger(L, id); // ... _R[REG_MTID] id + lua_pushvalue(L, i); // ... _R[REG_MTID] id {mt} + lua_rawset(L, -3); // ... _R[REG_MTID] } - lua_pop( L, 1); // ... - - STACK_CHECK( L, 0); + lua_pop(L, 1); // ... + STACK_CHECK(L, 0); return id; } @@ -684,7 +612,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; if (mode_ == LookupMode::FromKeeper) { lua_CFunction f = lua_tocfunction( L, i); // should *always* be func_lookup_sentinel or table_lookup_sentinel! - if( f == func_lookup_sentinel || f == table_lookup_sentinel || f == userdata_clone_sentinel) + if (f == func_lookup_sentinel || f == table_lookup_sentinel || f == userdata_clone_sentinel) { lua_getupvalue( L, i, 1); // ... v ... "f.q.n" } @@ -722,7 +650,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; typewhat = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : luaL_typename( L, -2); // second return value can be nil if the table was not found // probable reason: the function was removed from the source Lua state before Lanes was required. - if( lua_isnil( L, -1)) + if (lua_isnil( L, -1)) { gotchaA = " referenced by"; gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)"; @@ -744,22 +672,20 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; // ################################################################################################# -/* - * Push a looked-up table, or nothing if we found nothing - */ -[[nodiscard]] static bool lookup_table(Dest L2, Source L1, SourceIndex i_, LookupMode mode_, char const* upName_) +// Push a looked-up table, or nothing if we found nothing +[[nodiscard]] bool InterCopyContext::lookup_table() const { // get the name of the table we want to send size_t len; - char const* fqn = find_lookup_name(L1, i_, mode_, upName_, &len); + char const* fqn = find_lookup_name(L1, L1_i, mode, name, &len); if (nullptr == fqn) // name not found, it is some user-created table { return false; } // push the equivalent table in the destination's stack, retrieved from the lookup table STACK_CHECK_START_REL(L2, 0); // L // L2 - STACK_GROW( L2, 3); // up to 3 slots are necessary on error - switch( mode_) + STACK_GROW(L2, 3); // up to 3 slots are necessary on error + switch (mode) { default: // shouldn't happen, in theory... luaL_error(L1, "internal error: unknown lookup mode"); // doesn't return @@ -780,7 +706,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; lua_rawget(L2, -2); // {} t // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead) // but not when we extract something out of a keeper, as there is nothing to clone! - if (lua_isnil(L2, -1) && mode_ == LookupMode::LaneBody) + if (lua_isnil(L2, -1) && mode == LookupMode::LaneBody) { lua_pop(L2, 2); // STACK_CHECK(L2, 0); @@ -797,7 +723,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; lua_pop(L2, 1); // {} t // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error luaL_error( - (mode_ == LookupMode::FromKeeper) ? L2 : L1 + (mode == LookupMode::FromKeeper) ? L2 : L1 , "INTERNAL ERROR IN %s: table '%s' not found in %s destination transfer database." , from ? from : "main" , fqn @@ -808,7 +734,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; lua_remove(L2, -2); // t break; } - STACK_CHECK( L2, 1); + STACK_CHECK(L2, 1); return true; } @@ -877,7 +803,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; lua_pushvalue(L, -1); // o "r" {c} {fqn} ... {?} {?} lua_rawget(L, cache); // o "r" {c} {fqn} ... {?} nil/1 // if table is already visited, we are done - if( !lua_isnil(L, -1)) + if (!lua_isnil(L, -1)) { lua_pop(L, 1); // o "r" {c} {fqn} ... {?} return shortest_; @@ -902,7 +828,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; { STACK_CHECK(L, 2); // update shortest name - if( depth_ < shortest_) + if (depth_ < shortest_) { shortest_ = depth_; std::ignore = luaG_pushFQN(L, fqn, depth_, nullptr); // o "r" {c} {fqn} ... {?} k v "fqn" @@ -924,7 +850,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; // search in the table's metatable too if (lua_getmetatable(L, -1)) // o "r" {c} {fqn} ... {?} k {} {mt} { - if( lua_istable(L, -1)) + if (lua_istable(L, -1)) { ++ depth_; lua_pushliteral(L, "__metatable"); // o "r" {c} {fqn} ... {?} k {} {mt} "__metatable" @@ -966,7 +892,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; int uvi = 1; while (lua_getiuservalue(L, -1, uvi) != LUA_TNONE) // o "r" {c} {fqn} ... {?} k U {u} { - if( lua_istable(L, -1)) // if it is a table, look inside + if (lua_istable(L, -1)) // if it is a table, look inside { ++ depth_; lua_pushliteral(L, "uservalue"); // o "r" {c} {fqn} ... {?} k v {u} "uservalue" @@ -1010,13 +936,13 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; int luaG_nameof( lua_State* L) { int what = lua_gettop( L); - if( what > 1) + if (what > 1) { luaL_argerror( L, what, "too many arguments."); } // nil, boolean, light userdata, number and string aren't identifiable - if( lua_type( L, 1) < LUA_TTABLE) + if (lua_type( L, 1) < LUA_TTABLE) { lua_pushstring( L, luaL_typename( L, 1)); // o "type" lua_insert( L, -2); // "type" o @@ -1036,7 +962,7 @@ int luaG_nameof( lua_State* L) // this is where we start the search lua_pushglobaltable( L); // o nil {c} {fqn} _G (void) discover_object_name_recur( L, 6666, 1); - if( lua_isnil( L, 2)) // try again with registry, just in case... + if (lua_isnil( L, 2)) // try again with registry, just in case... { lua_pop( L, 1); // o nil {c} {fqn} lua_pushliteral( L, "_R"); // o nil {c} {fqn} "_R" @@ -1056,56 +982,56 @@ int luaG_nameof( lua_State* L) /* * Push a looked-up native/LuaJIT function. */ -static void lookup_native_func(lua_State* L2, lua_State* L, int i, LookupMode mode_, char const* upName_) +void InterCopyContext::lookup_native_func() const { // get the name of the function we want to send size_t len; - char const* fqn = find_lookup_name( L, i, mode_, upName_, &len); + char const* fqn = find_lookup_name(L1, L1_i, mode, name, &len); // push the equivalent function in the destination's stack, retrieved from the lookup table - STACK_CHECK_START_REL(L2, 0); // L // L2 - STACK_GROW( L2, 3); // up to 3 slots are necessary on error - switch( mode_) + STACK_CHECK_START_REL(L2, 0); // L1 // L2 + STACK_GROW(L2, 3); // up to 3 slots are necessary on error + switch (mode) { default: // shouldn't happen, in theory... - (void) luaL_error( L, "internal error: unknown lookup mode"); - return; + luaL_error(L1, "internal error: unknown lookup mode"); // doesn't return + break; case LookupMode::ToKeeper: // push a sentinel closure that holds the lookup name as upvalue - lua_pushlstring( L2, fqn, len); // "f.q.n" - lua_pushcclosure( L2, func_lookup_sentinel, 1); // f + lua_pushlstring(L2, fqn, len); // "f.q.n" + lua_pushcclosure(L2, func_lookup_sentinel, 1); // f break; case LookupMode::LaneBody: case LookupMode::FromKeeper: LOOKUP_REGKEY.pushValue(L2); // {} - STACK_CHECK( L2, 1); - ASSERT_L( lua_istable( L2, -1)); - lua_pushlstring( L2, fqn, len); // {} "f.q.n" - lua_rawget( L2, -2); // {} f + STACK_CHECK(L2, 1); + _ASSERT_L(L1, lua_istable(L2, -1)); + lua_pushlstring(L2, fqn, len); // {} "f.q.n" + lua_rawget(L2, -2); // {} f // nil means we don't know how to transfer stuff: user should do something // anything other than function or table should not happen! - if( !lua_isfunction( L2, -1) && !lua_istable( L2, -1)) + if (!lua_isfunction( L2, -1) && !lua_istable( L2, -1)) { char const* from, * to; - lua_getglobal( L, "decoda_name"); // ... f ... decoda_name - from = lua_tostring( L, -1); - lua_pop( L, 1); // ... f ... - lua_getglobal( L2, "decoda_name"); // {} f decoda_name - to = lua_tostring( L2, -1); - lua_pop( L2, 1); // {} f + lua_getglobal(L1, "decoda_name"); // ... f ... decoda_name + from = lua_tostring(L1, -1); + lua_pop(L1, 1); // ... f ... + lua_getglobal(L2, "decoda_name"); // {} f decoda_name + to = lua_tostring(L2, -1); + lua_pop(L2, 1); // {} f // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error (void) luaL_error( - (mode_ == LookupMode::FromKeeper) ? L2 : L + (mode == LookupMode::FromKeeper) ? L2 : L1 , "%s%s: function '%s' not found in %s destination transfer database." - , lua_isnil( L2, -1) ? "" : "INTERNAL ERROR IN " + , lua_isnil(L2, -1) ? "" : "INTERNAL ERROR IN " , from ? from : "main" , fqn , to ? to : "main" ); return; } - lua_remove( L2, -2); // f + lua_remove(L2, -2); // f break; /* keep it in case I need it someday, who knows... @@ -1115,7 +1041,7 @@ static void lookup_native_func(lua_State* L2, lua_State* L, int i, LookupMode mo char const* upname; lua_CFunction f = lua_tocfunction( L, i); // copy upvalues - for( n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != nullptr; ++ n) + for (n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != nullptr; ++ n) { luaG_inter_move( U, L, L2, 1, mode_); // [up[,up ...]] } @@ -1166,7 +1092,7 @@ static char const* vt_names[] = [[nodiscard]] static int buf_writer(lua_State* L, void const* b, size_t size, void* ud) { luaL_Buffer* B = (luaL_Buffer*) ud; - if( !B->L) + if (!B->L) { luaL_buffinit( L, B); } @@ -1278,7 +1204,7 @@ void InterCopyContext::copy_func() const { // ... _G up[n] DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "UPNAME[%d]: %s -> " INDENT_END, n, c.name)); #if LUA_VERSION_NUM >= 502 - if( lua_rawequal(L1, -1, -2)) // is the upvalue equal to the global table? + if (lua_rawequal(L1, -1, -2)) // is the upvalue equal to the global table? { DEBUGSPEW_CODE(fprintf(stderr, "pushing destination global scope\n")); lua_pushglobaltable(L2); // ... {cache} ... function <upvalues> @@ -1331,8 +1257,7 @@ void InterCopyContext::copy_func() const */ void InterCopyContext::copy_cached_func() const { - FuncSubType funcSubType; - std::ignore = luaG_tocfunction(L1, L1_i, &funcSubType); // nullptr for LuaJIT-fast && bytecode functions + FuncSubType const funcSubType{ luaG_getfuncsubtype(L1, L1_i) }; if (funcSubType == FST_Bytecode) { void* const aspointer = const_cast<void*>(lua_topointer(L1, L1_i)); @@ -1376,7 +1301,7 @@ void InterCopyContext::copy_cached_func() const } else // function is native/LuaJIT: no need to cache { - lookup_native_func(L2, L1, L1_i, mode, name); // ... {cache} ... function + lookup_native_func(); // ... {cache} ... function // if the function was in fact a lookup sentinel, we can either get a function or a table here _ASSERT_L(L1, lua_isfunction(L2, -1) || lua_istable(L2, -1)); } @@ -1440,7 +1365,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const SourceIndex const val_i{ lua_gettop(L1) }; SourceIndex const key_i{ val_i - 1 }; - // Only basic key types are copied over; others ignored + // For the key, only basic key types are copied over. others ignored InterCopyContext c{ U, L2, L1, L2_cache_i, key_i, VT::KEY, mode, name }; if (!c.inter_copy_one()) { @@ -1451,7 +1376,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const } char* valPath{ nullptr }; - if( U->verboseErrors) + if (U->verboseErrors) { // for debug purposes, let's try to build a useful name if (lua_type(L1, key_i) == LUA_TSTRING) @@ -1483,20 +1408,17 @@ void InterCopyContext::inter_copy_keyvaluepair() const valPath = (char*) alloca(strlen(name) + 16 + 5); sprintf(valPath, "%s[U:%p]", name, key); } - else if( lua_type( L1, key_i) == LUA_TBOOLEAN) + else if (lua_type( L1, key_i) == LUA_TBOOLEAN) { int const key{ lua_toboolean(L1, key_i) }; valPath = (char*) alloca(strlen(name) + 8); sprintf(valPath, "%s[%s]", name, key ? "true" : "false"); } } - /* - * Contents of metatables are copied with cache checking; - * important to detect loops. - */ c.L1_i = SourceIndex{ val_i }; - c.name = valPath ? valPath : name; + // Contents of metatables are copied with cache checking. important to detect loops. c.vt = VT::NORMAL; + c.name = valPath ? valPath : name; if (c.inter_copy_one()) { _ASSERT_L(L1, lua_istable( L2, -3)); @@ -1539,7 +1461,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; STACK_CHECK(L2, 0); // no metatable? -> not clonable - if( !lua_getmetatable(L1, L1_i)) // ... mt? + if (!lua_getmetatable(L1, L1_i)) // ... mt? { STACK_CHECK(L1, 0); return false; @@ -1547,7 +1469,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; // no __lanesclone? -> not clonable lua_getfield(L1, -1, "__lanesclone"); // ... mt __lanesclone? - if( lua_isnil(L1, -1)) + if (lua_isnil(L1, -1)) { lua_pop(L1, 2); // ... STACK_CHECK(L1, 0); @@ -1565,12 +1487,12 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; lua_pop(L1, 1); // ... mt __lanesclone [uv]+ -- uvi; // create the clone userdata with the required number of uservalue slots - void* clone = lua_newuserdatauv(L2, userdata_size, uvi); // ... u + void* const clone{ lua_newuserdatauv(L2, userdata_size, uvi) }; // ... u // copy the metatable in the target state, and give it to the clone we put there InterCopyContext c{ U, L2, L1, L2_cache_i, SourceIndex{ mt }, VT::NORMAL, mode, name }; if (c.inter_copy_one()) // ... u mt|sentinel { - if( LookupMode::ToKeeper == mode) // ... u sentinel + if (LookupMode::ToKeeper == mode) // ... u sentinel { _ASSERT_L(L1, lua_tocfunction(L2, -1) == table_lookup_sentinel); // we want to create a new closure with a 'clone sentinel' function, where the upvalues are the userdata and the metatable fqn @@ -1645,7 +1567,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; } // try clonable userdata first - if( copyclone()) + if (copyclone()) { STACK_CHECK(L1, 0); STACK_CHECK(L2, 1); @@ -1714,8 +1636,8 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; } lua_pop(L2, 1); // ... - // this function has 2 upvalues: the fqn of its metatable, and the userdata itself - bool const found{ lookup_table(L2, L1, L1_i, mode, name) }; // ... mt? + // userdata_clone_sentinel has 2 upvalues: the fqn of its metatable, and the userdata itself + bool const found{ lookup_table() }; // ... mt? if (!found) { STACK_CHECK(L2, 0); @@ -1802,7 +1724,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; * 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?) * Note that this table CAN be a module table, but we just didn't register it, in which case we'll send it through the table cloning mechanism */ - if (lookup_table(L2, L1, L1_i, mode, name)) + if (lookup_table()) { _ASSERT_L(L1, lua_istable(L2, -1) || (lua_tocfunction(L2, -1) == table_lookup_sentinel)); // from lookup data. can also be table_lookup_sentinel if this is a table we know return true; @@ -1849,6 +1771,71 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; // ################################################################################################# +[[nodiscard]] bool InterCopyContext::inter_copy_boolean() const +{ + int const v{ lua_toboolean(L1, L1_i) }; + DEBUGSPEW_CODE(fprintf(stderr, "%s\n", v ? "true" : "false")); + lua_pushboolean(L2, v); + return true; +} + +// ################################################################################################# + +[[nodiscard]] bool InterCopyContext::inter_copy_lightuserdata() const +{ + void* const p{ lua_touserdata(L1, L1_i) }; + DEBUGSPEW_CODE(fprintf(stderr, "%p\n", p)); + lua_pushlightuserdata(L2, p); + return true; +} + +// ################################################################################################# + +[[nodiscard]] bool InterCopyContext::inter_copy_nil() const +{ + if (vt == VT::KEY) + { + return false; + } + lua_pushnil(L2); + return true; +} + +// ################################################################################################# + +[[nodiscard]] bool InterCopyContext::inter_copy_number() const +{ + /* LNUM patch support (keeping integer accuracy) */ +#if defined LUA_LNUM || LUA_VERSION_NUM >= 503 + if (lua_isinteger(L1, L1_i)) + { + lua_Integer const v{ lua_tointeger(L1, L1_i) }; + DEBUGSPEW_CODE(fprintf(stderr, LUA_INTEGER_FMT "\n", v)); + lua_pushinteger(L2, v); + } + else +#endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 + { + lua_Number const v{ lua_tonumber(L1, L1_i) }; + DEBUGSPEW_CODE(fprintf(stderr, LUA_NUMBER_FMT "\n", v)); + lua_pushnumber(L2, v); + } + return true; +} + +// ################################################################################################# + +[[nodiscard]] bool InterCopyContext::inter_copy_string() const +{ + size_t len; + char const* const s{ lua_tolstring(L1, L1_i, &len) }; + DEBUGSPEW_CODE(fprintf(stderr, "'%s'\n", s)); + lua_pushlstring(L2, s, len); + return true; +} + +// ################################################################################################# + /* * Copies a value from 'L1' state (at index 'i') to 'L2' state. Does not remove * the original value. @@ -1878,7 +1865,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; if (lua_getmetatable(L1, L1_i)) // ... mt { lua_getfield(L1, -1, "__lanesignore"); // ... mt ignore? - if( lua_isboolean(L1, -1) && lua_toboolean(L1, -1)) + if (lua_isboolean(L1, -1) && lua_toboolean(L1, -1)) { DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "__lanesignore -> LUA_TNIL\n" INDENT_END)); val_type = LuaType::NIL; @@ -1892,81 +1879,21 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; bool ret{ true }; switch (val_type) { - /* Basic types allowed both as values, and as table keys */ - - case LuaType::BOOLEAN: - { - int const v{ lua_toboolean(L1, L1_i) }; - DEBUGSPEW_CODE( fprintf(stderr, "%s\n", v ? "true" : "false")); - lua_pushboolean(L2, v); - } - break; - - case LuaType::NUMBER: - /* LNUM patch support (keeping integer accuracy) */ -#if defined LUA_LNUM || LUA_VERSION_NUM >= 503 - if( lua_isinteger(L1, L1_i)) - { - lua_Integer const v{ lua_tointeger(L1, L1_i) }; - DEBUGSPEW_CODE(fprintf(stderr, LUA_INTEGER_FMT "\n", v)); - lua_pushinteger(L2, v); - break; - } - else -#endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 - { - lua_Number const v{ lua_tonumber(L1, L1_i) }; - DEBUGSPEW_CODE(fprintf(stderr, LUA_NUMBER_FMT "\n", v)); - lua_pushnumber(L2, v); - } - break; - - case LuaType::STRING: - { - size_t len; - char const* const s{ lua_tolstring(L1, L1_i, &len) }; - DEBUGSPEW_CODE(fprintf(stderr, "'%s'\n", s)); - lua_pushlstring(L2, s, len); - } - break; - - case LuaType::LIGHTUSERDATA: - { - void* const p{ lua_touserdata(L1, L1_i) }; - DEBUGSPEW_CODE(fprintf(stderr, "%p\n", p)); - lua_pushlightuserdata(L2, p); - } - break; - - /* The following types are not allowed as table keys */ - - case LuaType::USERDATA: - ret = inter_copy_userdata(); - break; - - case LuaType::NIL: - if (vt == VT::KEY) - { - ret = false; - break; - } - lua_pushnil( L2); - break; - - case LuaType::FUNCTION: - ret = inter_copy_function(); - break; - - case LuaType::TABLE: - ret = inter_copy_table(); - break; - - /* The following types cannot be copied */ - - case LuaType::CDATA: - case LuaType::THREAD: - ret = false; - break; + // Basic types allowed both as values, and as table keys + case LuaType::BOOLEAN: ret = inter_copy_boolean(); break; + case LuaType::NUMBER: ret = inter_copy_number(); break; + case LuaType::STRING: ret = inter_copy_string(); break; + case LuaType::LIGHTUSERDATA: ret = inter_copy_lightuserdata();break; + + // The following types are not allowed as table keys + case LuaType::USERDATA: ret = inter_copy_userdata(); break; + case LuaType::NIL: ret = inter_copy_nil(); break; + case LuaType::FUNCTION: ret = inter_copy_function(); break; + case LuaType::TABLE: ret = inter_copy_table(); break; + + // The following types cannot be copied + case LuaType::CDATA: [[fallthrough]]; + case LuaType::THREAD: ret = false; break; } STACK_CHECK(L2, ret ? 1 : 0); diff --git a/src/tools.h b/src/tools.h index 06646d3..ddf5c67 100644 --- a/src/tools.h +++ b/src/tools.h @@ -6,13 +6,7 @@ // forwards class Universe; -// ################################################################################################ - -#ifdef _DEBUG -void luaG_dump(lua_State* L); -#endif // _DEBUG - -// ################################################################################################ +// ################################################################################################# void push_registry_subtable_mode(lua_State* L, UniqueKey key_, const char* mode_); void push_registry_subtable(lua_State* L, UniqueKey key_); @@ -31,12 +25,13 @@ enum class InterCopyResult Error }; -// ################################################################################################ +// ################################################################################################# using CacheIndex = Unique<int>; using SourceIndex = Unique<int>; -struct InterCopyContext +class InterCopyContext { + public: Universe* const U; Dest const L2; @@ -47,35 +42,50 @@ struct InterCopyContext LookupMode const mode; char const* name; // that one can change when we reuse the context - [[nodiscard]] bool inter_copy_one() const; - private: - [[nodiscard]] bool inter_copy_userdata() const; - [[nodiscard]] bool inter_copy_function() const; - [[nodiscard]] bool inter_copy_table() const; - [[nodiscard]] bool copyclone() const; - [[nodiscard]] bool copydeep() const; - [[nodiscard]] bool push_cached_metatable() const; + // for use in copy_cached_func void copy_func() const; + void lookup_native_func() const; + + // for use in inter_copy_function void copy_cached_func() const; + [[nodiscard]] bool lookup_table() const; + + // for use in inter_copy_table void inter_copy_keyvaluepair() const; + [[nodiscard]] bool push_cached_metatable() const; + + // for use in inter_copy_userdata + [[nodiscard]] bool copyclone() const; + [[nodiscard]] bool copydeep() const; + + // copying a single Lua stack item + [[nodiscard]] bool inter_copy_boolean() const; + [[nodiscard]] bool inter_copy_function() const; + [[nodiscard]] bool inter_copy_lightuserdata() const; + [[nodiscard]] bool inter_copy_nil() const; + [[nodiscard]] bool inter_copy_number() const; + [[nodiscard]] bool inter_copy_string() const; + [[nodiscard]] bool inter_copy_table() const; + [[nodiscard]] bool inter_copy_userdata() const; public: + [[nodiscard]] bool inter_copy_one() const; [[nodiscard]] InterCopyResult inter_copy_package() const; [[nodiscard]] InterCopyResult inter_copy(int n_) const; [[nodiscard]] InterCopyResult inter_move(int n_) const; }; -// ################################################################################################ +// ################################################################################################# [[nodiscard]] int luaG_nameof(lua_State* L); void populate_func_lookup_table(lua_State* L, int _i, char const* _name); void initialize_allocator_function(Universe* U, lua_State* L); -// ################################################################################################ +// ################################################################################################# // crc64/we of string "CONFIG_REGKEY" generated at http://www.nitrxgen.net/hashgen/ static constexpr UniqueKey CONFIG_REGKEY{ 0x31cd24894eae8624ull }; // registry key to access the configuration diff --git a/src/uniquekey.h b/src/uniquekey.h index 78c0765..84553a5 100644 --- a/src/uniquekey.h +++ b/src/uniquekey.h @@ -44,8 +44,10 @@ class UniqueKey } void pushValue(lua_State* const L) const { + STACK_CHECK_START_REL(L, 0); pushKey(L); lua_rawget(L, LUA_REGISTRYINDEX); + STACK_CHECK(L, 1); } template <typename OP> void setValue(lua_State* L, OP operation_) const diff --git a/src/universe.cpp b/src/universe.cpp index 4c53987..a02a5e6 100644 --- a/src/universe.cpp +++ b/src/universe.cpp @@ -41,7 +41,7 @@ static constexpr UniqueKey UNIVERSE_FULL_REGKEY{ 0x99CA130C09EDC074ull }; // xxh64 of string "UNIVERSE_LIGHT_REGKEY" generated at http://www.nitrxgen.net/hashgen/ static constexpr UniqueKey UNIVERSE_LIGHT_REGKEY{ 0x3663C07C742CEB81ull }; -// ################################################################################################ +// ################################################################################################# Universe::Universe() { @@ -70,13 +70,13 @@ Universe::Universe() #endif // PLATFORM_LINUX } -// ################################################################################################ +// ################################################################################################# // only called from the master state Universe* universe_create(lua_State* L) { ASSERT_L(universe_get(L) == nullptr); - Universe* const U = static_cast<Universe*>(lua_newuserdatauv(L, sizeof(Universe), 0)); // universe + Universe* const U{ lua_newuserdatauv<Universe>(L, 0) }; // universe U->Universe::Universe(); STACK_CHECK_START_REL(L, 1); UNIVERSE_FULL_REGKEY.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); @@ -85,7 +85,7 @@ Universe* universe_create(lua_State* L) return U; } -// ################################################################################################ +// ################################################################################################# void universe_store(lua_State* L, Universe* U) { @@ -95,7 +95,7 @@ void universe_store(lua_State* L, Universe* U) STACK_CHECK(L, 0); } -// ################################################################################################ +// ################################################################################################# Universe* universe_get(lua_State* L) { diff --git a/src/universe.h b/src/universe.h index eb85133..320c400 100644 --- a/src/universe.h +++ b/src/universe.h @@ -13,7 +13,7 @@ extern "C" { #include <mutex> -// ################################################################################################ +// ################################################################################################# // forwards struct DeepPrelude; @@ -25,7 +25,7 @@ class Lane; */ #define HAVE_LANE_TRACKING() 1 -// ################################################################################################ +// ################################################################################################# // everything we need to provide to lua_newstate() class AllocatorDefinition @@ -35,6 +35,7 @@ class AllocatorDefinition lua_Alloc m_allocF{ nullptr }; void* m_allocUD{ nullptr }; + [[nodiscard]] static void* operator new(size_t size_) noexcept = delete; // can't create one outside of a Lua state [[nodiscard]] static void* operator new(size_t size_, lua_State* L) noexcept { return lua_newuserdatauv(L, size_, 0); } // always embedded somewhere else or "in-place constructed" as a full userdata // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception @@ -72,7 +73,7 @@ class AllocatorDefinition } }; -// ################################################################################################ +// ################################################################################################# // mutex-protected allocator for use with Lua states that share a non-threadsafe allocator class ProtectedAllocator : public AllocatorDefinition @@ -115,7 +116,7 @@ class ProtectedAllocator : public AllocatorDefinition } }; -// ################################################################################################ +// ################################################################################################# // everything regarding the Lanes universe is stored in that global structure // held as a full userdata in the master Lua state that required it for the first time @@ -183,13 +184,13 @@ class Universe Universe& operator=(Universe&&) = delete; }; -// ################################################################################################ +// ################################################################################################# [[nodiscard]] Universe* universe_get(lua_State* L); [[nodiscard]] Universe* universe_create(lua_State* L); void universe_store(lua_State* L, Universe* U); -// ################################################################################################ +// ################################################################################################# #if USE_DEBUG_SPEW() class DebugSpewIndentScope -- cgit v1.2.3-55-g6feb