diff options
| author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-03-27 10:37:05 +0100 |
|---|---|---|
| committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-03-27 10:37:05 +0100 |
| commit | 9e3ca50cfafa0d7dc3e15f3b6a635aef6a938b80 (patch) | |
| tree | 0b8dcb8cf1d90fedca7234e8a0179a09514a12bc /src | |
| parent | f214d35df5f09e7026dafd8553e83cc6ea21cbde (diff) | |
| download | lanes-9e3ca50cfafa0d7dc3e15f3b6a635aef6a938b80.tar.gz lanes-9e3ca50cfafa0d7dc3e15f3b6a635aef6a938b80.tar.bz2 lanes-9e3ca50cfafa0d7dc3e15f3b6a635aef6a938b80.zip | |
C++ migration: new helper templates lua_tolightuserdata and lua_tofulluserdata
Diffstat (limited to 'src')
| -rw-r--r-- | src/deep.cpp | 38 | ||||
| -rw-r--r-- | src/deep.h | 11 | ||||
| -rw-r--r-- | src/keeper.cpp | 19 | ||||
| -rw-r--r-- | src/lanes.cpp | 10 | ||||
| -rw-r--r-- | src/lanes_private.h | 2 | ||||
| -rw-r--r-- | src/linda.cpp | 2 | ||||
| -rw-r--r-- | src/macros_and_utils.h | 20 | ||||
| -rw-r--r-- | src/state.cpp | 2 | ||||
| -rw-r--r-- | src/universe.cpp | 20 |
9 files changed, 74 insertions, 50 deletions
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) | |||
| 108 | * Return the registered ID function for 'index' (deep userdata proxy), | 108 | * Return the registered ID function for 'index' (deep userdata proxy), |
| 109 | * or nullptr if 'index' is not a deep userdata proxy. | 109 | * or nullptr if 'index' is not a deep userdata proxy. |
| 110 | */ | 110 | */ |
| 111 | static inline luaG_IdFunction* get_idfunc( lua_State* L, int index, LookupMode mode_) | 111 | static inline luaG_IdFunction get_idfunc( lua_State* L, int index, LookupMode mode_) |
| 112 | { | 112 | { |
| 113 | // when looking inside a keeper, we are 100% sure the object is a deep userdata | 113 | // when looking inside a keeper, we are 100% sure the object is a deep userdata |
| 114 | if( mode_ == eLM_FromKeeper) | 114 | if( mode_ == eLM_FromKeeper) |
| 115 | { | 115 | { |
| 116 | DeepPrelude** const proxy{ lua_touserdata<DeepPrelude*>(L, index) }; | 116 | DeepPrelude** const proxy{ lua_tofulluserdata<DeepPrelude*>(L, index) }; |
| 117 | // we can (and must) cast and fetch the internally stored idfunc | 117 | // we can (and must) cast and fetch the internally stored idfunc |
| 118 | return (*proxy)->idfunc; | 118 | return (*proxy)->idfunc; |
| 119 | } | 119 | } |
| @@ -133,7 +133,7 @@ static inline luaG_IdFunction* get_idfunc( lua_State* L, int index, LookupMode m | |||
| 133 | // replace metatable with the idfunc pointer, if it is actually a deep userdata | 133 | // replace metatable with the idfunc pointer, if it is actually a deep userdata |
| 134 | get_deep_lookup( L); // deep ... idfunc|nil | 134 | get_deep_lookup( L); // deep ... idfunc|nil |
| 135 | 135 | ||
| 136 | luaG_IdFunction* const ret{ lua_touserdata<luaG_IdFunction>(L, -1) }; // nullptr if not a userdata | 136 | luaG_IdFunction const ret{ *lua_tolightuserdata<luaG_IdFunction>(L, -1) }; // nullptr if not a userdata |
| 137 | lua_pop( L, 1); | 137 | lua_pop( L, 1); |
| 138 | STACK_CHECK( L, 0); | 138 | STACK_CHECK( L, 0); |
| 139 | return ret; | 139 | return ret; |
| @@ -161,7 +161,7 @@ void free_deep_prelude( lua_State* L, DeepPrelude* prelude_) | |||
| 161 | */ | 161 | */ |
| 162 | static int deep_userdata_gc( lua_State* L) | 162 | static int deep_userdata_gc( lua_State* L) |
| 163 | { | 163 | { |
| 164 | DeepPrelude** const proxy{ lua_touserdata<DeepPrelude*>(L, 1) }; | 164 | DeepPrelude** const proxy{ lua_tofulluserdata<DeepPrelude*>(L, 1) }; |
| 165 | DeepPrelude* p = *proxy; | 165 | DeepPrelude* p = *proxy; |
| 166 | 166 | ||
| 167 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded | 167 | // 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) | |||
| 203 | */ | 203 | */ |
| 204 | char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_) | 204 | char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_) |
| 205 | { | 205 | { |
| 206 | DeepPrelude** proxy; | ||
| 207 | |||
| 208 | // Check if a proxy already exists | 206 | // Check if a proxy already exists |
| 209 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC | 207 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC |
| 210 | lua_pushlightuserdata( L, prelude); // DPC deep | 208 | lua_pushlightuserdata( L, prelude); // DPC deep |
| @@ -223,7 +221,7 @@ char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, Lookup | |||
| 223 | STACK_CHECK_START_REL(L, 0); | 221 | STACK_CHECK_START_REL(L, 0); |
| 224 | 222 | ||
| 225 | // a new full userdata, fitted with the specified number of uservalue slots (always 1 for Lua < 5.4) | 223 | // a new full userdata, fitted with the specified number of uservalue slots (always 1 for Lua < 5.4) |
| 226 | proxy = (DeepPrelude**) lua_newuserdatauv( L, sizeof(DeepPrelude*), nuv_); // DPC proxy | 224 | DeepPrelude** proxy = (DeepPrelude**) lua_newuserdatauv(L, sizeof(DeepPrelude*), nuv_); // DPC proxy |
| 227 | ASSERT_L( proxy); | 225 | ASSERT_L( proxy); |
| 228 | *proxy = prelude; | 226 | *proxy = prelude; |
| 229 | prelude->m_refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data | 227 | 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 | |||
| 333 | } | 331 | } |
| 334 | } | 332 | } |
| 335 | } | 333 | } |
| 336 | STACK_CHECK( L, 2); // DPC proxy metatable | 334 | STACK_CHECK(L, 2); // DPC proxy metatable |
| 337 | ASSERT_L( lua_isuserdata( L, -2)); | 335 | ASSERT_L(lua_type(L, -2) == LUA_TUSERDATA); |
| 338 | ASSERT_L( lua_istable( L, -1)); | 336 | ASSERT_L(lua_istable( L, -1)); |
| 339 | lua_setmetatable( L, -2); // DPC proxy | 337 | lua_setmetatable( L, -2); // DPC proxy |
| 340 | 338 | ||
| 341 | // If we're here, we obviously had to create a new proxy, so cache it. | 339 | // 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 | |||
| 343 | lua_pushvalue( L, -2); // DPC proxy deep proxy | 341 | lua_pushvalue( L, -2); // DPC proxy deep proxy |
| 344 | lua_rawset( L, -4); // DPC proxy | 342 | lua_rawset( L, -4); // DPC proxy |
| 345 | lua_remove( L, -2); // proxy | 343 | lua_remove( L, -2); // proxy |
| 346 | ASSERT_L( lua_isuserdata( L, -1)); | 344 | ASSERT_L(lua_type(L, -1) == LUA_TUSERDATA); |
| 347 | STACK_CHECK( L, 0); | 345 | STACK_CHECK(L, 0); |
| 348 | return nullptr; | 346 | return nullptr; |
| 349 | } | 347 | } |
| 350 | 348 | ||
| @@ -370,7 +368,7 @@ char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, Lookup | |||
| 370 | * | 368 | * |
| 371 | * Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' | 369 | * Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' |
| 372 | */ | 370 | */ |
| 373 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_) | 371 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc, int nuv_) |
| 374 | { | 372 | { |
| 375 | STACK_GROW( L, 1); | 373 | STACK_GROW( L, 1); |
| 376 | STACK_CHECK_START_REL(L, 0); | 374 | STACK_CHECK_START_REL(L, 0); |
| @@ -416,7 +414,7 @@ int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_) | |||
| 416 | * Reference count is not changed, and access to the deep userdata is not | 414 | * Reference count is not changed, and access to the deep userdata is not |
| 417 | * serialized. It is the module's responsibility to prevent conflicting usage. | 415 | * serialized. It is the module's responsibility to prevent conflicting usage. |
| 418 | */ | 416 | */ |
| 419 | void* luaG_todeep( lua_State* L, luaG_IdFunction* idfunc, int index) | 417 | DeepPrelude* luaG_todeep(lua_State* L, luaG_IdFunction idfunc, int index) |
| 420 | { | 418 | { |
| 421 | STACK_CHECK_START_REL(L, 0); | 419 | STACK_CHECK_START_REL(L, 0); |
| 422 | // ensure it is actually a deep userdata | 420 | // ensure it is actually a deep userdata |
| @@ -426,7 +424,7 @@ void* luaG_todeep( lua_State* L, luaG_IdFunction* idfunc, int index) | |||
| 426 | } | 424 | } |
| 427 | STACK_CHECK(L, 0); | 425 | STACK_CHECK(L, 0); |
| 428 | 426 | ||
| 429 | DeepPrelude** const proxy{ lua_touserdata<DeepPrelude*>(L, index) }; | 427 | DeepPrelude** const proxy{ lua_tofulluserdata<DeepPrelude*>(L, index) }; |
| 430 | 428 | ||
| 431 | return *proxy; | 429 | return *proxy; |
| 432 | } | 430 | } |
| @@ -441,10 +439,7 @@ void* luaG_todeep( lua_State* L, luaG_IdFunction* idfunc, int index) | |||
| 441 | */ | 439 | */ |
| 442 | bool copydeep(Universe* U, lua_State* L2, int L2_cache_i, lua_State* L, int i, LookupMode mode_, char const* upName_) | 440 | bool copydeep(Universe* U, lua_State* L2, int L2_cache_i, lua_State* L, int i, LookupMode mode_, char const* upName_) |
| 443 | { | 441 | { |
| 444 | char const* errmsg; | 442 | luaG_IdFunction const idfunc { get_idfunc(L, i, mode_) }; |
| 445 | luaG_IdFunction* idfunc = get_idfunc( L, i, mode_); | ||
| 446 | int nuv = 0; | ||
| 447 | |||
| 448 | if (idfunc == nullptr) | 443 | if (idfunc == nullptr) |
| 449 | { | 444 | { |
| 450 | return false; // not a deep userdata | 445 | 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 | |||
| 454 | STACK_CHECK_START_REL(L2, 0); | 449 | STACK_CHECK_START_REL(L2, 0); |
| 455 | 450 | ||
| 456 | // extract all uservalues of the source | 451 | // extract all uservalues of the source |
| 457 | while( lua_getiuservalue( L, i, nuv + 1) != LUA_TNONE) // ... u [uv]* nil | 452 | int nuv = 0; |
| 453 | while (lua_getiuservalue(L, i, nuv + 1) != LUA_TNONE) // ... u [uv]* nil | ||
| 458 | { | 454 | { |
| 459 | ++ nuv; | 455 | ++ nuv; |
| 460 | } | 456 | } |
| @@ -462,7 +458,7 @@ bool copydeep(Universe* U, lua_State* L2, int L2_cache_i, lua_State* L, int i, L | |||
| 462 | lua_pop( L, 1); // ... u [uv]* | 458 | lua_pop( L, 1); // ... u [uv]* |
| 463 | STACK_CHECK( L, nuv); | 459 | STACK_CHECK( L, nuv); |
| 464 | 460 | ||
| 465 | errmsg = push_deep_proxy(L2, *lua_touserdata<DeepPrelude*>(L, i), nuv, mode_); // u | 461 | char const* errmsg{ push_deep_proxy(L2, *lua_tofulluserdata<DeepPrelude*>(L, i), nuv, mode_) }; // u |
| 466 | 462 | ||
| 467 | // transfer all uservalues of the source in the destination | 463 | // transfer all uservalues of the source in the destination |
| 468 | { | 464 | { |
| @@ -36,19 +36,20 @@ enum DeepOp | |||
| 36 | eDO_module, | 36 | eDO_module, |
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | using luaG_IdFunction = void*( lua_State* L, DeepOp op_); | 39 | using luaG_IdFunction = void*(*)( lua_State* L, DeepOp op_); |
| 40 | 40 | ||
| 41 | // ################################################################################################ | 41 | // ################################################################################################ |
| 42 | 42 | ||
| 43 | // xxh64 of string "DEEP_VERSION_3" generated at https://www.pelock.com/products/hash-calculator | 43 | // xxh64 of string "DEEP_VERSION_3" generated at https://www.pelock.com/products/hash-calculator |
| 44 | static constexpr UniqueKey DEEP_VERSION{ 0xB2CC0FD9C0AE9674ull }; | 44 | static constexpr UniqueKey DEEP_VERSION{ 0xB2CC0FD9C0AE9674ull }; |
| 45 | 45 | ||
| 46 | // should be used as header for full userdata | 46 | // should be used as header for deep userdata |
| 47 | // a deep userdata is a full userdata that stores a single pointer to the actual DeepPrelude-derived object | ||
| 47 | struct DeepPrelude | 48 | struct DeepPrelude |
| 48 | { | 49 | { |
| 49 | UniqueKey const magic{ DEEP_VERSION }; | 50 | UniqueKey const magic{ DEEP_VERSION }; |
| 50 | // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc | 51 | // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc |
| 51 | luaG_IdFunction* idfunc { nullptr }; | 52 | luaG_IdFunction idfunc { nullptr }; |
| 52 | // data is destroyed when refcount is 0 | 53 | // data is destroyed when refcount is 0 |
| 53 | std::atomic<int> m_refcount{ 0 }; | 54 | std::atomic<int> m_refcount{ 0 }; |
| 54 | }; | 55 | }; |
| @@ -56,5 +57,5 @@ struct DeepPrelude | |||
| 56 | char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_); | 57 | char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_); |
| 57 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_); | 58 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_); |
| 58 | 59 | ||
| 59 | LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_); | 60 | LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc, int nuv_); |
| 60 | LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction* idfunc, int index); | 61 | 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 | |||
| 64 | // always embedded somewhere else or "in-place constructed" as a full userdata | 64 | // always embedded somewhere else or "in-place constructed" as a full userdata |
| 65 | // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception | 65 | // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception |
| 66 | static void operator delete(void* p_, lua_State* L){ ASSERT_L(!"should never be called") }; | 66 | static void operator delete(void* p_, lua_State* L){ ASSERT_L(!"should never be called") }; |
| 67 | |||
| 68 | static keeper_fifo* getPtr(lua_State* L, int idx_) | ||
| 69 | { | ||
| 70 | return lua_tofulluserdata<keeper_fifo>(L, idx_); | ||
| 71 | } | ||
| 67 | }; | 72 | }; |
| 68 | 73 | ||
| 69 | static constexpr int CONTENTS_TABLE{ 1 }; | 74 | static constexpr int CONTENTS_TABLE{ 1 }; |
| @@ -73,7 +78,7 @@ static constexpr int CONTENTS_TABLE{ 1 }; | |||
| 73 | // replaces the fifo ud by its uservalue on the stack | 78 | // replaces the fifo ud by its uservalue on the stack |
| 74 | static keeper_fifo* prepare_fifo_access(lua_State* L, int idx_) | 79 | static keeper_fifo* prepare_fifo_access(lua_State* L, int idx_) |
| 75 | { | 80 | { |
| 76 | keeper_fifo* const fifo{ lua_touserdata<keeper_fifo>(L, idx_) }; | 81 | keeper_fifo* const fifo{ keeper_fifo::getPtr(L, idx_) }; |
| 77 | if (fifo != nullptr) | 82 | if (fifo != nullptr) |
| 78 | { | 83 | { |
| 79 | idx_ = lua_absindex(L, idx_); | 84 | idx_ = lua_absindex(L, idx_); |
| @@ -284,8 +289,8 @@ int keepercall_send(lua_State* L) | |||
| 284 | lua_rawset(L, -4); // ud key ... fifos fifo | 289 | lua_rawset(L, -4); // ud key ... fifos fifo |
| 285 | } | 290 | } |
| 286 | lua_remove(L, -2); // ud key ... fifo | 291 | lua_remove(L, -2); // ud key ... fifo |
| 287 | keeper_fifo* fifo{ lua_touserdata<keeper_fifo>(L, -1) }; | 292 | keeper_fifo* fifo{ keeper_fifo::getPtr(L, -1) }; |
| 288 | if( fifo->limit >= 0 && fifo->count + n > fifo->limit) | 293 | if (fifo->limit >= 0 && fifo->count + n > fifo->limit) |
| 289 | { | 294 | { |
| 290 | lua_settop(L, 0); // | 295 | lua_settop(L, 0); // |
| 291 | lua_pushboolean(L, 0); // false | 296 | lua_pushboolean(L, 0); // false |
| @@ -382,12 +387,12 @@ int keepercall_limit(lua_State* L) | |||
| 382 | lua_pop(L, 1); // fifos key | 387 | lua_pop(L, 1); // fifos key |
| 383 | lua_pushvalue(L, -1); // fifos key key | 388 | lua_pushvalue(L, -1); // fifos key key |
| 384 | lua_rawget(L, -3); // fifos key fifo|nil | 389 | lua_rawget(L, -3); // fifos key fifo|nil |
| 385 | keeper_fifo* fifo{ lua_touserdata<keeper_fifo>(L, -1) }; | 390 | keeper_fifo* fifo{ keeper_fifo::getPtr(L, -1) }; |
| 386 | if (fifo == nullptr) | 391 | if (fifo == nullptr) |
| 387 | { // fifos key nil | 392 | { // fifos key nil |
| 388 | lua_pop(L, 1); // fifos key | 393 | lua_pop(L, 1); // fifos key |
| 389 | fifo_new(L); // fifos key fifo | 394 | fifo_new(L); // fifos key fifo |
| 390 | fifo = lua_touserdata<keeper_fifo>(L, -1); | 395 | fifo = keeper_fifo::getPtr(L, -1); |
| 391 | lua_rawset(L, -3); // fifos | 396 | lua_rawset(L, -3); // fifos |
| 392 | } | 397 | } |
| 393 | // remove any clutter on the stack | 398 | // remove any clutter on the stack |
| @@ -426,7 +431,7 @@ int keepercall_set(lua_State* L) | |||
| 426 | lua_pushvalue(L, -1); // fifos key key | 431 | lua_pushvalue(L, -1); // fifos key key |
| 427 | lua_rawget(L, 1); // fifos key fifo|nil | 432 | lua_rawget(L, 1); // fifos key fifo|nil |
| 428 | // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! | 433 | // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! |
| 429 | keeper_fifo* const fifo{ lua_touserdata<keeper_fifo>(L, -1) }; | 434 | keeper_fifo* const fifo{ keeper_fifo::getPtr(L, -1) }; |
| 430 | if (fifo != nullptr) // might be nullptr if we set a nonexistent key to nil | 435 | if (fifo != nullptr) // might be nullptr if we set a nonexistent key to nil |
| 431 | { // fifos key fifo | 436 | { // fifos key fifo |
| 432 | if (fifo->limit < 0) // fifo limit value is the default (unlimited): we can totally remove it | 437 | 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) | |||
| 452 | int const count{ lua_gettop(L) - 2 }; // number of items we want to store | 457 | int const count{ lua_gettop(L) - 2 }; // number of items we want to store |
| 453 | lua_pushvalue(L, 2); // fifos key [val [, ...]] key | 458 | lua_pushvalue(L, 2); // fifos key [val [, ...]] key |
| 454 | lua_rawget(L, 1); // fifos key [val [, ...]] fifo|nil | 459 | lua_rawget(L, 1); // fifos key [val [, ...]] fifo|nil |
| 455 | keeper_fifo* fifo{ lua_touserdata<keeper_fifo>(L, -1) }; | 460 | keeper_fifo* fifo{ keeper_fifo::getPtr(L, -1) }; |
| 456 | if( fifo == nullptr) // can be nullptr if we store a value at a new key | 461 | if( fifo == nullptr) // can be nullptr if we store a value at a new key |
| 457 | { // fifos key [val [, ...]] nil | 462 | { // fifos key [val [, ...]] nil |
| 458 | // no need to wake writers in that case, because a writer can't wait on an inexistent key | 463 | // 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) | |||
| 442 | */ | 442 | */ |
| 443 | static int selfdestruct_gc( lua_State* L) | 443 | static int selfdestruct_gc( lua_State* L) |
| 444 | { | 444 | { |
| 445 | Universe* const U{ lua_touserdata<Universe>(L, 1) }; | 445 | Universe* const U{ lua_tofulluserdata<Universe>(L, 1) }; |
| 446 | 446 | ||
| 447 | while( U->selfdestruct_first != SELFDESTRUCT_END) // true at most once! | 447 | while( U->selfdestruct_first != SELFDESTRUCT_END) // true at most once! |
| 448 | { | 448 | { |
| @@ -574,7 +574,7 @@ static int selfdestruct_gc( lua_State* L) | |||
| 574 | { | 574 | { |
| 575 | int const prev_ref_count{ U->timer_deep->m_refcount.fetch_sub(1, std::memory_order_relaxed) }; | 575 | int const prev_ref_count{ U->timer_deep->m_refcount.fetch_sub(1, std::memory_order_relaxed) }; |
| 576 | ASSERT_L(prev_ref_count == 1); // this should be the last reference | 576 | ASSERT_L(prev_ref_count == 1); // this should be the last reference |
| 577 | free_deep_prelude( L, (DeepPrelude*) U->timer_deep); | 577 | free_deep_prelude(L, U->timer_deep); |
| 578 | U->timer_deep = nullptr; | 578 | U->timer_deep = nullptr; |
| 579 | } | 579 | } |
| 580 | 580 | ||
| @@ -781,7 +781,7 @@ LUAG_FUNC( set_debug_threadname) | |||
| 781 | // fnv164 of string "debug_threadname" generated at https://www.pelock.com/products/hash-calculator | 781 | // fnv164 of string "debug_threadname" generated at https://www.pelock.com/products/hash-calculator |
| 782 | constexpr UniqueKey hidden_regkey{ 0x79C0669AAAE04440ull }; | 782 | constexpr UniqueKey hidden_regkey{ 0x79C0669AAAE04440ull }; |
| 783 | // C s_lane structure is a light userdata upvalue | 783 | // C s_lane structure is a light userdata upvalue |
| 784 | Lane* const s{ lua_touserdata<Lane>(L, lua_upvalueindex(1)) }; | 784 | Lane* const s{ lua_tolightuserdata<Lane>(L, lua_upvalueindex(1)) }; |
| 785 | luaL_checktype( L, -1, LUA_TSTRING); // "name" | 785 | luaL_checktype( L, -1, LUA_TSTRING); // "name" |
| 786 | lua_settop( L, 1); | 786 | lua_settop( L, 1); |
| 787 | STACK_CHECK_START_ABS( L, 1); | 787 | STACK_CHECK_START_ABS( L, 1); |
| @@ -1887,7 +1887,7 @@ LUAG_FUNC( configure) | |||
| 1887 | STACK_CHECK( L, 2); | 1887 | STACK_CHECK( L, 2); |
| 1888 | 1888 | ||
| 1889 | // Proxy userdata contents is only a 'DeepPrelude*' pointer | 1889 | // Proxy userdata contents is only a 'DeepPrelude*' pointer |
| 1890 | U->timer_deep = *lua_touserdata<DeepPrelude*>(L, -1); | 1890 | U->timer_deep = *lua_tofulluserdata<DeepPrelude*>(L, -1); |
| 1891 | // increment refcount so that this linda remains alive as long as the universe exists. | 1891 | // increment refcount so that this linda remains alive as long as the universe exists. |
| 1892 | U->timer_deep->m_refcount.fetch_add(1, std::memory_order_relaxed); | 1892 | U->timer_deep->m_refcount.fetch_add(1, std::memory_order_relaxed); |
| 1893 | lua_pop( L, 1); // settings | 1893 | lua_pop( L, 1); // settings |
| @@ -1916,7 +1916,7 @@ LUAG_FUNC( configure) | |||
| 1916 | 1916 | ||
| 1917 | { | 1917 | { |
| 1918 | char const* errmsg; | 1918 | char const* errmsg; |
| 1919 | errmsg = push_deep_proxy(L, (DeepPrelude*) U->timer_deep, 0, eLM_LaneBody); // settings M timer_deep | 1919 | errmsg = push_deep_proxy(L, U->timer_deep, 0, eLM_LaneBody); // settings M timer_deep |
| 1920 | if( errmsg != nullptr) | 1920 | if( errmsg != nullptr) |
| 1921 | { | 1921 | { |
| 1922 | return luaL_error( L, errmsg); | 1922 | 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) | |||
| 83 | STACK_GROW( L, 1); | 83 | STACK_GROW( L, 1); |
| 84 | STACK_CHECK_START_REL(L, 0); | 84 | STACK_CHECK_START_REL(L, 0); |
| 85 | CANCEL_TEST_KEY.query_registry(L); | 85 | CANCEL_TEST_KEY.query_registry(L); |
| 86 | Lane* const s{ lua_touserdata<Lane>(L, -1) }; // lightuserdata (true 's_lane' pointer) / nil | 86 | Lane* const s{ lua_tolightuserdata<Lane>(L, -1) }; // lightuserdata (true 's_lane' pointer) / nil |
| 87 | lua_pop( L, 1); | 87 | lua_pop( L, 1); |
| 88 | STACK_CHECK( L, 0); | 88 | STACK_CHECK( L, 0); |
| 89 | return s; | 89 | 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_) | |||
| 808 | 808 | ||
| 809 | case eDO_delete: | 809 | case eDO_delete: |
| 810 | { | 810 | { |
| 811 | struct s_Linda* const linda{ lua_touserdata<struct s_Linda>(L, 1) }; | 811 | struct s_Linda* const linda{ lua_tolightuserdata<struct s_Linda>(L, 1) }; |
| 812 | ASSERT_L( linda); | 812 | ASSERT_L( linda); |
| 813 | 813 | ||
| 814 | // Clean associated structures in the keeper state. | 814 | // 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" { | |||
| 11 | #endif // __cplusplus | 11 | #endif // __cplusplus |
| 12 | 12 | ||
| 13 | #include <cassert> | 13 | #include <cassert> |
| 14 | #include <type_traits> | ||
| 14 | 15 | ||
| 15 | #define USE_DEBUG_SPEW() 0 | 16 | #define USE_DEBUG_SPEW() 0 |
| 16 | #if USE_DEBUG_SPEW() | 17 | #if USE_DEBUG_SPEW() |
| @@ -125,9 +126,24 @@ inline void STACK_GROW(lua_State* L, int n_) | |||
| 125 | 126 | ||
| 126 | #define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L) | 127 | #define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L) |
| 127 | 128 | ||
| 128 | // a small helper to extract a userdata pointer from the stack | 129 | // a small helper to extract a full userdata pointer from the stack in a safe way |
| 129 | template<typename T> | 130 | template<typename T> |
| 130 | T* lua_touserdata(lua_State* L, int index_) | 131 | T* lua_tofulluserdata(lua_State* L, int index_) |
| 131 | { | 132 | { |
| 133 | ASSERT_L(lua_isnil(L, index_) || lua_type(L, index_) == LUA_TUSERDATA); | ||
| 132 | return static_cast<T*>(lua_touserdata(L, index_)); | 134 | return static_cast<T*>(lua_touserdata(L, index_)); |
| 133 | } | 135 | } |
| 136 | |||
| 137 | template<typename T> | ||
| 138 | auto lua_tolightuserdata(lua_State* L, int index_) | ||
| 139 | { | ||
| 140 | ASSERT_L(lua_isnil(L, index_) || lua_islightuserdata(L, index_)); | ||
| 141 | if constexpr (std::is_pointer_v<T>) | ||
| 142 | { | ||
| 143 | return static_cast<T>(lua_touserdata(L, index_)); | ||
| 144 | } | ||
| 145 | else | ||
| 146 | { | ||
| 147 | return static_cast<T*>(lua_touserdata(L, index_)); | ||
| 148 | } | ||
| 149 | } | ||
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_) | |||
| 259 | lua_pushcclosure( from_, U->provide_allocator, 0); | 259 | lua_pushcclosure( from_, U->provide_allocator, 0); |
| 260 | lua_call( from_, 0, 1); | 260 | lua_call( from_, 0, 1); |
| 261 | { | 261 | { |
| 262 | AllocatorDefinition* const def{ lua_touserdata<AllocatorDefinition>(from_, -1) }; | 262 | AllocatorDefinition* const def{ lua_tofulluserdata<AllocatorDefinition>(from_, -1) }; |
| 263 | L = lua_newstate( def->m_allocF, def->m_allocUD); | 263 | L = lua_newstate( def->m_allocF, def->m_allocUD); |
| 264 | } | 264 | } |
| 265 | lua_pop( from_, 1); | 265 | 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. | |||
| 36 | #include "macros_and_utils.h" | 36 | #include "macros_and_utils.h" |
| 37 | #include "uniquekey.h" | 37 | #include "uniquekey.h" |
| 38 | 38 | ||
| 39 | // crc64/we of string "UNIVERSE_REGKEY" generated at http://www.nitrxgen.net/hashgen/ | 39 | // xxh64 of string "UNIVERSE_FULL_REGKEY" generated at http://www.nitrxgen.net/hashgen/ |
| 40 | static constexpr UniqueKey UNIVERSE_REGKEY{ 0x9f877b2cf078f17full }; | 40 | static constexpr UniqueKey UNIVERSE_FULL_REGKEY{ 0x99CA130C09EDC074ull }; |
| 41 | // xxh64 of string "UNIVERSE_LIGHT_REGKEY" generated at http://www.nitrxgen.net/hashgen/ | ||
| 42 | static constexpr UniqueKey UNIVERSE_LIGHT_REGKEY{ 0x3663C07C742CEB81ull }; | ||
| 41 | 43 | ||
| 42 | // ################################################################################################ | 44 | // ################################################################################################ |
| 43 | 45 | ||
| 46 | // only called from the master state | ||
| 44 | Universe* universe_create(lua_State* L) | 47 | Universe* universe_create(lua_State* L) |
| 45 | { | 48 | { |
| 46 | Universe* const U = static_cast<Universe*>(lua_newuserdatauv(L, sizeof(Universe), 0)); // universe | 49 | ASSERT_L(universe_get(L) == nullptr); |
| 50 | Universe* const U = static_cast<Universe*>(lua_newuserdatauv(L, sizeof(Universe), 0)); // universe | ||
| 47 | U->Universe::Universe(); | 51 | U->Universe::Universe(); |
| 48 | STACK_CHECK_START_REL(L, 1); | 52 | STACK_CHECK_START_REL(L, 1); |
| 49 | UNIVERSE_REGKEY.set_registry(L, [](lua_State* L) { lua_pushvalue(L, -2); }); // universe | 53 | UNIVERSE_FULL_REGKEY.set_registry(L, [](lua_State* L) { lua_pushvalue(L, -2); }); |
| 54 | UNIVERSE_LIGHT_REGKEY.set_registry(L, [U](lua_State* L) { lua_pushlightuserdata( L, U); }); | ||
| 50 | STACK_CHECK(L, 1); | 55 | STACK_CHECK(L, 1); |
| 51 | return U; | 56 | return U; |
| 52 | } | 57 | } |
| @@ -55,8 +60,9 @@ Universe* universe_create(lua_State* L) | |||
| 55 | 60 | ||
| 56 | void universe_store(lua_State* L, Universe* U) | 61 | void universe_store(lua_State* L, Universe* U) |
| 57 | { | 62 | { |
| 63 | ASSERT_L(universe_get(L) == nullptr); | ||
| 58 | STACK_CHECK_START_REL(L, 0); | 64 | STACK_CHECK_START_REL(L, 0); |
| 59 | UNIVERSE_REGKEY.set_registry(L, [U](lua_State* L) { U ? lua_pushlightuserdata( L, U) : lua_pushnil( L); }); | 65 | UNIVERSE_LIGHT_REGKEY.set_registry(L, [U](lua_State* L) { U ? lua_pushlightuserdata( L, U) : lua_pushnil( L); }); |
| 60 | STACK_CHECK( L, 0); | 66 | STACK_CHECK( L, 0); |
| 61 | } | 67 | } |
| 62 | 68 | ||
| @@ -66,8 +72,8 @@ Universe* universe_get(lua_State* L) | |||
| 66 | { | 72 | { |
| 67 | STACK_GROW(L, 2); | 73 | STACK_GROW(L, 2); |
| 68 | STACK_CHECK_START_REL(L, 0); | 74 | STACK_CHECK_START_REL(L, 0); |
| 69 | UNIVERSE_REGKEY.query_registry(L); | 75 | UNIVERSE_LIGHT_REGKEY.query_registry(L); |
| 70 | Universe* const universe{ lua_touserdata<Universe>(L, -1) }; // nullptr if nil | 76 | Universe* const universe{ lua_tolightuserdata<Universe>(L, -1) }; // nullptr if nil |
| 71 | lua_pop(L, 1); | 77 | lua_pop(L, 1); |
| 72 | STACK_CHECK(L, 0); | 78 | STACK_CHECK(L, 0); |
| 73 | return universe; | 79 | return universe; |
