From 9e3ca50cfafa0d7dc3e15f3b6a635aef6a938b80 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Wed, 27 Mar 2024 10:37:05 +0100 Subject: C++ migration: new helper templates lua_tolightuserdata and lua_tofulluserdata --- src/deep.cpp | 38 +++++++++++++++++--------------------- src/deep.h | 11 ++++++----- src/keeper.cpp | 19 ++++++++++++------- src/lanes.cpp | 10 +++++----- src/lanes_private.h | 2 +- src/linda.cpp | 2 +- src/macros_and_utils.h | 20 ++++++++++++++++++-- src/state.cpp | 2 +- src/universe.cpp | 20 +++++++++++++------- 9 files changed, 74 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/deep.cpp b/src/deep.cpp index f091d4d..e62ca6d 100644 --- a/src/deep.cpp +++ b/src/deep.cpp @@ -108,12 +108,12 @@ static void get_deep_lookup( lua_State* L) * Return the registered ID function for 'index' (deep userdata proxy), * or nullptr if 'index' is not a deep userdata proxy. */ -static inline luaG_IdFunction* get_idfunc( lua_State* L, int index, LookupMode mode_) +static inline luaG_IdFunction get_idfunc( lua_State* L, int index, LookupMode mode_) { // when looking inside a keeper, we are 100% sure the object is a deep userdata if( mode_ == eLM_FromKeeper) { - DeepPrelude** const proxy{ lua_touserdata(L, index) }; + DeepPrelude** const proxy{ lua_tofulluserdata(L, index) }; // we can (and must) cast and fetch the internally stored idfunc return (*proxy)->idfunc; } @@ -133,7 +133,7 @@ static inline luaG_IdFunction* get_idfunc( lua_State* L, int index, LookupMode m // replace metatable with the idfunc pointer, if it is actually a deep userdata get_deep_lookup( L); // deep ... idfunc|nil - luaG_IdFunction* const ret{ lua_touserdata(L, -1) }; // nullptr if not a userdata + luaG_IdFunction const ret{ *lua_tolightuserdata(L, -1) }; // nullptr if not a userdata lua_pop( L, 1); STACK_CHECK( L, 0); return ret; @@ -161,7 +161,7 @@ void free_deep_prelude( lua_State* L, DeepPrelude* prelude_) */ static int deep_userdata_gc( lua_State* L) { - DeepPrelude** const proxy{ lua_touserdata(L, 1) }; + DeepPrelude** const proxy{ lua_tofulluserdata(L, 1) }; DeepPrelude* p = *proxy; // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded @@ -203,8 +203,6 @@ static int deep_userdata_gc( lua_State* L) */ char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_) { - DeepPrelude** proxy; - // Check if a proxy already exists push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC lua_pushlightuserdata( L, prelude); // DPC deep @@ -223,7 +221,7 @@ char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, Lookup STACK_CHECK_START_REL(L, 0); // a new full userdata, fitted with the specified number of uservalue slots (always 1 for Lua < 5.4) - proxy = (DeepPrelude**) lua_newuserdatauv( L, sizeof(DeepPrelude*), nuv_); // DPC proxy + DeepPrelude** proxy = (DeepPrelude**) lua_newuserdatauv(L, sizeof(DeepPrelude*), 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 @@ -333,9 +331,9 @@ char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, Lookup } } } - STACK_CHECK( L, 2); // DPC proxy metatable - ASSERT_L( lua_isuserdata( L, -2)); - ASSERT_L( lua_istable( L, -1)); + STACK_CHECK(L, 2); // DPC proxy metatable + ASSERT_L(lua_type(L, -2) == LUA_TUSERDATA); + ASSERT_L(lua_istable( L, -1)); lua_setmetatable( L, -2); // DPC proxy // If we're here, we obviously had to create a new proxy, so cache it. @@ -343,8 +341,8 @@ char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, Lookup lua_pushvalue( L, -2); // DPC proxy deep proxy lua_rawset( L, -4); // DPC proxy lua_remove( L, -2); // proxy - ASSERT_L( lua_isuserdata( L, -1)); - STACK_CHECK( L, 0); + ASSERT_L(lua_type(L, -1) == LUA_TUSERDATA); + STACK_CHECK(L, 0); return nullptr; } @@ -370,7 +368,7 @@ char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, Lookup * * Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' */ -int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_) +int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc, int nuv_) { STACK_GROW( L, 1); STACK_CHECK_START_REL(L, 0); @@ -416,7 +414,7 @@ int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_) * Reference count is not changed, and access to the deep userdata is not * serialized. It is the module's responsibility to prevent conflicting usage. */ -void* luaG_todeep( lua_State* L, luaG_IdFunction* idfunc, int index) +DeepPrelude* luaG_todeep(lua_State* L, luaG_IdFunction idfunc, int index) { STACK_CHECK_START_REL(L, 0); // ensure it is actually a deep userdata @@ -426,7 +424,7 @@ void* luaG_todeep( lua_State* L, luaG_IdFunction* idfunc, int index) } STACK_CHECK(L, 0); - DeepPrelude** const proxy{ lua_touserdata(L, index) }; + DeepPrelude** const proxy{ lua_tofulluserdata(L, index) }; return *proxy; } @@ -441,10 +439,7 @@ void* luaG_todeep( lua_State* L, luaG_IdFunction* idfunc, int index) */ bool copydeep(Universe* U, lua_State* L2, int L2_cache_i, lua_State* L, int i, LookupMode mode_, char const* upName_) { - char const* errmsg; - luaG_IdFunction* idfunc = get_idfunc( L, i, mode_); - int nuv = 0; - + luaG_IdFunction const idfunc { get_idfunc(L, i, mode_) }; if (idfunc == nullptr) { return false; // not a deep userdata @@ -454,7 +449,8 @@ bool copydeep(Universe* U, lua_State* L2, int L2_cache_i, lua_State* L, int i, L STACK_CHECK_START_REL(L2, 0); // extract all uservalues of the source - while( lua_getiuservalue( L, i, nuv + 1) != LUA_TNONE) // ... u [uv]* nil + int nuv = 0; + while (lua_getiuservalue(L, i, nuv + 1) != LUA_TNONE) // ... u [uv]* nil { ++ nuv; } @@ -462,7 +458,7 @@ bool copydeep(Universe* U, lua_State* L2, int L2_cache_i, lua_State* L, int i, L lua_pop( L, 1); // ... u [uv]* STACK_CHECK( L, nuv); - errmsg = push_deep_proxy(L2, *lua_touserdata(L, i), nuv, mode_); // u + char const* errmsg{ push_deep_proxy(L2, *lua_tofulluserdata(L, i), nuv, mode_) }; // u // transfer all uservalues of the source in the destination { diff --git a/src/deep.h b/src/deep.h index 878fa63..2983427 100644 --- a/src/deep.h +++ b/src/deep.h @@ -36,19 +36,20 @@ enum DeepOp eDO_module, }; -using luaG_IdFunction = void*( lua_State* L, DeepOp op_); +using luaG_IdFunction = void*(*)( lua_State* L, DeepOp op_); // ################################################################################################ // xxh64 of string "DEEP_VERSION_3" generated at https://www.pelock.com/products/hash-calculator static constexpr UniqueKey DEEP_VERSION{ 0xB2CC0FD9C0AE9674ull }; -// should be used as header for full userdata +// should be used as header for deep userdata +// a deep userdata is a full userdata that stores a single pointer to the actual DeepPrelude-derived object struct DeepPrelude { UniqueKey const magic{ DEEP_VERSION }; // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc - luaG_IdFunction* idfunc { nullptr }; + luaG_IdFunction idfunc { nullptr }; // data is destroyed when refcount is 0 std::atomic m_refcount{ 0 }; }; @@ -56,5 +57,5 @@ struct DeepPrelude char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_); void free_deep_prelude( lua_State* L, DeepPrelude* prelude_); -LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_); -LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction* idfunc, int index); +LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc, int nuv_); +LANES_API DeepPrelude* luaG_todeep(lua_State* L, luaG_IdFunction idfunc, int index); diff --git a/src/keeper.cpp b/src/keeper.cpp index 35b5ea8..e0a9fdc 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp @@ -64,6 +64,11 @@ class keeper_fifo // 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 static void operator delete(void* p_, lua_State* L){ ASSERT_L(!"should never be called") }; + + static keeper_fifo* getPtr(lua_State* L, int idx_) + { + return lua_tofulluserdata(L, idx_); + } }; static constexpr int CONTENTS_TABLE{ 1 }; @@ -73,7 +78,7 @@ static constexpr int CONTENTS_TABLE{ 1 }; // replaces the fifo ud by its uservalue on the stack static keeper_fifo* prepare_fifo_access(lua_State* L, int idx_) { - keeper_fifo* const fifo{ lua_touserdata(L, idx_) }; + keeper_fifo* const fifo{ keeper_fifo::getPtr(L, idx_) }; if (fifo != nullptr) { idx_ = lua_absindex(L, idx_); @@ -284,8 +289,8 @@ int keepercall_send(lua_State* L) lua_rawset(L, -4); // ud key ... fifos fifo } lua_remove(L, -2); // ud key ... fifo - keeper_fifo* fifo{ lua_touserdata(L, -1) }; - if( fifo->limit >= 0 && fifo->count + n > fifo->limit) + keeper_fifo* fifo{ keeper_fifo::getPtr(L, -1) }; + if (fifo->limit >= 0 && fifo->count + n > fifo->limit) { lua_settop(L, 0); // lua_pushboolean(L, 0); // false @@ -382,12 +387,12 @@ int keepercall_limit(lua_State* L) lua_pop(L, 1); // fifos key lua_pushvalue(L, -1); // fifos key key lua_rawget(L, -3); // fifos key fifo|nil - keeper_fifo* fifo{ lua_touserdata(L, -1) }; + keeper_fifo* fifo{ keeper_fifo::getPtr(L, -1) }; if (fifo == nullptr) { // fifos key nil lua_pop(L, 1); // fifos key fifo_new(L); // fifos key fifo - fifo = lua_touserdata(L, -1); + fifo = keeper_fifo::getPtr(L, -1); lua_rawset(L, -3); // fifos } // remove any clutter on the stack @@ -426,7 +431,7 @@ int keepercall_set(lua_State* L) lua_pushvalue(L, -1); // fifos key key lua_rawget(L, 1); // fifos key fifo|nil // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! - keeper_fifo* const fifo{ lua_touserdata(L, -1) }; + keeper_fifo* const fifo{ keeper_fifo::getPtr(L, -1) }; if (fifo != nullptr) // might be nullptr if we set a nonexistent key to nil { // fifos key fifo if (fifo->limit < 0) // fifo limit value is the default (unlimited): we can totally remove it @@ -452,7 +457,7 @@ int keepercall_set(lua_State* L) int const count{ lua_gettop(L) - 2 }; // number of items we want to store lua_pushvalue(L, 2); // fifos key [val [, ...]] key lua_rawget(L, 1); // fifos key [val [, ...]] fifo|nil - keeper_fifo* fifo{ lua_touserdata(L, -1) }; + keeper_fifo* fifo{ keeper_fifo::getPtr(L, -1) }; 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 diff --git a/src/lanes.cpp b/src/lanes.cpp index 6b3542b..df509ee 100644 --- a/src/lanes.cpp +++ b/src/lanes.cpp @@ -442,7 +442,7 @@ static bool selfdestruct_remove( Lane* s) */ static int selfdestruct_gc( lua_State* L) { - Universe* const U{ lua_touserdata(L, 1) }; + Universe* const U{ lua_tofulluserdata(L, 1) }; while( U->selfdestruct_first != SELFDESTRUCT_END) // true at most once! { @@ -574,7 +574,7 @@ static int selfdestruct_gc( lua_State* L) { int const prev_ref_count{ U->timer_deep->m_refcount.fetch_sub(1, std::memory_order_relaxed) }; ASSERT_L(prev_ref_count == 1); // this should be the last reference - free_deep_prelude( L, (DeepPrelude*) U->timer_deep); + free_deep_prelude(L, U->timer_deep); U->timer_deep = nullptr; } @@ -781,7 +781,7 @@ LUAG_FUNC( set_debug_threadname) // fnv164 of string "debug_threadname" generated at https://www.pelock.com/products/hash-calculator constexpr UniqueKey hidden_regkey{ 0x79C0669AAAE04440ull }; // C s_lane structure is a light userdata upvalue - Lane* const s{ lua_touserdata(L, lua_upvalueindex(1)) }; + Lane* const s{ lua_tolightuserdata(L, lua_upvalueindex(1)) }; luaL_checktype( L, -1, LUA_TSTRING); // "name" lua_settop( L, 1); STACK_CHECK_START_ABS( L, 1); @@ -1887,7 +1887,7 @@ LUAG_FUNC( configure) STACK_CHECK( L, 2); // Proxy userdata contents is only a 'DeepPrelude*' pointer - U->timer_deep = *lua_touserdata(L, -1); + U->timer_deep = *lua_tofulluserdata(L, -1); // increment refcount so that this linda remains alive as long as the universe exists. U->timer_deep->m_refcount.fetch_add(1, std::memory_order_relaxed); lua_pop( L, 1); // settings @@ -1916,7 +1916,7 @@ LUAG_FUNC( configure) { char const* errmsg; - errmsg = push_deep_proxy(L, (DeepPrelude*) U->timer_deep, 0, eLM_LaneBody); // settings M timer_deep + errmsg = push_deep_proxy(L, U->timer_deep, 0, eLM_LaneBody); // settings M timer_deep if( errmsg != nullptr) { return luaL_error( L, errmsg); diff --git a/src/lanes_private.h b/src/lanes_private.h index 839a51f..5d6d25c 100644 --- a/src/lanes_private.h +++ b/src/lanes_private.h @@ -83,7 +83,7 @@ static inline Lane* get_lane_from_registry( lua_State* L) STACK_GROW( L, 1); STACK_CHECK_START_REL(L, 0); CANCEL_TEST_KEY.query_registry(L); - Lane* const s{ lua_touserdata(L, -1) }; // lightuserdata (true 's_lane' pointer) / nil + Lane* const s{ lua_tolightuserdata(L, -1) }; // lightuserdata (true 's_lane' pointer) / nil lua_pop( L, 1); STACK_CHECK( L, 0); return s; diff --git a/src/linda.cpp b/src/linda.cpp index 7e346d8..b28a126 100644 --- a/src/linda.cpp +++ b/src/linda.cpp @@ -808,7 +808,7 @@ static void* linda_id( lua_State* L, DeepOp op_) case eDO_delete: { - struct s_Linda* const linda{ lua_touserdata(L, 1) }; + struct s_Linda* const linda{ lua_tolightuserdata(L, 1) }; ASSERT_L( linda); // Clean associated structures in the keeper state. diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h index 370cbed..23fa0e9 100644 --- a/src/macros_and_utils.h +++ b/src/macros_and_utils.h @@ -11,6 +11,7 @@ extern "C" { #endif // __cplusplus #include +#include #define USE_DEBUG_SPEW() 0 #if USE_DEBUG_SPEW() @@ -125,9 +126,24 @@ inline void STACK_GROW(lua_State* L, int n_) #define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L) -// a small helper to extract a userdata pointer from the stack +// a small helper to extract a full userdata pointer from the stack in a safe way template -T* lua_touserdata(lua_State* L, int index_) +T* lua_tofulluserdata(lua_State* L, int index_) { + ASSERT_L(lua_isnil(L, index_) || lua_type(L, index_) == LUA_TUSERDATA); return static_cast(lua_touserdata(L, index_)); } + +template +auto lua_tolightuserdata(lua_State* L, int index_) +{ + ASSERT_L(lua_isnil(L, index_) || lua_islightuserdata(L, index_)); + if constexpr (std::is_pointer_v) + { + return static_cast(lua_touserdata(L, index_)); + } + else + { + return static_cast(lua_touserdata(L, index_)); + } +} diff --git a/src/state.cpp b/src/state.cpp index b46a145..817d5b4 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -259,7 +259,7 @@ lua_State* create_state( Universe* U, lua_State* from_) lua_pushcclosure( from_, U->provide_allocator, 0); lua_call( from_, 0, 1); { - AllocatorDefinition* const def{ lua_touserdata(from_, -1) }; + AllocatorDefinition* const def{ lua_tofulluserdata(from_, -1) }; L = lua_newstate( def->m_allocF, def->m_allocUD); } lua_pop( from_, 1); diff --git a/src/universe.cpp b/src/universe.cpp index 095f000..3792da6 100644 --- a/src/universe.cpp +++ b/src/universe.cpp @@ -36,17 +36,22 @@ THE SOFTWARE. #include "macros_and_utils.h" #include "uniquekey.h" -// crc64/we of string "UNIVERSE_REGKEY" generated at http://www.nitrxgen.net/hashgen/ -static constexpr UniqueKey UNIVERSE_REGKEY{ 0x9f877b2cf078f17full }; +// xxh64 of string "UNIVERSE_FULL_REGKEY" generated at http://www.nitrxgen.net/hashgen/ +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 }; // ################################################################################################ +// only called from the master state Universe* universe_create(lua_State* L) { - Universe* const U = static_cast(lua_newuserdatauv(L, sizeof(Universe), 0)); // universe + ASSERT_L(universe_get(L) == nullptr); + Universe* const U = static_cast(lua_newuserdatauv(L, sizeof(Universe), 0)); // universe U->Universe::Universe(); STACK_CHECK_START_REL(L, 1); - UNIVERSE_REGKEY.set_registry(L, [](lua_State* L) { lua_pushvalue(L, -2); }); // universe + UNIVERSE_FULL_REGKEY.set_registry(L, [](lua_State* L) { lua_pushvalue(L, -2); }); + UNIVERSE_LIGHT_REGKEY.set_registry(L, [U](lua_State* L) { lua_pushlightuserdata( L, U); }); STACK_CHECK(L, 1); return U; } @@ -55,8 +60,9 @@ Universe* universe_create(lua_State* L) void universe_store(lua_State* L, Universe* U) { + ASSERT_L(universe_get(L) == nullptr); STACK_CHECK_START_REL(L, 0); - UNIVERSE_REGKEY.set_registry(L, [U](lua_State* L) { U ? lua_pushlightuserdata( L, U) : lua_pushnil( L); }); + UNIVERSE_LIGHT_REGKEY.set_registry(L, [U](lua_State* L) { U ? lua_pushlightuserdata( L, U) : lua_pushnil( L); }); STACK_CHECK( L, 0); } @@ -66,8 +72,8 @@ Universe* universe_get(lua_State* L) { STACK_GROW(L, 2); STACK_CHECK_START_REL(L, 0); - UNIVERSE_REGKEY.query_registry(L); - Universe* const universe{ lua_touserdata(L, -1) }; // nullptr if nil + UNIVERSE_LIGHT_REGKEY.query_registry(L); + Universe* const universe{ lua_tolightuserdata(L, -1) }; // nullptr if nil lua_pop(L, 1); STACK_CHECK(L, 0); return universe; -- cgit v1.2.3-55-g6feb