diff options
Diffstat (limited to 'src/tools.cpp')
-rw-r--r-- | src/tools.cpp | 64 |
1 files changed, 31 insertions, 33 deletions
diff --git a/src/tools.cpp b/src/tools.cpp index c4ce24f..0495561 100644 --- a/src/tools.cpp +++ b/src/tools.cpp | |||
@@ -101,7 +101,7 @@ extern "C" [[nodiscard]] static void* libc_lua_Alloc([[maybe_unused]] void* ud, | |||
101 | { | 101 | { |
102 | Universe* const U{ universe_get(L_) }; | 102 | Universe* const U{ universe_get(L_) }; |
103 | // push a new full userdata on the stack, giving access to the universe's protected allocator | 103 | // push a new full userdata on the stack, giving access to the universe's protected allocator |
104 | [[maybe_unused]] AllocatorDefinition* const def{ new (L_) AllocatorDefinition{ U->protected_allocator.makeDefinition() } }; | 104 | [[maybe_unused]] AllocatorDefinition* const def{ new (L_) AllocatorDefinition{ U->protectedAllocator.makeDefinition() } }; |
105 | return 1; | 105 | return 1; |
106 | } | 106 | } |
107 | 107 | ||
@@ -115,8 +115,8 @@ void initialize_allocator_function(Universe* U_, lua_State* L_) | |||
115 | lua_getfield(L_, -1, "allocator"); // L_: settings allocator|nil|"protected" | 115 | lua_getfield(L_, -1, "allocator"); // L_: settings allocator|nil|"protected" |
116 | if (!lua_isnil(L_, -1)) { | 116 | if (!lua_isnil(L_, -1)) { |
117 | // store C function pointer in an internal variable | 117 | // store C function pointer in an internal variable |
118 | U_->provide_allocator = lua_tocfunction(L_, -1); // L_: settings allocator | 118 | U_->provideAllocator = lua_tocfunction(L_, -1); // L_: settings allocator |
119 | if (U_->provide_allocator != nullptr) { | 119 | if (U_->provideAllocator != nullptr) { |
120 | // make sure the function doesn't have upvalues | 120 | // make sure the function doesn't have upvalues |
121 | char const* upname = lua_getupvalue(L_, -1, 1); // L_: settings allocator upval? | 121 | char const* upname = lua_getupvalue(L_, -1, 1); // L_: settings allocator upval? |
122 | if (upname != nullptr) { // should be "" for C functions with upvalues if any | 122 | if (upname != nullptr) { // should be "" for C functions with upvalues if any |
@@ -129,14 +129,14 @@ void initialize_allocator_function(Universe* U_, lua_State* L_) | |||
129 | } else if (lua_type(L_, -1) == LUA_TSTRING) { // should be "protected" | 129 | } else if (lua_type(L_, -1) == LUA_TSTRING) { // should be "protected" |
130 | LUA_ASSERT(L_, strcmp(lua_tostring(L_, -1), "protected") == 0); | 130 | LUA_ASSERT(L_, strcmp(lua_tostring(L_, -1), "protected") == 0); |
131 | // set the original allocator to call from inside protection by the mutex | 131 | // set the original allocator to call from inside protection by the mutex |
132 | U_->protected_allocator.initFrom(L_); | 132 | U_->protectedAllocator.initFrom(L_); |
133 | U_->protected_allocator.installIn(L_); | 133 | U_->protectedAllocator.installIn(L_); |
134 | // before a state is created, this function will be called to obtain the allocator | 134 | // before a state is created, this function will be called to obtain the allocator |
135 | U_->provide_allocator = luaG_provide_protected_allocator; | 135 | U_->provideAllocator = luaG_provide_protected_allocator; |
136 | } | 136 | } |
137 | } else { | 137 | } else { |
138 | // just grab whatever allocator was provided to lua_newstate | 138 | // just grab whatever allocator was provided to lua_newstate |
139 | U_->protected_allocator.initFrom(L_); | 139 | U_->protectedAllocator.initFrom(L_); |
140 | } | 140 | } |
141 | lua_pop(L_, 1); // L_: settings | 141 | lua_pop(L_, 1); // L_: settings |
142 | STACK_CHECK(L_, 1); | 142 | STACK_CHECK(L_, 1); |
@@ -145,13 +145,13 @@ void initialize_allocator_function(Universe* U_, lua_State* L_) | |||
145 | { | 145 | { |
146 | char const* allocator = lua_tostring(L_, -1); | 146 | char const* allocator = lua_tostring(L_, -1); |
147 | if (strcmp(allocator, "libc") == 0) { | 147 | if (strcmp(allocator, "libc") == 0) { |
148 | U_->internal_allocator = AllocatorDefinition{ libc_lua_Alloc, nullptr }; | 148 | U_->internalAllocator = AllocatorDefinition{ libc_lua_Alloc, nullptr }; |
149 | } else if (U_->provide_allocator == luaG_provide_protected_allocator) { | 149 | } else if (U_->provideAllocator == luaG_provide_protected_allocator) { |
150 | // user wants mutex protection on the state's allocator. Use protection for our own allocations too, just in case. | 150 | // user wants mutex protection on the state's allocator. Use protection for our own allocations too, just in case. |
151 | U_->internal_allocator = U_->protected_allocator.makeDefinition(); | 151 | U_->internalAllocator = U_->protectedAllocator.makeDefinition(); |
152 | } else { | 152 | } else { |
153 | // no protection required, just use whatever we have as-is. | 153 | // no protection required, just use whatever we have as-is. |
154 | U_->internal_allocator = U_->protected_allocator; | 154 | U_->internalAllocator = U_->protectedAllocator; |
155 | } | 155 | } |
156 | } | 156 | } |
157 | lua_pop(L_, 1); // L_: settings | 157 | lua_pop(L_, 1); // L_: settings |
@@ -314,14 +314,13 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L | |||
314 | 314 | ||
315 | // ################################################################################################# | 315 | // ################################################################################################# |
316 | 316 | ||
317 | static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L_, int ctxBase_, int i_, int depth_) | 317 | static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L_, int dbIdx_, int i_, int depth_) |
318 | { | 318 | { |
319 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot i_ | 319 | // slot dbIdx_ contains the lookup database table |
320 | int const fqn = ctxBase_ + 1; | 320 | // slot dbIdx_ + 1 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot i_ |
321 | // slot 3 contains a cache that stores all already visited tables to avoid infinite recursion loops | 321 | int const fqn{ dbIdx_ + 1 }; |
322 | int const cache = ctxBase_ + 2; | 322 | // slot dbIdx_ + 2 contains a cache that stores all already visited tables to avoid infinite recursion loops |
323 | // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search) | 323 | int const cache{ dbIdx_ + 2 }; |
324 | int const breadth_first_cache = lua_gettop(L_) + 1; | ||
325 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "populate_func_lookup_table_recur()\n" INDENT_END(U_))); | 324 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "populate_func_lookup_table_recur()\n" INDENT_END(U_))); |
326 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U_ }); | 325 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U_ }); |
327 | 326 | ||
@@ -352,9 +351,9 @@ static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U_) | |||
352 | lua_rawset(L_, cache); // L_: ... {i_} | 351 | lua_rawset(L_, cache); // L_: ... {i_} |
353 | STACK_CHECK(L_, 0); | 352 | STACK_CHECK(L_, 0); |
354 | 353 | ||
355 | // this table is at breadth_first_cache index | 354 | // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search) |
356 | lua_newtable(L_); // L_: ... {i_} {bfc} | 355 | lua_newtable(L_); // L_: ... {i_} {bfc} |
357 | LUA_ASSERT(L_, lua_gettop(L_) == breadth_first_cache); | 356 | int const breadthFirstCache{ lua_gettop(L_) }; |
358 | // iterate over all entries in the processed table | 357 | // iterate over all entries in the processed table |
359 | lua_pushnil(L_); // L_: ... {i_} {bfc} nil | 358 | lua_pushnil(L_); // L_: ... {i_} {bfc} nil |
360 | while (lua_next(L_, i_) != 0) { // L_: ... {i_} {bfc} k v | 359 | while (lua_next(L_, i_) != 0) { // L_: ... {i_} {bfc} k v |
@@ -373,13 +372,13 @@ static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U_) | |||
373 | // store the table in the breadth-first cache | 372 | // store the table in the breadth-first cache |
374 | lua_pushvalue(L_, -2); // L_: ... {i_} {bfc} k {} k | 373 | lua_pushvalue(L_, -2); // L_: ... {i_} {bfc} k {} k |
375 | lua_pushvalue(L_, -2); // L_: ... {i_} {bfc} k {} k {} | 374 | lua_pushvalue(L_, -2); // L_: ... {i_} {bfc} k {} k {} |
376 | lua_rawset(L_, breadth_first_cache); // L_: ... {i_} {bfc} k {} | 375 | lua_rawset(L_, breadthFirstCache); // L_: ... {i_} {bfc} k {} |
377 | // generate a name, and if we already had one name, keep whichever is the shorter | 376 | // generate a name, and if we already had one name, keep whichever is the shorter |
378 | update_lookup_entry(DEBUGSPEW_PARAM_COMMA(U_) L_, ctxBase_, depth_); // L_: ... {i_} {bfc} k | 377 | update_lookup_entry(DEBUGSPEW_PARAM_COMMA(U_) L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k |
379 | } else if (lua_isfunction(L_, -1) && (luaG_getfuncsubtype(L_, -1) != FuncSubType::Bytecode)) { | 378 | } else if (lua_isfunction(L_, -1) && (luaG_getfuncsubtype(L_, -1) != FuncSubType::Bytecode)) { |
380 | // generate a name, and if we already had one name, keep whichever is the shorter | 379 | // generate a name, and if we already had one name, keep whichever is the shorter |
381 | // this pops the function from the stack | 380 | // this pops the function from the stack |
382 | update_lookup_entry(DEBUGSPEW_PARAM_COMMA(U_) L_, ctxBase_, depth_); // L_: ... {i_} {bfc} k | 381 | update_lookup_entry(DEBUGSPEW_PARAM_COMMA(U_) L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k |
383 | } else { | 382 | } else { |
384 | lua_pop(L_, 1); // L_: ... {i_} {bfc} k | 383 | lua_pop(L_, 1); // L_: ... {i_} {bfc} k |
385 | } | 384 | } |
@@ -388,7 +387,7 @@ static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U_) | |||
388 | // now process the tables we encountered at that depth | 387 | // now process the tables we encountered at that depth |
389 | ++depth_; | 388 | ++depth_; |
390 | lua_pushnil(L_); // L_: ... {i_} {bfc} nil | 389 | lua_pushnil(L_); // L_: ... {i_} {bfc} nil |
391 | while (lua_next(L_, breadth_first_cache) != 0) { // L_: ... {i_} {bfc} k {} | 390 | while (lua_next(L_, breadthFirstCache) != 0) { // L_: ... {i_} {bfc} k {} |
392 | DEBUGSPEW_CODE(char const* key = (lua_type(L_, -2) == LUA_TSTRING) ? lua_tostring(L_, -2) : "not a string"); | 391 | DEBUGSPEW_CODE(char const* key = (lua_type(L_, -2) == LUA_TSTRING) ? lua_tostring(L_, -2) : "not a string"); |
393 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "table '%s'\n" INDENT_END(U_), key)); | 392 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "table '%s'\n" INDENT_END(U_), key)); |
394 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U_ }); | 393 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U_ }); |
@@ -408,7 +407,7 @@ static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U_) | |||
408 | // push table name in fqn stack (note that concatenation will crash if name is a not string!) | 407 | // push table name in fqn stack (note that concatenation will crash if name is a not string!) |
409 | lua_pushvalue(L_, -2); // L_: ... {i_} {bfc} k {} k | 408 | lua_pushvalue(L_, -2); // L_: ... {i_} {bfc} k {} k |
410 | lua_rawseti(L_, fqn, depth_); // L_: ... {i_} {bfc} k {} | 409 | lua_rawseti(L_, fqn, depth_); // L_: ... {i_} {bfc} k {} |
411 | populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U_) L_, ctxBase_, lua_gettop(L_), depth_); | 410 | populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U_) L_, dbIdx_, lua_gettop(L_), depth_); |
412 | lua_pop(L_, 1); // L_: ... {i_} {bfc} k | 411 | lua_pop(L_, 1); // L_: ... {i_} {bfc} k |
413 | STACK_CHECK(L_, 2); | 412 | STACK_CHECK(L_, 2); |
414 | } | 413 | } |
@@ -427,15 +426,14 @@ static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U_) | |||
427 | // create a "fully.qualified.name" <-> function equivalence database | 426 | // create a "fully.qualified.name" <-> function equivalence database |
428 | void populate_func_lookup_table(lua_State* L_, int i_, char const* name_) | 427 | void populate_func_lookup_table(lua_State* L_, int i_, char const* name_) |
429 | { | 428 | { |
430 | int const ctx_base = lua_gettop(L_) + 1; | ||
431 | int const in_base = lua_absindex(L_, i_); | 429 | int const in_base = lua_absindex(L_, i_); |
432 | int start_depth = 0; | ||
433 | DEBUGSPEW_CODE(Universe* U = universe_get(L_)); | 430 | DEBUGSPEW_CODE(Universe* U = universe_get(L_)); |
434 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END(U), L_, name_ ? name_ : "nullptr")); | 431 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END(U), L_, name_ ? name_ : "nullptr")); |
435 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); | 432 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); |
436 | STACK_GROW(L_, 3); | 433 | STACK_GROW(L_, 3); |
437 | STACK_CHECK_START_REL(L_, 0); | 434 | STACK_CHECK_START_REL(L_, 0); |
438 | kLookupRegKey.pushValue(L_); // L_: {} | 435 | kLookupRegKey.pushValue(L_); // L_: {} |
436 | int const dbIdx{ lua_gettop(L_) }; | ||
439 | STACK_CHECK(L_, 1); | 437 | STACK_CHECK(L_, 1); |
440 | LUA_ASSERT(L_, lua_istable(L_, -1)); | 438 | LUA_ASSERT(L_, lua_istable(L_, -1)); |
441 | if (lua_type(L_, in_base) == LUA_TFUNCTION) { // for example when a module is a simple function | 439 | if (lua_type(L_, in_base) == LUA_TFUNCTION) { // for example when a module is a simple function |
@@ -449,15 +447,15 @@ void populate_func_lookup_table(lua_State* L_, int i_, char const* name_) | |||
449 | lua_pop(L_, 1); // L_: | 447 | lua_pop(L_, 1); // L_: |
450 | } else if (lua_type(L_, in_base) == LUA_TTABLE) { | 448 | } else if (lua_type(L_, in_base) == LUA_TTABLE) { |
451 | lua_newtable(L_); // L_: {} {fqn} | 449 | lua_newtable(L_); // L_: {} {fqn} |
450 | int startDepth{ 0 }; | ||
452 | if (name_) { | 451 | if (name_) { |
453 | STACK_CHECK(L_, 2); | 452 | STACK_CHECK(L_, 2); |
454 | lua_pushstring(L_, name_); // L_: {} {fqn} "name" | 453 | lua_pushstring(L_, name_); // L_: {} {fqn} "name" |
455 | // generate a name, and if we already had one name, keep whichever is the shorter | 454 | // generate a name, and if we already had one name, keep whichever is the shorter |
456 | lua_pushvalue(L_, in_base); // L_: {} {fqn} "name" t | 455 | lua_pushvalue(L_, in_base); // L_: {} {fqn} "name" t |
457 | update_lookup_entry(DEBUGSPEW_PARAM_COMMA(U) L_, ctx_base, start_depth); // L_: {} {fqn} "name" | 456 | update_lookup_entry(DEBUGSPEW_PARAM_COMMA(U) L_, dbIdx, startDepth); // L_: {} {fqn} "name" |
458 | // don't forget to store the name at the bottom of the fqn stack | 457 | // don't forget to store the name at the bottom of the fqn stack |
459 | ++start_depth; | 458 | lua_rawseti(L_, -2, ++startDepth); // L_: {} {fqn} |
460 | lua_rawseti(L_, -2, start_depth); // L_: {} {fqn} | ||
461 | STACK_CHECK(L_, 2); | 459 | STACK_CHECK(L_, 2); |
462 | } | 460 | } |
463 | // retrieve the cache, create it if we haven't done it yet | 461 | // retrieve the cache, create it if we haven't done it yet |
@@ -469,8 +467,8 @@ void populate_func_lookup_table(lua_State* L_, int i_, char const* name_) | |||
469 | STACK_CHECK(L_, 3); | 467 | STACK_CHECK(L_, 3); |
470 | } | 468 | } |
471 | // process everything we find in that table, filling in lookup data for all functions and tables we see there | 469 | // process everything we find in that table, filling in lookup data for all functions and tables we see there |
472 | populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U) L_, ctx_base, in_base, start_depth); | 470 | populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U) L_, dbIdx, in_base, startDepth); |
473 | lua_pop(L_, 3); | 471 | lua_pop(L_, 3); // L_: |
474 | } else { | 472 | } else { |
475 | lua_pop(L_, 1); // L_: | 473 | lua_pop(L_, 1); // L_: |
476 | raise_luaL_error(L_, "unsupported module type %s", lua_typename(L_, lua_type(L_, in_base))); | 474 | raise_luaL_error(L_, "unsupported module type %s", lua_typename(L_, lua_type(L_, in_base))); |
@@ -502,7 +500,7 @@ static constexpr RegistryUniqueKey kMtIdRegKey{ 0xA8895DCF4EC3FE3Cull }; | |||
502 | STACK_CHECK(L_, 1); | 500 | STACK_CHECK(L_, 1); |
503 | 501 | ||
504 | if (id == 0) { | 502 | if (id == 0) { |
505 | id = U_->next_mt_id.fetch_add(1, std::memory_order_relaxed); | 503 | id = U_->nextMetatableId.fetch_add(1, std::memory_order_relaxed); |
506 | 504 | ||
507 | // Create two-way references: id_uint <-> table | 505 | // Create two-way references: id_uint <-> table |
508 | lua_pushvalue(L_, idx_); // L_: ... _R[kMtIdRegKey] {mt} | 506 | lua_pushvalue(L_, idx_); // L_: ... _R[kMtIdRegKey] {mt} |