aboutsummaryrefslogtreecommitdiff
path: root/src/tools.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools.cpp')
-rw-r--r--src/tools.cpp64
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
317static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L_, int ctxBase_, int i_, int depth_) 317static 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
428void populate_func_lookup_table(lua_State* L_, int i_, char const* name_) 427void 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}