diff options
-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; |