aboutsummaryrefslogtreecommitdiff
path: root/src/tools.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools.cpp')
-rw-r--r--src/tools.cpp1501
1 files changed, 661 insertions, 840 deletions
diff --git a/src/tools.cpp b/src/tools.cpp
index 7b2d153..63bb323 100644
--- a/src/tools.cpp
+++ b/src/tools.cpp
@@ -2,7 +2,7 @@
2 * TOOLS.C Copyright (c) 2002-10, Asko Kauppi 2 * TOOLS.C Copyright (c) 2002-10, Asko Kauppi
3 * 3 *
4 * Lua tools to support Lanes. 4 * Lua tools to support Lanes.
5*/ 5 */
6 6
7/* 7/*
8=============================================================================== 8===============================================================================
@@ -42,33 +42,29 @@ static constexpr RegistryUniqueKey kLookupCacheRegKey{ 0x9BF75F84E54B691Bull };
42 42
43// ################################################################################################# 43// #################################################################################################
44 44
45/* 45// does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it
46 * Does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it
47 */
48void push_registry_subtable_mode(lua_State* L_, RegistryUniqueKey key_, const char* mode_) 46void push_registry_subtable_mode(lua_State* L_, RegistryUniqueKey key_, const char* mode_)
49{ 47{
50 STACK_GROW(L_, 3); 48 STACK_GROW(L_, 3);
51 STACK_CHECK_START_REL(L_, 0); 49 STACK_CHECK_START_REL(L_, 0);
52 50
53 key_.pushValue(L_); // {}|nil 51 key_.pushValue(L_); // L_: {}|nil
54 STACK_CHECK(L_, 1); 52 STACK_CHECK(L_, 1);
55 53
56 if (lua_isnil(L_, -1)) 54 if (lua_isnil(L_, -1)) {
57 { 55 lua_pop(L_, 1); // L_:
58 lua_pop(L_, 1); // 56 lua_newtable(L_); // L_: {}
59 lua_newtable(L_); // {}
60 // _R[key_] = {} 57 // _R[key_] = {}
61 key_.setValue(L_, [](lua_State* L_) { lua_pushvalue(L_, -2); }); // {} 58 key_.setValue(L_, [](lua_State* L_) { lua_pushvalue(L_, -2); }); // L_: {}
62 STACK_CHECK(L_, 1); 59 STACK_CHECK(L_, 1);
63 60
64 // Set its metatable if requested 61 // Set its metatable if requested
65 if (mode_) 62 if (mode_) {
66 { 63 lua_newtable(L_); // L_: {} mt
67 lua_newtable(L_); // {} mt 64 lua_pushliteral(L_, "__mode"); // L_: {} mt "__mode"
68 lua_pushliteral(L_, "__mode"); // {} mt "__mode" 65 lua_pushstring(L_, mode_); // L_: {} mt "__mode" mode
69 lua_pushstring(L_, mode_); // {} mt "__mode" mode 66 lua_rawset(L_, -3); // L_: {} mt
70 lua_rawset(L_, -3); // {} mt 67 lua_setmetatable(L_, -2); // L_: {}
71 lua_setmetatable(L_, -2); // {}
72 } 68 }
73 } 69 }
74 STACK_CHECK(L_, 1); 70 STACK_CHECK(L_, 1);
@@ -83,7 +79,7 @@ void push_registry_subtable_mode(lua_State* L_, RegistryUniqueKey key_, const ch
83 */ 79 */
84void push_registry_subtable(lua_State* L_, RegistryUniqueKey key_) 80void push_registry_subtable(lua_State* L_, RegistryUniqueKey key_)
85{ 81{
86 push_registry_subtable_mode(L_, key_, nullptr); 82 push_registry_subtable_mode(L_, key_, nullptr);
87} 83}
88 84
89// ################################################################################################# 85// #################################################################################################
@@ -91,13 +87,10 @@ void push_registry_subtable(lua_State* L_, RegistryUniqueKey key_)
91// same as PUC-Lua l_alloc 87// same as PUC-Lua l_alloc
92extern "C" [[nodiscard]] static void* libc_lua_Alloc([[maybe_unused]] void* ud, [[maybe_unused]] void* ptr_, [[maybe_unused]] size_t osize_, size_t nsize_) 88extern "C" [[nodiscard]] static void* libc_lua_Alloc([[maybe_unused]] void* ud, [[maybe_unused]] void* ptr_, [[maybe_unused]] size_t osize_, size_t nsize_)
93{ 89{
94 if (nsize_ == 0) 90 if (nsize_ == 0) {
95 {
96 free(ptr_); 91 free(ptr_);
97 return nullptr; 92 return nullptr;
98 } 93 } else {
99 else
100 {
101 return realloc(ptr_, nsize_); 94 return realloc(ptr_, nsize_);
102 } 95 }
103} 96}
@@ -116,64 +109,52 @@ extern "C" [[nodiscard]] static void* libc_lua_Alloc([[maybe_unused]] void* ud,
116 109
117// called once at the creation of the universe (therefore L is the master Lua state everything originates from) 110// called once at the creation of the universe (therefore L is the master Lua state everything originates from)
118// Do I need to disable this when compiling for LuaJIT to prevent issues? 111// Do I need to disable this when compiling for LuaJIT to prevent issues?
119void initialize_allocator_function(Universe* U, lua_State* L_) 112void initialize_allocator_function(Universe* U_, lua_State* L_)
120{ 113{
121 STACK_CHECK_START_REL(L_, 1); // settings 114 STACK_CHECK_START_REL(L_, 1); // L_: settings
122 lua_getfield(L_, -1, "allocator"); // settings allocator|nil|"protected" 115 lua_getfield(L_, -1, "allocator"); // L_: settings allocator|nil|"protected"
123 if (!lua_isnil(L_, -1)) 116 if (!lua_isnil(L_, -1)) {
124 {
125 // store C function pointer in an internal variable 117 // store C function pointer in an internal variable
126 U->provide_allocator = lua_tocfunction(L_, -1); // settings allocator 118 U_->provide_allocator = lua_tocfunction(L_, -1); // L_: settings allocator
127 if (U->provide_allocator != nullptr) 119 if (U_->provide_allocator != nullptr) {
128 {
129 // make sure the function doesn't have upvalues 120 // make sure the function doesn't have upvalues
130 char const* upname = lua_getupvalue(L_, -1, 1); // settings allocator upval? 121 char const* upname = lua_getupvalue(L_, -1, 1); // L_: settings allocator upval?
131 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
132 {
133 raise_luaL_error(L_, "config.allocator() shouldn't have upvalues"); 123 raise_luaL_error(L_, "config.allocator() shouldn't have upvalues");
134 } 124 }
135 // remove this C function from the config table so that it doesn't cause problems 125 // remove this C function from the config table so that it doesn't cause problems
136 // when we transfer the config table in newly created Lua states 126 // when we transfer the config table in newly created Lua states
137 lua_pushnil(L_); // settings allocator nil 127 lua_pushnil(L_); // L_: settings allocator nil
138 lua_setfield(L_, -3, "allocator"); // settings allocator 128 lua_setfield(L_, -3, "allocator"); // L_: settings allocator
139 } 129 } else if (lua_type(L_, -1) == LUA_TSTRING) { // should be "protected"
140 else if (lua_type(L_, -1) == LUA_TSTRING) // should be "protected"
141 {
142 LUA_ASSERT(L_, strcmp(lua_tostring(L_, -1), "protected") == 0); 130 LUA_ASSERT(L_, strcmp(lua_tostring(L_, -1), "protected") == 0);
143 // 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
144 U->protected_allocator.initFrom(L_); 132 U_->protected_allocator.initFrom(L_);
145 U->protected_allocator.installIn(L_); 133 U_->protected_allocator.installIn(L_);
146 // 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
147 U->provide_allocator = luaG_provide_protected_allocator; 135 U_->provide_allocator = luaG_provide_protected_allocator;
148 } 136 }
149 } 137 } else {
150 else
151 {
152 // just grab whatever allocator was provided to lua_newstate 138 // just grab whatever allocator was provided to lua_newstate
153 U->protected_allocator.initFrom(L_); 139 U_->protected_allocator.initFrom(L_);
154 } 140 }
155 lua_pop(L_, 1); // settings 141 lua_pop(L_, 1); // L_: settings
156 STACK_CHECK(L_, 1); 142 STACK_CHECK(L_, 1);
157 143
158 lua_getfield(L_, -1, "internal_allocator"); // settings "libc"|"allocator" 144 lua_getfield(L_, -1, "internal_allocator"); // L_: settings "libc"|"allocator"
159 { 145 {
160 char const* allocator = lua_tostring(L_, -1); 146 char const* allocator = lua_tostring(L_, -1);
161 if (strcmp(allocator, "libc") == 0) 147 if (strcmp(allocator, "libc") == 0) {
162 { 148 U_->internal_allocator = AllocatorDefinition{ libc_lua_Alloc, nullptr };
163 U->internal_allocator = AllocatorDefinition{ libc_lua_Alloc, nullptr }; 149 } else if (U_->provide_allocator == luaG_provide_protected_allocator) {
164 }
165 else if (U->provide_allocator == luaG_provide_protected_allocator)
166 {
167 // 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.
168 U->internal_allocator = U->protected_allocator.makeDefinition(); 151 U_->internal_allocator = U_->protected_allocator.makeDefinition();
169 } 152 } else {
170 else
171 {
172 // no protection required, just use whatever we have as-is. 153 // no protection required, just use whatever we have as-is.
173 U->internal_allocator = U->protected_allocator; 154 U_->internal_allocator = U_->protected_allocator;
174 } 155 }
175 } 156 }
176 lua_pop(L_, 1); // settings 157 lua_pop(L_, 1); // L_: settings
177 STACK_CHECK(L_, 1); 158 STACK_CHECK(L_, 1);
178} 159}
179 160
@@ -204,18 +185,16 @@ enum class FuncSubType
204 Bytecode, 185 Bytecode,
205 Native, 186 Native,
206 FastJIT 187 FastJIT
207} ; 188};
208 189
209FuncSubType luaG_getfuncsubtype(lua_State* L_, int _i) 190FuncSubType luaG_getfuncsubtype(lua_State* L_, int _i)
210{ 191{
211 if (lua_tocfunction(L_, _i)) // nullptr for LuaJIT-fast && bytecode functions 192 if (lua_tocfunction(L_, _i)) { // nullptr for LuaJIT-fast && bytecode functions
212 {
213 return FuncSubType::Native; 193 return FuncSubType::Native;
214 } 194 }
215 { 195 {
216 int mustpush{ 0 }; 196 int mustpush{ 0 };
217 if (lua_absindex(L_, _i) != lua_gettop(L_)) 197 if (lua_absindex(L_, _i) != lua_gettop(L_)) {
218 {
219 lua_pushvalue(L_, _i); 198 lua_pushvalue(L_, _i);
220 mustpush = 1; 199 mustpush = 1;
221 } 200 }
@@ -224,8 +203,7 @@ FuncSubType luaG_getfuncsubtype(lua_State* L_, int _i)
224 // all other cases mean this is either a C or LuaJIT-fast function 203 // all other cases mean this is either a C or LuaJIT-fast function
225 int const dumpres{ lua504_dump(L_, dummy_writer, nullptr, 0) }; 204 int const dumpres{ lua504_dump(L_, dummy_writer, nullptr, 0) };
226 lua_pop(L_, mustpush); 205 lua_pop(L_, mustpush);
227 if (dumpres == 666) 206 if (dumpres == 666) {
228 {
229 return FuncSubType::Bytecode; 207 return FuncSubType::Bytecode;
230 } 208 }
231 } 209 }
@@ -235,28 +213,26 @@ FuncSubType luaG_getfuncsubtype(lua_State* L_, int _i)
235// ################################################################################################# 213// #################################################################################################
236 214
237// inspired from tconcat() in ltablib.c 215// inspired from tconcat() in ltablib.c
238[[nodiscard]] static char const* luaG_pushFQN(lua_State* L_, int t, int last, size_t* length) 216[[nodiscard]] static char const* luaG_pushFQN(lua_State* L_, int t_, int last_, size_t* length_)
239{ 217{
240 luaL_Buffer b; 218 luaL_Buffer b;
241 STACK_CHECK_START_REL(L_, 0); 219 STACK_CHECK_START_REL(L_, 0);
242 // Lua 5.4 pushes &b as light userdata on the stack. be aware of it... 220 // Lua 5.4 pushes &b as light userdata on the stack. be aware of it...
243 luaL_buffinit(L_, &b); // ... {} ... &b? 221 luaL_buffinit(L_, &b); // L_: ... {} ... &b?
244 int i = 1; 222 int i = 1;
245 for (; i < last; ++i) 223 for (; i < last_; ++i) {
246 { 224 lua_rawgeti(L_, t_, i);
247 lua_rawgeti( L_, t, i); 225 luaL_addvalue(&b);
248 luaL_addvalue( &b);
249 luaL_addlstring(&b, "/", 1); 226 luaL_addlstring(&b, "/", 1);
250 } 227 }
251 if (i == last) // add last value (if interval was not empty) 228 if (i == last_) { // add last value (if interval was not empty)
252 { 229 lua_rawgeti(L_, t_, i);
253 lua_rawgeti(L_, t, i);
254 luaL_addvalue(&b); 230 luaL_addvalue(&b);
255 } 231 }
256 // &b is popped at that point (-> replaced by the result) 232 // &b is popped at that point (-> replaced by the result)
257 luaL_pushresult(&b); // ... {} ... "<result>" 233 luaL_pushresult(&b); // L_: ... {} ... "<result>"
258 STACK_CHECK(L_, 1); 234 STACK_CHECK(L_, 1);
259 return lua_tolstring( L_, -1, length); 235 return lua_tolstring(L_, -1, length_);
260} 236}
261 237
262// ################################################################################################# 238// #################################################################################################
@@ -269,7 +245,7 @@ FuncSubType luaG_getfuncsubtype(lua_State* L_, int _i)
269 * if we already had an entry of type [o] = ..., replace the name if the new one is shorter 245 * if we already had an entry of type [o] = ..., replace the name if the new one is shorter
270 * pops the processed object from the stack 246 * pops the processed object from the stack
271 */ 247 */
272static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L_, int _ctx_base, int _depth) 248static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L_, int _ctx_base, int _depth)
273{ 249{
274 // slot 1 in the stack contains the table that receives everything we found 250 // slot 1 in the stack contains the table that receives everything we found
275 int const dest{ _ctx_base }; 251 int const dest{ _ctx_base };
@@ -278,22 +254,22 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L_
278 254
279 size_t prevNameLength, newNameLength; 255 size_t prevNameLength, newNameLength;
280 char const* prevName; 256 char const* prevName;
281 DEBUGSPEW_CODE(char const *newName); 257 DEBUGSPEW_CODE(char const* newName);
282 DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "update_lookup_entry()\n" INDENT_END)); 258 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "update_lookup_entry()\n" INDENT_END(U_)));
283 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); 259 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U_ });
284 260
285 STACK_CHECK_START_REL(L_, 0); 261 STACK_CHECK_START_REL(L_, 0);
286 // first, raise an error if the function is already known 262 // first, raise an error if the function is already known
287 lua_pushvalue(L_, -1); // ... {bfc} k o o 263 lua_pushvalue(L_, -1); // L_: ... {bfc} k o o
288 lua_rawget(L_, dest); // ... {bfc} k o name? 264 lua_rawget(L_, dest); // L_: ... {bfc} k o name?
289 prevName = lua_tolstring( L_, -1, &prevNameLength); // nullptr if we got nil (first encounter of this object) 265 prevName = lua_tolstring(L_, -1, &prevNameLength); // nullptr if we got nil (first encounter of this object)
290 // push name in fqn stack (note that concatenation will crash if name is a not string or a number) 266 // push name in fqn stack (note that concatenation will crash if name is a not string or a number)
291 lua_pushvalue(L_, -3); // ... {bfc} k o name? k 267 lua_pushvalue(L_, -3); // L_: ... {bfc} k o name? k
292 LUA_ASSERT(L_, lua_type(L_, -1) == LUA_TNUMBER || lua_type(L_, -1) == LUA_TSTRING); 268 LUA_ASSERT(L_, lua_type(L_, -1) == LUA_TNUMBER || lua_type(L_, -1) == LUA_TSTRING);
293 ++_depth; 269 ++_depth;
294 lua_rawseti(L_, fqn, _depth); // ... {bfc} k o name? 270 lua_rawseti(L_, fqn, _depth); // L_: ... {bfc} k o name?
295 // generate name 271 // generate name
296 DEBUGSPEW_OR_NOT(newName, std::ignore) = luaG_pushFQN(L_, fqn, _depth, &newNameLength); // ... {bfc} k o name? "f.q.n" 272 DEBUGSPEW_OR_NOT(newName, std::ignore) = luaG_pushFQN(L_, fqn, _depth, &newNameLength); // L_: ... {bfc} k o name? "f.q.n"
297 // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order 273 // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order
298 // on different VMs even when the tables are populated the exact same way. 274 // on different VMs even when the tables are populated the exact same way.
299 // When Lua is built with compatibility options (such as LUA_COMPAT_ALL), 275 // When Lua is built with compatibility options (such as LUA_COMPAT_ALL),
@@ -303,227 +279,200 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L_
303 // Also, nothing prevents any external module from exposing a given object under several names, so... 279 // Also, nothing prevents any external module from exposing a given object under several names, so...
304 // Therefore, when we encounter an object for which a name was previously registered, we need to select the names 280 // Therefore, when we encounter an object for which a name was previously registered, we need to select the names
305 // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded 281 // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded
306 if (prevName != nullptr && (prevNameLength < newNameLength || lua_lessthan(L_, -2, -1))) 282 if (prevName != nullptr && (prevNameLength < newNameLength || lua_lessthan(L_, -2, -1))) {
307 { 283 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END(U_), lua_typename(L_, lua_type(L_, -3)), newName, prevName));
308 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END, lua_typename(L_, lua_type(L_, -3)), newName, prevName));
309 // the previous name is 'smaller' than the one we just generated: keep it! 284 // the previous name is 'smaller' than the one we just generated: keep it!
310 lua_pop(L_, 3); // ... {bfc} k 285 lua_pop(L_, 3); // L_: ... {bfc} k
311 } 286 } else {
312 else
313 {
314 // the name we generated is either the first one, or a better fit for our purposes 287 // the name we generated is either the first one, or a better fit for our purposes
315 if (prevName) 288 if (prevName) {
316 {
317 // clear the previous name for the database to avoid clutter 289 // clear the previous name for the database to avoid clutter
318 lua_insert(L_, -2); // ... {bfc} k o "f.q.n" prevName 290 lua_insert(L_, -2); // L_: ... {bfc} k o "f.q.n" prevName
319 // t[prevName] = nil 291 // t[prevName] = nil
320 lua_pushnil(L_); // ... {bfc} k o "f.q.n" prevName nil 292 lua_pushnil(L_); // L_: ... {bfc} k o "f.q.n" prevName nil
321 lua_rawset(L_, dest); // ... {bfc} k o "f.q.n" 293 lua_rawset(L_, dest); // L_: ... {bfc} k o "f.q.n"
322 } 294 } else {
323 else 295 lua_remove(L_, -2); // L_: ... {bfc} k o "f.q.n"
324 {
325 lua_remove(L_, -2); // ... {bfc} k o "f.q.n"
326 } 296 }
327 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END, lua_typename(L_, lua_type(L_, -2)), newName)); 297 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END(U_), lua_typename(L_, lua_type(L_, -2)), newName));
328 // prepare the stack for database feed 298 // prepare the stack for database feed
329 lua_pushvalue(L_, -1); // ... {bfc} k o "f.q.n" "f.q.n" 299 lua_pushvalue(L_, -1); // L_: ... {bfc} k o "f.q.n" "f.q.n"
330 lua_pushvalue(L_, -3); // ... {bfc} k o "f.q.n" "f.q.n" o 300 lua_pushvalue(L_, -3); // L_: ... {bfc} k o "f.q.n" "f.q.n" o
331 LUA_ASSERT(L_, lua_rawequal(L_, -1, -4)); 301 LUA_ASSERT(L_, lua_rawequal(L_, -1, -4));
332 LUA_ASSERT(L_, lua_rawequal(L_, -2, -3)); 302 LUA_ASSERT(L_, lua_rawequal(L_, -2, -3));
333 // t["f.q.n"] = o 303 // t["f.q.n"] = o
334 lua_rawset(L_, dest); // ... {bfc} k o "f.q.n" 304 lua_rawset(L_, dest); // L_: ... {bfc} k o "f.q.n"
335 // t[o] = "f.q.n" 305 // t[o] = "f.q.n"
336 lua_rawset(L_, dest); // ... {bfc} k 306 lua_rawset(L_, dest); // L_: ... {bfc} k
337 // remove table name from fqn stack 307 // remove table name from fqn stack
338 lua_pushnil(L_); // ... {bfc} k nil 308 lua_pushnil(L_); // L_: ... {bfc} k nil
339 lua_rawseti(L_, fqn, _depth); // ... {bfc} k 309 lua_rawseti(L_, fqn, _depth); // L_: ... {bfc} k
340 } 310 }
341 -- _depth; 311 --_depth;
342 STACK_CHECK(L_, -1); 312 STACK_CHECK(L_, -1);
343} 313}
344 314
345// ################################################################################################# 315// #################################################################################################
346 316
347static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L_, int _ctx_base, int _i, int _depth) 317static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L_, int ctxBase_, int i_, int depth_)
348{ 318{
349 // 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 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot i_
350 int const fqn = _ctx_base + 1; 320 int const fqn = ctxBase_ + 1;
351 // slot 3 contains a cache that stores all already visited tables to avoid infinite recursion loops 321 // slot 3 contains a cache that stores all already visited tables to avoid infinite recursion loops
352 int const cache = _ctx_base + 2; 322 int const cache = ctxBase_ + 2;
353 // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search) 323 // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search)
354 int const breadth_first_cache = lua_gettop(L_) + 1; 324 int const breadth_first_cache = lua_gettop(L_) + 1;
355 DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "populate_func_lookup_table_recur()\n" INDENT_END)); 325 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "populate_func_lookup_table_recur()\n" INDENT_END(U_)));
356 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); 326 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U_ });
357 327
358 STACK_GROW(L_, 6); 328 STACK_GROW(L_, 6);
359 // slot _i contains a table where we search for functions (or a full userdata with a metatable) 329 // slot i_ contains a table where we search for functions (or a full userdata with a metatable)
360 STACK_CHECK_START_REL(L_, 0); // ... {_i} 330 STACK_CHECK_START_REL(L_, 0); // L_: ... {i_}
361 331
362 // if object is a userdata, replace it by its metatable 332 // if object is a userdata, replace it by its metatable
363 if (lua_type(L_, _i) == LUA_TUSERDATA) 333 if (lua_type(L_, i_) == LUA_TUSERDATA) {
364 { 334 lua_getmetatable(L_, i_); // L_: ... {i_} mt
365 lua_getmetatable(L_, _i); // ... {_i} mt 335 lua_replace(L_, i_); // L_: ... {i_}
366 lua_replace(L_, _i); // ... {_i}
367 } 336 }
368 337
369 // if table is already visited, we are done 338 // if table is already visited, we are done
370 lua_pushvalue(L_, _i); // ... {_i} {} 339 lua_pushvalue(L_, i_); // L_: ... {i_} {}
371 lua_rawget(L_, cache); // ... {_i} nil|n 340 lua_rawget(L_, cache); // L_: ... {i_} nil|n
372 lua_Integer visit_count{ lua_tointeger(L_, -1) }; // 0 if nil, else n 341 lua_Integer visit_count{ lua_tointeger(L_, -1) }; // 0 if nil, else n
373 lua_pop(L_, 1); // ... {_i} 342 lua_pop(L_, 1); // L_: ... {i_}
374 STACK_CHECK(L_, 0); 343 STACK_CHECK(L_, 0);
375 if (visit_count > 0) 344 if (visit_count > 0) {
376 { 345 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "already visited\n" INDENT_END(U_)));
377 DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "already visited\n" INDENT_END));
378 return; 346 return;
379 } 347 }
380 348
381 // remember we visited this table (1-visit count) 349 // remember we visited this table (1-visit count)
382 lua_pushvalue(L_, _i); // ... {_i} {} 350 lua_pushvalue(L_, i_); // L_: ... {i_} {}
383 lua_pushinteger(L_, visit_count + 1); // ... {_i} {} 1 351 lua_pushinteger(L_, visit_count + 1); // L_: ... {i_} {} 1
384 lua_rawset(L_, cache); // ... {_i} 352 lua_rawset(L_, cache); // L_: ... {i_}
385 STACK_CHECK(L_, 0); 353 STACK_CHECK(L_, 0);
386 354
387 // this table is at breadth_first_cache index 355 // this table is at breadth_first_cache index
388 lua_newtable(L_); // ... {_i} {bfc} 356 lua_newtable(L_); // L_: ... {i_} {bfc}
389 LUA_ASSERT(L_, lua_gettop(L_) == breadth_first_cache); 357 LUA_ASSERT(L_, lua_gettop(L_) == breadth_first_cache);
390 // iterate over all entries in the processed table 358 // iterate over all entries in the processed table
391 lua_pushnil(L_); // ... {_i} {bfc} nil 359 lua_pushnil(L_); // L_: ... {i_} {bfc} nil
392 while( lua_next(L_, _i) != 0) // ... {_i} {bfc} k v 360 while (lua_next(L_, i_) != 0) { // L_: ... {i_} {bfc} k v
393 {
394 // just for debug, not actually needed 361 // just for debug, not actually needed
395 //char const* key = (lua_type(L, -2) == LUA_TSTRING) ? lua_tostring(L, -2) : "not a string"; 362 // char const* key = (lua_type(L, -2) == LUA_TSTRING) ? lua_tostring(L, -2) : "not a string";
396 // subtable: process it recursively 363 // subtable: process it recursively
397 if (lua_istable(L_, -1)) // ... {_i} {bfc} k {} 364 if (lua_istable(L_, -1)) { // L_: ... {i_} {bfc} k {}
398 {
399 // increment visit count to make sure we will actually scan it at this recursive level 365 // increment visit count to make sure we will actually scan it at this recursive level
400 lua_pushvalue(L_, -1); // ... {_i} {bfc} k {} {} 366 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {}
401 lua_pushvalue(L_, -1); // ... {_i} {bfc} k {} {} {} 367 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {} {}
402 lua_rawget(L_, cache); // ... {_i} {bfc} k {} {} n? 368 lua_rawget(L_, cache); // L_: ... {i_} {bfc} k {} {} n?
403 visit_count = lua_tointeger(L_, -1) + 1; // 1 if we got nil, else n+1 369 visit_count = lua_tointeger(L_, -1) + 1; // 1 if we got nil, else n+1
404 lua_pop(L_, 1); // ... {_i} {bfc} k {} {} 370 lua_pop(L_, 1); // L_: ... {i_} {bfc} k {} {}
405 lua_pushinteger(L_, visit_count); // ... {_i} {bfc} k {} {} n 371 lua_pushinteger(L_, visit_count); // L_: ... {i_} {bfc} k {} {} n
406 lua_rawset(L_, cache); // ... {_i} {bfc} k {} 372 lua_rawset(L_, cache); // L_: ... {i_} {bfc} k {}
407 // store the table in the breadth-first cache 373 // store the table in the breadth-first cache
408 lua_pushvalue(L_, -2); // ... {_i} {bfc} k {} k 374 lua_pushvalue(L_, -2); // L_: ... {i_} {bfc} k {} k
409 lua_pushvalue(L_, -2); // ... {_i} {bfc} k {} k {} 375 lua_pushvalue(L_, -2); // L_: ... {i_} {bfc} k {} k {}
410 lua_rawset(L_, breadth_first_cache); // ... {_i} {bfc} k {} 376 lua_rawset(L_, breadth_first_cache); // L_: ... {i_} {bfc} k {}
411 // generate a name, and if we already had one name, keep whichever is the shorter 377 // generate a name, and if we already had one name, keep whichever is the shorter
412 update_lookup_entry( DEBUGSPEW_PARAM_COMMA(U) L_, _ctx_base, _depth); // ... {_i} {bfc} k 378 update_lookup_entry(DEBUGSPEW_PARAM_COMMA(U_) L_, ctxBase_, depth_); // L_: ... {i_} {bfc} k
413 } 379 } else if (lua_isfunction(L_, -1) && (luaG_getfuncsubtype(L_, -1) != FuncSubType::Bytecode)) {
414 else if (lua_isfunction(L_, -1) && (luaG_getfuncsubtype(L_, -1) != FuncSubType::Bytecode))
415 {
416 // generate a name, and if we already had one name, keep whichever is the shorter 380 // generate a name, and if we already had one name, keep whichever is the shorter
417 // this pops the function from the stack 381 // this pops the function from the stack
418 update_lookup_entry( DEBUGSPEW_PARAM_COMMA(U) L_, _ctx_base, _depth); // ... {_i} {bfc} k 382 update_lookup_entry(DEBUGSPEW_PARAM_COMMA(U_) L_, ctxBase_, depth_); // L_: ... {i_} {bfc} k
419 } 383 } else {
420 else 384 lua_pop(L_, 1); // L_: ... {i_} {bfc} k
421 {
422 lua_pop(L_, 1); // ... {_i} {bfc} k
423 } 385 }
424 STACK_CHECK(L_, 2); 386 STACK_CHECK(L_, 2);
425 } 387 }
426 // now process the tables we encountered at that depth 388 // now process the tables we encountered at that depth
427 ++ _depth; 389 ++depth_;
428 lua_pushnil(L_); // ... {_i} {bfc} nil 390 lua_pushnil(L_); // L_: ... {i_} {bfc} nil
429 while (lua_next(L_, breadth_first_cache) != 0) // ... {_i} {bfc} k {} 391 while (lua_next(L_, breadth_first_cache) != 0) { // L_: ... {i_} {bfc} k {}
430 {
431 DEBUGSPEW_CODE(char const* key = (lua_type(L_, -2) == LUA_TSTRING) ? lua_tostring(L_, -2) : "not a string"); 392 DEBUGSPEW_CODE(char const* key = (lua_type(L_, -2) == LUA_TSTRING) ? lua_tostring(L_, -2) : "not a string");
432 DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "table '%s'\n" INDENT_END, key)); 393 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "table '%s'\n" INDENT_END(U_), key));
433 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); 394 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U_ });
434 // un-visit this table in case we do need to process it 395 // un-visit this table in case we do need to process it
435 lua_pushvalue(L_, -1); // ... {_i} {bfc} k {} {} 396 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {}
436 lua_rawget(L_, cache); // ... {_i} {bfc} k {} n 397 lua_rawget(L_, cache); // L_: ... {i_} {bfc} k {} n
437 LUA_ASSERT(L_, lua_type(L_, -1) == LUA_TNUMBER); 398 LUA_ASSERT(L_, lua_type(L_, -1) == LUA_TNUMBER);
438 visit_count = lua_tointeger(L_, -1) - 1; 399 visit_count = lua_tointeger(L_, -1) - 1;
439 lua_pop(L_, 1); // ... {_i} {bfc} k {} 400 lua_pop(L_, 1); // L_: ... {i_} {bfc} k {}
440 lua_pushvalue(L_, -1); // ... {_i} {bfc} k {} {} 401 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {}
441 if (visit_count > 0) 402 if (visit_count > 0) {
442 { 403 lua_pushinteger(L_, visit_count); // L_: ... {i_} {bfc} k {} {} n
443 lua_pushinteger(L_, visit_count); // ... {_i} {bfc} k {} {} n 404 } else {
444 } 405 lua_pushnil(L_); // L_: ... {i_} {bfc} k {} {} nil
445 else
446 {
447 lua_pushnil(L_); // ... {_i} {bfc} k {} {} nil
448 } 406 }
449 lua_rawset(L_, cache); // ... {_i} {bfc} k {} 407 lua_rawset(L_, cache); // L_: ... {i_} {bfc} k {}
450 // push table name in fqn stack (note that concatenation will crash if name is a not string!) 408 // push table name in fqn stack (note that concatenation will crash if name is a not string!)
451 lua_pushvalue(L_, -2); // ... {_i} {bfc} k {} k 409 lua_pushvalue(L_, -2); // L_: ... {i_} {bfc} k {} k
452 lua_rawseti(L_, fqn, _depth); // ... {_i} {bfc} k {} 410 lua_rawseti(L_, fqn, depth_); // L_: ... {i_} {bfc} k {}
453 populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U) L_, _ctx_base, lua_gettop(L_), _depth); 411 populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U_) L_, ctxBase_, lua_gettop(L_), depth_);
454 lua_pop(L_, 1); // ... {_i} {bfc} k 412 lua_pop(L_, 1); // L_: ... {i_} {bfc} k
455 STACK_CHECK(L_, 2); 413 STACK_CHECK(L_, 2);
456 } 414 }
457 // remove table name from fqn stack 415 // remove table name from fqn stack
458 lua_pushnil(L_); // ... {_i} {bfc} nil 416 lua_pushnil(L_); // L_: ... {i_} {bfc} nil
459 lua_rawseti(L_, fqn, _depth); // ... {_i} {bfc} 417 lua_rawseti(L_, fqn, depth_); // L_: ... {i_} {bfc}
460 -- _depth; 418 --depth_;
461 // we are done with our cache 419 // we are done with our cache
462 lua_pop(L_, 1); // ... {_i} 420 lua_pop(L_, 1); // L_: ... {i_}
463 STACK_CHECK(L_, 0); 421 STACK_CHECK(L_, 0);
464 // we are done // ... {_i} {bfc} 422 // we are done // L_: ... {i_} {bfc}
465} 423}
466 424
467// ################################################################################################# 425// #################################################################################################
468 426
469/* 427// create a "fully.qualified.name" <-> function equivalence database
470 * create a "fully.qualified.name" <-> function equivalence database
471 */
472void populate_func_lookup_table(lua_State* L_, int i_, char const* name_) 428void populate_func_lookup_table(lua_State* L_, int i_, char const* name_)
473{ 429{
474 int const ctx_base = lua_gettop(L_) + 1; 430 int const ctx_base = lua_gettop(L_) + 1;
475 int const in_base = lua_absindex(L_, i_); 431 int const in_base = lua_absindex(L_, i_);
476 int start_depth = 0; 432 int start_depth = 0;
477 DEBUGSPEW_CODE(Universe* U = universe_get(L_)); 433 DEBUGSPEW_CODE(Universe* U = universe_get(L_));
478 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L_, name_ ? name_ : "nullptr")); 434 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END(U), L_, name_ ? name_ : "nullptr"));
479 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); 435 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U });
480 STACK_GROW(L_, 3); 436 STACK_GROW(L_, 3);
481 STACK_CHECK_START_REL(L_, 0); 437 STACK_CHECK_START_REL(L_, 0);
482 kLookupRegKey.pushValue(L_); // {} 438 kLookupRegKey.pushValue(L_); // L_: {}
483 STACK_CHECK(L_, 1); 439 STACK_CHECK(L_, 1);
484 LUA_ASSERT(L_, lua_istable(L_, -1)); 440 LUA_ASSERT(L_, lua_istable(L_, -1));
485 if (lua_type(L_, in_base) == LUA_TFUNCTION) // for example when a module is a simple function 441 if (lua_type(L_, in_base) == LUA_TFUNCTION) { // for example when a module is a simple function
486 {
487 name_ = name_ ? name_ : "nullptr"; 442 name_ = name_ ? name_ : "nullptr";
488 lua_pushvalue(L_, in_base); // {} f 443 lua_pushvalue(L_, in_base); // L_: {} f
489 lua_pushstring(L_, name_); // {} f _name 444 lua_pushstring(L_, name_); // L_: {} f _name
490 lua_rawset(L_, -3); // {} 445 lua_rawset(L_, -3); // L_: {}
491 lua_pushstring(L_, name_); // {} _name 446 lua_pushstring(L_, name_); // L_: {} _name
492 lua_pushvalue(L_, in_base); // {} _name f 447 lua_pushvalue(L_, in_base); // L_: {} _name f
493 lua_rawset(L_, -3); // {} 448 lua_rawset(L_, -3); // L_: {}
494 lua_pop(L_, 1); // 449 lua_pop(L_, 1); // L_:
495 } 450 } else if (lua_type(L_, in_base) == LUA_TTABLE) {
496 else if (lua_type(L_, in_base) == LUA_TTABLE) 451 lua_newtable(L_); // L_: {} {fqn}
497 { 452 if (name_) {
498 lua_newtable(L_); // {} {fqn}
499 if (name_)
500 {
501 STACK_CHECK(L_, 2); 453 STACK_CHECK(L_, 2);
502 lua_pushstring(L_, name_); // {} {fqn} "name" 454 lua_pushstring(L_, name_); // L_: {} {fqn} "name"
503 // generate a name, and if we already had one name, keep whichever is the shorter 455 // generate a name, and if we already had one name, keep whichever is the shorter
504 lua_pushvalue(L_, in_base); // {} {fqn} "name" t 456 lua_pushvalue(L_, in_base); // L_: {} {fqn} "name" t
505 update_lookup_entry(DEBUGSPEW_PARAM_COMMA(U) L_, ctx_base, start_depth); // {} {fqn} "name" 457 update_lookup_entry(DEBUGSPEW_PARAM_COMMA(U) L_, ctx_base, start_depth); // L_: {} {fqn} "name"
506 // don't forget to store the name at the bottom of the fqn stack 458 // don't forget to store the name at the bottom of the fqn stack
507 ++ start_depth; 459 ++start_depth;
508 lua_rawseti(L_, -2, start_depth); // {} {fqn} 460 lua_rawseti(L_, -2, start_depth); // L_: {} {fqn}
509 STACK_CHECK(L_, 2); 461 STACK_CHECK(L_, 2);
510 } 462 }
511 // retrieve the cache, create it if we haven't done it yet 463 // retrieve the cache, create it if we haven't done it yet
512 kLookupCacheRegKey.pushValue(L_); // {} {fqn} {cache}? 464 kLookupCacheRegKey.pushValue(L_); // L_: {} {fqn} {cache}?
513 if (lua_isnil(L_, -1)) 465 if (lua_isnil(L_, -1)) {
514 { 466 lua_pop(L_, 1); // L_: {} {fqn}
515 lua_pop(L_, 1); // {} {fqn} 467 lua_newtable(L_); // L_: {} {fqn} {cache}
516 lua_newtable(L_); // {} {fqn} {cache}
517 kLookupCacheRegKey.setValue(L_, [](lua_State* L_) { lua_pushvalue(L_, -2); }); 468 kLookupCacheRegKey.setValue(L_, [](lua_State* L_) { lua_pushvalue(L_, -2); });
518 STACK_CHECK(L_, 3); 469 STACK_CHECK(L_, 3);
519 } 470 }
520 // process everything we find in that table, filling in lookup data for all functions and tables we see there 471 // process everything we find in that table, filling in lookup data for all functions and tables we see there
521 populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U) L_, ctx_base, in_base, start_depth); 472 populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U) L_, ctx_base, in_base, start_depth);
522 lua_pop(L_, 3); 473 lua_pop(L_, 3);
523 } 474 } else {
524 else 475 lua_pop(L_, 1); // L_:
525 {
526 lua_pop(L_, 1); //
527 raise_luaL_error(L_, "unsupported module type %s", lua_typename(L_, lua_type(L_, in_base))); 476 raise_luaL_error(L_, "unsupported module type %s", lua_typename(L_, lua_type(L_, in_base)));
528 } 477 }
529 STACK_CHECK(L_, 0); 478 STACK_CHECK(L_, 0);
@@ -536,38 +485,35 @@ void populate_func_lookup_table(lua_State* L_, int i_, char const* name_)
536// xxh64 of string "kMtIdRegKey" generated at https://www.pelock.com/products/hash-calculator 485// xxh64 of string "kMtIdRegKey" generated at https://www.pelock.com/products/hash-calculator
537static constexpr RegistryUniqueKey kMtIdRegKey{ 0xA8895DCF4EC3FE3Cull }; 486static constexpr RegistryUniqueKey kMtIdRegKey{ 0xA8895DCF4EC3FE3Cull };
538 487
539/* 488// get a unique ID for metatable at [i].
540* Get a unique ID for metatable at [i]. 489[[nodiscard]] static lua_Integer get_mt_id(Universe* U_, lua_State* L_, int i)
541*/
542[[nodiscard]] static lua_Integer get_mt_id(Universe* U, lua_State* L_, int i)
543{ 490{
544 i = lua_absindex(L_, i); 491 i = lua_absindex(L_, i);
545 492
546 STACK_GROW(L_, 3); 493 STACK_GROW(L_, 3);
547 494
548 STACK_CHECK_START_REL(L_, 0); 495 STACK_CHECK_START_REL(L_, 0);
549 push_registry_subtable(L_, kMtIdRegKey); // ... _R[kMtIdRegKey] 496 push_registry_subtable(L_, kMtIdRegKey); // L_: ... _R[kMtIdRegKey]
550 lua_pushvalue(L_, i); // ... _R[kMtIdRegKey] {mt} 497 lua_pushvalue(L_, i); // L_: ... _R[kMtIdRegKey] {mt}
551 lua_rawget(L_, -2); // ... _R[kMtIdRegKey] mtk? 498 lua_rawget(L_, -2); // L_: ... _R[kMtIdRegKey] mtk?
552 499
553 lua_Integer id{ lua_tointeger(L_, -1) }; // 0 for nil 500 lua_Integer id{ lua_tointeger(L_, -1) }; // 0 for nil
554 lua_pop(L_, 1); // ... _R[kMtIdRegKey] 501 lua_pop(L_, 1); // L_: ... _R[kMtIdRegKey]
555 STACK_CHECK(L_, 1); 502 STACK_CHECK(L_, 1);
556 503
557 if (id == 0) 504 if (id == 0) {
558 { 505 id = U_->next_mt_id.fetch_add(1, std::memory_order_relaxed);
559 id = U->next_mt_id.fetch_add(1, std::memory_order_relaxed);
560 506
561 // Create two-way references: id_uint <-> table 507 // Create two-way references: id_uint <-> table
562 lua_pushvalue(L_, i); // ... _R[kMtIdRegKey] {mt} 508 lua_pushvalue(L_, i); // L_: ... _R[kMtIdRegKey] {mt}
563 lua_pushinteger(L_, id); // ... _R[kMtIdRegKey] {mt} id 509 lua_pushinteger(L_, id); // L_: ... _R[kMtIdRegKey] {mt} id
564 lua_rawset(L_, -3); // ... _R[kMtIdRegKey] 510 lua_rawset(L_, -3); // L_: ... _R[kMtIdRegKey]
565 511
566 lua_pushinteger(L_, id); // ... _R[kMtIdRegKey] id 512 lua_pushinteger(L_, id); // L_: ... _R[kMtIdRegKey] id
567 lua_pushvalue(L_, i); // ... _R[kMtIdRegKey] id {mt} 513 lua_pushvalue(L_, i); // L_: ... _R[kMtIdRegKey] id {mt}
568 lua_rawset(L_, -3); // ... _R[kMtIdRegKey] 514 lua_rawset(L_, -3); // L_: ... _R[kMtIdRegKey]
569 } 515 }
570 lua_pop(L_, 1); // ... 516 lua_pop(L_, 1); // L_: ...
571 STACK_CHECK(L_, 0); 517 STACK_CHECK(L_, 0);
572 518
573 return id; 519 return id;
@@ -599,74 +545,62 @@ static constexpr RegistryUniqueKey kMtIdRegKey{ 0xA8895DCF4EC3FE3Cull };
599 545
600// ################################################################################################# 546// #################################################################################################
601 547
602/* 548// retrieve the name of a function/table in the lookup database
603 * retrieve the name of a function/table in the lookup database 549[[nodiscard]] static char const* find_lookup_name(lua_State* L_, int i_, LookupMode mode_, char const* upName_, size_t* len_)
604 */
605[[nodiscard]] static char const* find_lookup_name(lua_State* L_, int i, LookupMode mode_, char const* upName_, size_t* len_)
606{ 550{
607 DEBUGSPEW_CODE( Universe* const U = universe_get( L_)); 551 DEBUGSPEW_CODE(Universe* const U = universe_get(L_));
608 char const* fqn; 552 char const* fqn;
609 LUA_ASSERT(L_, lua_isfunction( L_, i) || lua_istable( L_, i)); // ... v ... 553 LUA_ASSERT(L_, lua_isfunction(L_, i_) || lua_istable(L_, i_)); // L_: ... v ...
610 STACK_CHECK_START_REL(L_, 0); 554 STACK_CHECK_START_REL(L_, 0);
611 STACK_GROW( L_, 3); // up to 3 slots are necessary on error 555 STACK_GROW(L_, 3); // up to 3 slots are necessary on error
612 if (mode_ == LookupMode::FromKeeper) 556 if (mode_ == LookupMode::FromKeeper) {
613 { 557 lua_CFunction f = lua_tocfunction(L_, i_); // should *always* be func_lookup_sentinel or table_lookup_sentinel!
614 lua_CFunction f = lua_tocfunction( L_, i); // should *always* be func_lookup_sentinel or table_lookup_sentinel! 558 if (f == func_lookup_sentinel || f == table_lookup_sentinel || f == userdata_clone_sentinel) {
615 if (f == func_lookup_sentinel || f == table_lookup_sentinel || f == userdata_clone_sentinel) 559 lua_getupvalue(L_, i_, 1); // L_: ... v ... "f.q.n"
616 { 560 } else {
617 lua_getupvalue( L_, i, 1); // ... v ... "f.q.n"
618 }
619 else
620 {
621 // if this is not a sentinel, this is some user-created table we wanted to lookup 561 // if this is not a sentinel, this is some user-created table we wanted to lookup
622 LUA_ASSERT(L_, nullptr == f && lua_istable(L_, i)); 562 LUA_ASSERT(L_, nullptr == f && lua_istable(L_, i_));
623 // push anything that will convert to nullptr string 563 // push anything that will convert to nullptr string
624 lua_pushnil( L_); // ... v ... nil 564 lua_pushnil(L_); // L_: ... v ... nil
625 } 565 }
626 } 566 } else {
627 else
628 {
629 // fetch the name from the source state's lookup table 567 // fetch the name from the source state's lookup table
630 kLookupRegKey.pushValue(L_); // ... v ... {} 568 kLookupRegKey.pushValue(L_); // L_: ... v ... {}
631 STACK_CHECK( L_, 1); 569 STACK_CHECK(L_, 1);
632 LUA_ASSERT(L_, lua_istable( L_, -1)); 570 LUA_ASSERT(L_, lua_istable(L_, -1));
633 lua_pushvalue( L_, i); // ... v ... {} v 571 lua_pushvalue(L_, i_); // L_: ... v ... {} v
634 lua_rawget( L_, -2); // ... v ... {} "f.q.n" 572 lua_rawget(L_, -2); // L_: ... v ... {} "f.q.n"
635 } 573 }
636 fqn = lua_tolstring( L_, -1, len_); 574 fqn = lua_tolstring(L_, -1, len_);
637 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END, fqn)); 575 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END(U), fqn));
638 // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database 576 // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database
639 lua_pop( L_, (mode_ == LookupMode::FromKeeper) ? 1 : 2); // ... v ... 577 lua_pop(L_, (mode_ == LookupMode::FromKeeper) ? 1 : 2); // L_: ... v ...
640 STACK_CHECK( L_, 0); 578 STACK_CHECK(L_, 0);
641 if (nullptr == fqn && !lua_istable(L_, i)) // raise an error if we try to send an unknown function (but not for tables) 579 if (nullptr == fqn && !lua_istable(L_, i_)) { // raise an error if we try to send an unknown function (but not for tables)
642 {
643 char const *from, *typewhat, *what, *gotchaA, *gotchaB; 580 char const *from, *typewhat, *what, *gotchaA, *gotchaB;
644 // try to discover the name of the function we want to send 581 // try to discover the name of the function we want to send
645 lua_getglobal( L_, "decoda_name"); // ... v ... decoda_name 582 lua_getglobal(L_, "decoda_name"); // L_: ... v ... decoda_name
646 from = lua_tostring( L_, -1); 583 from = lua_tostring(L_, -1);
647 lua_pushcfunction( L_, luaG_nameof); // ... v ... decoda_name luaG_nameof 584 lua_pushcfunction(L_, luaG_nameof); // L_: ... v ... decoda_name luaG_nameof
648 lua_pushvalue( L_, i); // ... v ... decoda_name luaG_nameof t 585 lua_pushvalue(L_, i_); // L_: ... v ... decoda_name luaG_nameof t
649 lua_call( L_, 1, 2); // ... v ... decoda_name "type" "name"|nil 586 lua_call(L_, 1, 2); // L_: ... v ... decoda_name "type" "name"|nil
650 typewhat = (lua_type( L_, -2) == LUA_TSTRING) ? lua_tostring( L_, -2) : luaL_typename( L_, -2); 587 typewhat = (lua_type(L_, -2) == LUA_TSTRING) ? lua_tostring(L_, -2) : luaL_typename(L_, -2);
651 // second return value can be nil if the table was not found 588 // second return value can be nil if the table was not found
652 // probable reason: the function was removed from the source Lua state before Lanes was required. 589 // probable reason: the function was removed from the source Lua state before Lanes was required.
653 if (lua_isnil( L_, -1)) 590 if (lua_isnil(L_, -1)) {
654 {
655 gotchaA = " referenced by"; 591 gotchaA = " referenced by";
656 gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)"; 592 gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)";
657 what = upName_; 593 what = upName_;
658 } 594 } else {
659 else
660 {
661 gotchaA = ""; 595 gotchaA = "";
662 gotchaB = ""; 596 gotchaB = "";
663 what = (lua_type( L_, -1) == LUA_TSTRING) ? lua_tostring( L_, -1) : luaL_typename( L_, -1); 597 what = (lua_type(L_, -1) == LUA_TSTRING) ? lua_tostring(L_, -1) : luaL_typename(L_, -1);
664 } 598 }
665 raise_luaL_error(L_, "%s%s '%s' not found in %s origin transfer database.%s", typewhat, gotchaA, what, from ? from : "main", gotchaB); 599 raise_luaL_error(L_, "%s%s '%s' not found in %s origin transfer database.%s", typewhat, gotchaA, what, from ? from : "main", gotchaB);
666 *len_ = 0; 600 *len_ = 0;
667 return nullptr; 601 return nullptr;
668 } 602 }
669 STACK_CHECK( L_, 0); 603 STACK_CHECK(L_, 0);
670 return fqn; 604 return fqn;
671} 605}
672 606
@@ -678,60 +612,54 @@ static constexpr RegistryUniqueKey kMtIdRegKey{ 0xA8895DCF4EC3FE3Cull };
678 // get the name of the table we want to send 612 // get the name of the table we want to send
679 size_t len; 613 size_t len;
680 char const* fqn = find_lookup_name(L1, L1_i, mode, name, &len); 614 char const* fqn = find_lookup_name(L1, L1_i, mode, name, &len);
681 if (nullptr == fqn) // name not found, it is some user-created table 615 if (nullptr == fqn) { // name not found, it is some user-created table
682 {
683 return false; 616 return false;
684 } 617 }
685 // push the equivalent table in the destination's stack, retrieved from the lookup table 618 // push the equivalent table in the destination's stack, retrieved from the lookup table
686 STACK_CHECK_START_REL(L2, 0); // L // L2 619 STACK_CHECK_START_REL(L2, 0);
687 STACK_GROW(L2, 3); // up to 3 slots are necessary on error 620 STACK_GROW(L2, 3); // up to 3 slots are necessary on error
688 switch (mode) 621 switch (mode) {
689 { 622 default: // shouldn't happen, in theory...
690 default: // shouldn't happen, in theory...
691 raise_luaL_error(L1, "internal error: unknown lookup mode"); 623 raise_luaL_error(L1, "internal error: unknown lookup mode");
692 break; 624 break;
693 625
694 case LookupMode::ToKeeper: 626 case LookupMode::ToKeeper:
695 // push a sentinel closure that holds the lookup name as upvalue 627 // push a sentinel closure that holds the lookup name as upvalue
696 lua_pushlstring(L2, fqn, len); // "f.q.n" 628 lua_pushlstring(L2, fqn, len); // L1: ... t ... L2: "f.q.n"
697 lua_pushcclosure(L2, table_lookup_sentinel, 1); // f 629 lua_pushcclosure(L2, table_lookup_sentinel, 1); // L1: ... t ... L2: f
698 break; 630 break;
699 631
700 case LookupMode::LaneBody: 632 case LookupMode::LaneBody:
701 case LookupMode::FromKeeper: 633 case LookupMode::FromKeeper:
702 kLookupRegKey.pushValue(L2); // {} 634 kLookupRegKey.pushValue(L2); // L1: ... t ... L2: {}
703 STACK_CHECK(L2, 1); 635 STACK_CHECK(L2, 1);
704 LUA_ASSERT(L1, lua_istable(L2, -1)); 636 LUA_ASSERT(L1, lua_istable(L2, -1));
705 lua_pushlstring(L2, fqn, len); // {} "f.q.n" 637 lua_pushlstring(L2, fqn, len); // L2: {} "f.q.n"
706 lua_rawget(L2, -2); // {} t 638 lua_rawget(L2, -2); // L2: {} t
707 // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead) 639 // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead)
708 // but not when we extract something out of a keeper, as there is nothing to clone! 640 // but not when we extract something out of a keeper, as there is nothing to clone!
709 if (lua_isnil(L2, -1) && mode == LookupMode::LaneBody) 641 if (lua_isnil(L2, -1) && mode == LookupMode::LaneBody) {
710 { 642 lua_pop(L2, 2); // L1: ... t ... L2:
711 lua_pop(L2, 2); //
712 STACK_CHECK(L2, 0); 643 STACK_CHECK(L2, 0);
713 return false; 644 return false;
714 } 645 } else if (!lua_istable(L2, -1)) {
715 else if (!lua_istable(L2, -1)) 646 char const *from, *to;
716 { 647 lua_getglobal(L1, "decoda_name"); // L1: ... t ... decoda_name
717 char const* from, *to;
718 lua_getglobal(L1, "decoda_name"); // ... t ... decoda_name
719 from = lua_tostring(L1, -1); 648 from = lua_tostring(L1, -1);
720 lua_pop(L1, 1); // ... t ... 649 lua_pop(L1, 1); // L1: ... t ...
721 lua_getglobal(L2, "decoda_name"); // {} t decoda_name 650 lua_getglobal(L2, "decoda_name"); // L1: ... t ... L2: {} t decoda_name
722 to = lua_tostring(L2, -1); 651 to = lua_tostring(L2, -1);
723 lua_pop(L2, 1); // {} t 652 lua_pop(L2, 1); // L1: ... t ... L2: {} t
724 // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error 653 // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error
725 raise_luaL_error( 654 raise_luaL_error(
726 (mode == LookupMode::FromKeeper) ? L2 : L1 655 (mode == LookupMode::FromKeeper) ? L2 : L1,
727 , "INTERNAL ERROR IN %s: table '%s' not found in %s destination transfer database." 656 "INTERNAL ERROR IN %s: table '%s' not found in %s destination transfer database.",
728 , from ? from : "main" 657 from ? from : "main",
729 , fqn 658 fqn,
730 , to ? to : "main" 659 to ? to : "main");
731 );
732 return false; 660 return false;
733 } 661 }
734 lua_remove(L2, -2); // t 662 lua_remove(L2, -2); // L1: ... t ... L2: t
735 break; 663 break;
736 } 664 }
737 STACK_CHECK(L2, 1); 665 STACK_CHECK(L2, 1);
@@ -740,12 +668,12 @@ static constexpr RegistryUniqueKey kMtIdRegKey{ 0xA8895DCF4EC3FE3Cull };
740 668
741// ################################################################################################# 669// #################################################################################################
742 670
743/* 671/*
744 * Check if we've already copied the same table from 'L', and 672 * Check if we've already copied the same table from 'L1_', and
745 * reuse the old copy. This allows table upvalues shared by multiple 673 * reuse the old copy. This allows table upvalues shared by multiple
746 * local functions to point to the same table, also in the target. 674 * local functions to point to the same table, also in the target.
747 * 675 *
748 * Always pushes a table to 'L2'. 676 * Always pushes a table to 'L2_'.
749 * 677 *
750 * Returns true if the table was cached (no need to fill it!); false if 678 * Returns true if the table was cached (no need to fill it!); false if
751 * it's a virgin. 679 * it's a virgin.
@@ -755,271 +683,247 @@ static constexpr RegistryUniqueKey kMtIdRegKey{ 0xA8895DCF4EC3FE3Cull };
755 void const* p{ lua_topointer(L1, i) }; 683 void const* p{ lua_topointer(L1, i) };
756 684
757 LUA_ASSERT(L1, L2_cache_i != 0); 685 LUA_ASSERT(L1, L2_cache_i != 0);
758 STACK_GROW(L2, 3); // L2 686 STACK_GROW(L2, 3);
759 STACK_CHECK_START_REL(L2, 0); 687 STACK_CHECK_START_REL(L2, 0);
760 688
761 // We don't need to use the from state ('L1') in ID since the life span 689 // We don't need to use the from state ('L1') in ID since the life span
762 // is only for the duration of a copy (both states are locked). 690 // is only for the duration of a copy (both states are locked).
763 // push a light userdata uniquely representing the table 691 // push a light userdata uniquely representing the table
764 lua_pushlightuserdata(L2, const_cast<void*>(p)); // ... p 692 lua_pushlightuserdata(L2, const_cast<void*>(p)); // L2: ... p
765 693
766 //fprintf(stderr, "<< ID: %s >>\n", lua_tostring(L2, -1)); 694 // fprintf(stderr, "<< ID: %s >>\n", lua_tostring(L2, -1));
767 695
768 lua_rawget(L2, L2_cache_i); // ... {cached|nil} 696 lua_rawget(L2, L2_cache_i); // L2: ... {cached|nil}
769 bool const not_found_in_cache{ lua_isnil(L2, -1) }; 697 bool const not_found_in_cache{ lua_isnil(L2, -1) };
770 if (not_found_in_cache) 698 if (not_found_in_cache) {
771 {
772 // create a new entry in the cache 699 // create a new entry in the cache
773 lua_pop(L2, 1); // ... 700 lua_pop(L2, 1); // L2: ...
774 lua_newtable(L2); // ... {} 701 lua_newtable(L2); // L2: ... {}
775 lua_pushlightuserdata(L2, const_cast<void*>(p)); // ... {} p 702 lua_pushlightuserdata(L2, const_cast<void*>(p)); // L2: ... {} p
776 lua_pushvalue(L2, -2); // ... {} p {} 703 lua_pushvalue(L2, -2); // L2: ... {} p {}
777 lua_rawset(L2, L2_cache_i); // ... {} 704 lua_rawset(L2, L2_cache_i); // L2: ... {}
778 } 705 }
779 STACK_CHECK(L2, 1); 706 STACK_CHECK(L2, 1);
780 LUA_ASSERT(L1, lua_istable( L2, -1)); 707 LUA_ASSERT(L1, lua_istable(L2, -1));
781 return !not_found_in_cache; 708 return !not_found_in_cache;
782} 709}
783 710
784// ################################################################################################# 711// #################################################################################################
785 712
786/* 713// Return some name helping to identify an object
787 * Return some name helping to identify an object
788 */
789[[nodiscard]] static int discover_object_name_recur(lua_State* L_, int shortest_, int depth_) 714[[nodiscard]] static int discover_object_name_recur(lua_State* L_, int shortest_, int depth_)
790{ 715{
791 int const what = 1; // o "r" {c} {fqn} ... {?} 716 int const what = 1; // L_: o "r" {c} {fqn} ... {?}
792 int const result = 2; 717 int const result = 2;
793 int const cache = 3; 718 int const cache = 3;
794 int const fqn = 4; 719 int const fqn = 4;
795 // no need to scan this table if the name we will discover is longer than one we already know 720 // no need to scan this table if the name we will discover is longer than one we already know
796 if (shortest_ <= depth_ + 1) 721 if (shortest_ <= depth_ + 1) {
797 {
798 return shortest_; 722 return shortest_;
799 } 723 }
800 STACK_GROW(L_, 3); 724 STACK_GROW(L_, 3);
801 STACK_CHECK_START_REL(L_, 0); 725 STACK_CHECK_START_REL(L_, 0);
802 // stack top contains the table to search in 726 // stack top contains the table to search in
803 lua_pushvalue(L_, -1); // o "r" {c} {fqn} ... {?} {?} 727 lua_pushvalue(L_, -1); // L_: o "r" {c} {fqn} ... {?} {?}
804 lua_rawget(L_, cache); // o "r" {c} {fqn} ... {?} nil/1 728 lua_rawget(L_, cache); // L_: o "r" {c} {fqn} ... {?} nil/1
805 // if table is already visited, we are done 729 // if table is already visited, we are done
806 if (!lua_isnil(L_, -1)) 730 if (!lua_isnil(L_, -1)) {
807 { 731 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?}
808 lua_pop(L_, 1); // o "r" {c} {fqn} ... {?}
809 return shortest_; 732 return shortest_;
810 } 733 }
811 // examined table is not in the cache, add it now 734 // examined table is not in the cache, add it now
812 lua_pop(L_, 1); // o "r" {c} {fqn} ... {?} 735 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?}
813 lua_pushvalue(L_, -1); // o "r" {c} {fqn} ... {?} {?} 736 lua_pushvalue(L_, -1); // L_: o "r" {c} {fqn} ... {?} {?}
814 lua_pushinteger(L_, 1); // o "r" {c} {fqn} ... {?} {?} 1 737 lua_pushinteger(L_, 1); // L_: o "r" {c} {fqn} ... {?} {?} 1
815 lua_rawset(L_, cache); // o "r" {c} {fqn} ... {?} 738 lua_rawset(L_, cache); // L_: o "r" {c} {fqn} ... {?}
816 // scan table contents 739 // scan table contents
817 lua_pushnil(L_); // o "r" {c} {fqn} ... {?} nil 740 lua_pushnil(L_); // L_: o "r" {c} {fqn} ... {?} nil
818 while (lua_next(L_, -2)) // o "r" {c} {fqn} ... {?} k v 741 while (lua_next(L_, -2)) { // L_: o "r" {c} {fqn} ... {?} k v
819 { 742 // char const *const strKey = (lua_type(L_, -2) == LUA_TSTRING) ? lua_tostring(L_, -2) : nullptr; // only for debugging
820 //char const *const strKey = (lua_type(L_, -2) == LUA_TSTRING) ? lua_tostring(L_, -2) : nullptr; // only for debugging 743 // lua_Number const numKey = (lua_type(L_, -2) == LUA_TNUMBER) ? lua_tonumber(L_, -2) : -6666; // only for debugging
821 //lua_Number const numKey = (lua_type(L_, -2) == LUA_TNUMBER) ? lua_tonumber(L_, -2) : -6666; // only for debugging
822 STACK_CHECK(L_, 2); 744 STACK_CHECK(L_, 2);
823 // append key name to fqn stack 745 // append key name to fqn stack
824 ++ depth_; 746 ++depth_;
825 lua_pushvalue(L_, -2); // o "r" {c} {fqn} ... {?} k v k 747 lua_pushvalue(L_, -2); // L_: o "r" {c} {fqn} ... {?} k v k
826 lua_rawseti(L_, fqn, depth_); // o "r" {c} {fqn} ... {?} k v 748 lua_rawseti(L_, fqn, depth_); // L_: o "r" {c} {fqn} ... {?} k v
827 if (lua_rawequal(L_, -1, what)) // is it what we are looking for? 749 if (lua_rawequal(L_, -1, what)) { // is it what we are looking for?
828 {
829 STACK_CHECK(L_, 2); 750 STACK_CHECK(L_, 2);
830 // update shortest name 751 // update shortest name
831 if (depth_ < shortest_) 752 if (depth_ < shortest_) {
832 {
833 shortest_ = depth_; 753 shortest_ = depth_;
834 std::ignore = luaG_pushFQN(L_, fqn, depth_, nullptr); // o "r" {c} {fqn} ... {?} k v "fqn" 754 std::ignore = luaG_pushFQN(L_, fqn, depth_, nullptr); // L_: o "r" {c} {fqn} ... {?} k v "fqn"
835 lua_replace(L_, result); // o "r" {c} {fqn} ... {?} k v 755 lua_replace(L_, result); // L_: o "r" {c} {fqn} ... {?} k v
836 } 756 }
837 // no need to search further at this level 757 // no need to search further at this level
838 lua_pop(L_, 2); // o "r" {c} {fqn} ... {?} 758 lua_pop(L_, 2); // L_: o "r" {c} {fqn} ... {?}
839 STACK_CHECK(L_, 0); 759 STACK_CHECK(L_, 0);
840 break; 760 break;
841 } 761 }
842 switch (lua_type(L_, -1)) // o "r" {c} {fqn} ... {?} k v 762 switch (lua_type(L_, -1)) { // L_: o "r" {c} {fqn} ... {?} k v
843 { 763 default: // nil, boolean, light userdata, number and string aren't identifiable
844 default: // nil, boolean, light userdata, number and string aren't identifiable
845 break; 764 break;
846 765
847 case LUA_TTABLE: // o "r" {c} {fqn} ... {?} k {} 766 case LUA_TTABLE: // L_: o "r" {c} {fqn} ... {?} k {}
848 STACK_CHECK(L_, 2); 767 STACK_CHECK(L_, 2);
849 shortest_ = discover_object_name_recur(L_, shortest_, depth_); 768 shortest_ = discover_object_name_recur(L_, shortest_, depth_);
850 // search in the table's metatable too 769 // search in the table's metatable too
851 if (lua_getmetatable(L_, -1)) // o "r" {c} {fqn} ... {?} k {} {mt} 770 if (lua_getmetatable(L_, -1)) { // L_: o "r" {c} {fqn} ... {?} k {} {mt}
852 { 771 if (lua_istable(L_, -1)) {
853 if (lua_istable(L_, -1)) 772 ++depth_;
854 { 773 lua_pushliteral(L_, "__metatable"); // L_: o "r" {c} {fqn} ... {?} k {} {mt} "__metatable"
855 ++ depth_; 774 lua_rawseti(L_, fqn, depth_); // L_: o "r" {c} {fqn} ... {?} k {} {mt}
856 lua_pushliteral(L_, "__metatable"); // o "r" {c} {fqn} ... {?} k {} {mt} "__metatable"
857 lua_rawseti(L_, fqn, depth_); // o "r" {c} {fqn} ... {?} k {} {mt}
858 shortest_ = discover_object_name_recur(L_, shortest_, depth_); 775 shortest_ = discover_object_name_recur(L_, shortest_, depth_);
859 lua_pushnil(L_); // o "r" {c} {fqn} ... {?} k {} {mt} nil 776 lua_pushnil(L_); // L_: o "r" {c} {fqn} ... {?} k {} {mt} nil
860 lua_rawseti(L_, fqn, depth_); // o "r" {c} {fqn} ... {?} k {} {mt} 777 lua_rawseti(L_, fqn, depth_); // L_: o "r" {c} {fqn} ... {?} k {} {mt}
861 -- depth_; 778 --depth_;
862 } 779 }
863 lua_pop(L_, 1); // o "r" {c} {fqn} ... {?} k {} 780 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?} k {}
864 } 781 }
865 STACK_CHECK(L_, 2); 782 STACK_CHECK(L_, 2);
866 break; 783 break;
867 784
868 case LUA_TTHREAD: // o "r" {c} {fqn} ... {?} k T 785 case LUA_TTHREAD: // L_: o "r" {c} {fqn} ... {?} k T
869 // TODO: explore the thread's stack frame looking for our culprit? 786 // TODO: explore the thread's stack frame looking for our culprit?
870 break; 787 break;
871 788
872 case LUA_TUSERDATA: // o "r" {c} {fqn} ... {?} k U 789 case LUA_TUSERDATA: // L_: o "r" {c} {fqn} ... {?} k U
873 STACK_CHECK(L_, 2); 790 STACK_CHECK(L_, 2);
874 // search in the object's metatable (some modules are built that way) 791 // search in the object's metatable (some modules are built that way)
875 if (lua_getmetatable(L_, -1)) // o "r" {c} {fqn} ... {?} k U {mt} 792 if (lua_getmetatable(L_, -1)) { // L_: o "r" {c} {fqn} ... {?} k U {mt}
876 { 793 if (lua_istable(L_, -1)) {
877 if (lua_istable(L_, -1)) 794 ++depth_;
878 { 795 lua_pushliteral(L_, "__metatable"); // L_: o "r" {c} {fqn} ... {?} k U {mt} "__metatable"
879 ++ depth_; 796 lua_rawseti(L_, fqn, depth_); // L_: o "r" {c} {fqn} ... {?} k U {mt}
880 lua_pushliteral(L_, "__metatable"); // o "r" {c} {fqn} ... {?} k U {mt} "__metatable"
881 lua_rawseti(L_, fqn, depth_); // o "r" {c} {fqn} ... {?} k U {mt}
882 shortest_ = discover_object_name_recur(L_, shortest_, depth_); 797 shortest_ = discover_object_name_recur(L_, shortest_, depth_);
883 lua_pushnil(L_); // o "r" {c} {fqn} ... {?} k U {mt} nil 798 lua_pushnil(L_); // L_: o "r" {c} {fqn} ... {?} k U {mt} nil
884 lua_rawseti(L_, fqn, depth_); // o "r" {c} {fqn} ... {?} k U {mt} 799 lua_rawseti(L_, fqn, depth_); // L_: o "r" {c} {fqn} ... {?} k U {mt}
885 -- depth_; 800 --depth_;
886 } 801 }
887 lua_pop(L_, 1); // o "r" {c} {fqn} ... {?} k U 802 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?} k U
888 } 803 }
889 STACK_CHECK(L_, 2); 804 STACK_CHECK(L_, 2);
890 // search in the object's uservalues 805 // search in the object's uservalues
891 { 806 {
892 int uvi = 1; 807 int uvi = 1;
893 while (lua_getiuservalue(L_, -1, uvi) != LUA_TNONE) // o "r" {c} {fqn} ... {?} k U {u} 808 while (lua_getiuservalue(L_, -1, uvi) != LUA_TNONE) { // L_: o "r" {c} {fqn} ... {?} k U {u}
894 { 809 if (lua_istable(L_, -1)) { // if it is a table, look inside
895 if (lua_istable(L_, -1)) // if it is a table, look inside 810 ++depth_;
896 { 811 lua_pushliteral(L_, "uservalue"); // L_: o "r" {c} {fqn} ... {?} k v {u} "uservalue"
897 ++ depth_; 812 lua_rawseti(L_, fqn, depth_); // L_: o "r" {c} {fqn} ... {?} k v {u}
898 lua_pushliteral(L_, "uservalue"); // o "r" {c} {fqn} ... {?} k v {u} "uservalue"
899 lua_rawseti(L_, fqn, depth_); // o "r" {c} {fqn} ... {?} k v {u}
900 shortest_ = discover_object_name_recur(L_, shortest_, depth_); 813 shortest_ = discover_object_name_recur(L_, shortest_, depth_);
901 lua_pushnil(L_); // o "r" {c} {fqn} ... {?} k v {u} nil 814 lua_pushnil(L_); // L_: o "r" {c} {fqn} ... {?} k v {u} nil
902 lua_rawseti(L_, fqn, depth_); // o "r" {c} {fqn} ... {?} k v {u} 815 lua_rawseti(L_, fqn, depth_); // L_: o "r" {c} {fqn} ... {?} k v {u}
903 -- depth_; 816 --depth_;
904 } 817 }
905 lua_pop(L_, 1); // o "r" {c} {fqn} ... {?} k U 818 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?} k U
906 ++ uvi; 819 ++uvi;
907 } 820 }
908 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now 821 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now
909 lua_pop(L_, 1); // o "r" {c} {fqn} ... {?} k U 822 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?} k U
910 } 823 }
911 STACK_CHECK(L_, 2); 824 STACK_CHECK(L_, 2);
912 break; 825 break;
913 } 826 }
914 // make ready for next iteration 827 // make ready for next iteration
915 lua_pop(L_, 1); // o "r" {c} {fqn} ... {?} k 828 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?} k
916 // remove name from fqn stack 829 // remove name from fqn stack
917 lua_pushnil(L_); // o "r" {c} {fqn} ... {?} k nil 830 lua_pushnil(L_); // L_: o "r" {c} {fqn} ... {?} k nil
918 lua_rawseti(L_, fqn, depth_); // o "r" {c} {fqn} ... {?} k 831 lua_rawseti(L_, fqn, depth_); // L_: o "r" {c} {fqn} ... {?} k
919 STACK_CHECK(L_, 1); 832 STACK_CHECK(L_, 1);
920 -- depth_; 833 --depth_;
921 } // o "r" {c} {fqn} ... {?} 834 } // L_: o "r" {c} {fqn} ... {?}
922 STACK_CHECK(L_, 0); 835 STACK_CHECK(L_, 0);
923 // remove the visited table from the cache, in case a shorter path to the searched object exists 836 // remove the visited table from the cache, in case a shorter path to the searched object exists
924 lua_pushvalue(L_, -1); // o "r" {c} {fqn} ... {?} {?} 837 lua_pushvalue(L_, -1); // L_: o "r" {c} {fqn} ... {?} {?}
925 lua_pushnil(L_); // o "r" {c} {fqn} ... {?} {?} nil 838 lua_pushnil(L_); // L_: o "r" {c} {fqn} ... {?} {?} nil
926 lua_rawset(L_, cache); // o "r" {c} {fqn} ... {?} 839 lua_rawset(L_, cache); // L_: o "r" {c} {fqn} ... {?}
927 STACK_CHECK(L_, 0); 840 STACK_CHECK(L_, 0);
928 return shortest_; 841 return shortest_;
929} 842}
930 843
931// ################################################################################################# 844// #################################################################################################
932 845
933/* 846// "type", "name" = lanes.nameof( o)
934 * "type", "name" = lanes.nameof( o) 847int luaG_nameof(lua_State* L_)
935 */
936int luaG_nameof( lua_State* L_)
937{ 848{
938 int const what{ lua_gettop(L_) }; 849 int const what{ lua_gettop(L_) };
939 if (what > 1) 850 if (what > 1) {
940 { 851 raise_luaL_argerror(L_, what, "too many arguments.");
941 raise_luaL_argerror( L_, what, "too many arguments.");
942 } 852 }
943 853
944 // nil, boolean, light userdata, number and string aren't identifiable 854 // nil, boolean, light userdata, number and string aren't identifiable
945 if (lua_type( L_, 1) < LUA_TTABLE) 855 if (lua_type(L_, 1) < LUA_TTABLE) {
946 { 856 lua_pushstring(L_, luaL_typename(L_, 1)); // L_: o "type"
947 lua_pushstring( L_, luaL_typename( L_, 1)); // o "type" 857 lua_insert(L_, -2); // L_: "type" o
948 lua_insert( L_, -2); // "type" o
949 return 2; 858 return 2;
950 } 859 }
951 860
952 STACK_GROW( L_, 4); 861 STACK_GROW(L_, 4);
953 STACK_CHECK_START_REL(L_, 0); 862 STACK_CHECK_START_REL(L_, 0);
954 // this slot will contain the shortest name we found when we are done 863 // this slot will contain the shortest name we found when we are done
955 lua_pushnil( L_); // o nil 864 lua_pushnil(L_); // L_: o nil
956 // push a cache that will contain all already visited tables 865 // push a cache that will contain all already visited tables
957 lua_newtable( L_); // o nil {c} 866 lua_newtable(L_); // o nil {c}
958 // push a table whose contents are strings that, when concatenated, produce unique name 867 // push a table whose contents are strings that, when concatenated, produce unique name
959 lua_newtable( L_); // o nil {c} {fqn} 868 lua_newtable(L_); // L_: o nil {c} {fqn}
960 lua_pushliteral( L_, "_G"); // o nil {c} {fqn} "_G" 869 lua_pushliteral(L_, "_G"); // L_: o nil {c} {fqn} "_G"
961 lua_rawseti( L_, -2, 1); // o nil {c} {fqn} 870 lua_rawseti(L_, -2, 1); // L_: o nil {c} {fqn}
962 // this is where we start the search 871 // this is where we start the search
963 lua_pushglobaltable( L_); // o nil {c} {fqn} _G 872 lua_pushglobaltable(L_); // L_: o nil {c} {fqn} _G
964 (void) discover_object_name_recur( L_, 6666, 1); 873 std::ignore = discover_object_name_recur(L_, 6666, 1);
965 if (lua_isnil( L_, 2)) // try again with registry, just in case... 874 if (lua_isnil(L_, 2)) { // try again with registry, just in case...
966 { 875 lua_pop(L_, 1); // L_: o nil {c} {fqn}
967 lua_pop( L_, 1); // o nil {c} {fqn} 876 lua_pushliteral(L_, "_R"); // L_: o nil {c} {fqn} "_R"
968 lua_pushliteral( L_, "_R"); // o nil {c} {fqn} "_R" 877 lua_rawseti(L_, -2, 1); // L_: o nil {c} {fqn}
969 lua_rawseti( L_, -2, 1); // o nil {c} {fqn} 878 lua_pushvalue(L_, LUA_REGISTRYINDEX); // L_: o nil {c} {fqn} _R
970 lua_pushvalue( L_, LUA_REGISTRYINDEX); // o nil {c} {fqn} _R 879 (void) discover_object_name_recur(L_, 6666, 1);
971 (void) discover_object_name_recur( L_, 6666, 1); 880 }
972 } 881 lua_pop(L_, 3); // L_: o "result"
973 lua_pop( L_, 3); // o "result" 882 STACK_CHECK(L_, 1);
974 STACK_CHECK( L_, 1); 883 lua_pushstring(L_, luaL_typename(L_, 1)); // L_: o "result" "type"
975 lua_pushstring( L_, luaL_typename( L_, 1)); // o "result" "type" 884 lua_replace(L_, -3); // L_: "type" "result"
976 lua_replace( L_, -3); // "type" "result"
977 return 2; 885 return 2;
978} 886}
979 887
980// ################################################################################################# 888// #################################################################################################
981 889
982/* 890// Push a looked-up native/LuaJIT function.
983 * Push a looked-up native/LuaJIT function.
984 */
985void InterCopyContext::lookup_native_func() const 891void InterCopyContext::lookup_native_func() const
986{ 892{
987 // get the name of the function we want to send 893 // get the name of the function we want to send
988 size_t len; 894 size_t len;
989 char const* fqn = find_lookup_name(L1, L1_i, mode, name, &len); 895 char const* fqn = find_lookup_name(L1, L1_i, mode, name, &len);
990 // push the equivalent function in the destination's stack, retrieved from the lookup table 896 // push the equivalent function in the destination's stack, retrieved from the lookup table
991 STACK_CHECK_START_REL(L2, 0); // L1 // L2 897 STACK_CHECK_START_REL(L2, 0);
992 STACK_GROW(L2, 3); // up to 3 slots are necessary on error 898 STACK_GROW(L2, 3); // up to 3 slots are necessary on error
993 switch (mode) 899 switch (mode) {
994 { 900 default: // shouldn't happen, in theory...
995 default: // shouldn't happen, in theory...
996 raise_luaL_error(L1, "internal error: unknown lookup mode"); 901 raise_luaL_error(L1, "internal error: unknown lookup mode");
997 break; 902 break;
998 903
999 case LookupMode::ToKeeper: 904 case LookupMode::ToKeeper:
1000 // push a sentinel closure that holds the lookup name as upvalue 905 // push a sentinel closure that holds the lookup name as upvalue
1001 lua_pushlstring(L2, fqn, len); // "f.q.n" 906 lua_pushlstring(L2, fqn, len); // L1: ... f ... L2: "f.q.n"
1002 lua_pushcclosure(L2, func_lookup_sentinel, 1); // f 907 lua_pushcclosure(L2, func_lookup_sentinel, 1); // L1: ... f ... L2: f
1003 break; 908 break;
1004 909
1005 case LookupMode::LaneBody: 910 case LookupMode::LaneBody:
1006 case LookupMode::FromKeeper: 911 case LookupMode::FromKeeper:
1007 kLookupRegKey.pushValue(L2); // {} 912 kLookupRegKey.pushValue(L2); // L1: ... f ... L2: {}
1008 STACK_CHECK(L2, 1); 913 STACK_CHECK(L2, 1);
1009 LUA_ASSERT(L1, lua_istable(L2, -1)); 914 LUA_ASSERT(L1, lua_istable(L2, -1));
1010 lua_pushlstring(L2, fqn, len); // {} "f.q.n" 915 lua_pushlstring(L2, fqn, len); // L1: ... f ... L2: {} "f.q.n"
1011 lua_rawget(L2, -2); // {} f 916 lua_rawget(L2, -2); // L1: ... f ... L2: {} f
1012 // nil means we don't know how to transfer stuff: user should do something 917 // nil means we don't know how to transfer stuff: user should do something
1013 // anything other than function or table should not happen! 918 // anything other than function or table should not happen!
1014 if (!lua_isfunction( L2, -1) && !lua_istable( L2, -1)) 919 if (!lua_isfunction(L2, -1) && !lua_istable(L2, -1)) {
1015 { 920 char const *from, *to;
1016 char const* from, * to; 921 lua_getglobal(L1, "decoda_name"); // L1: ... f ... decoda_name
1017 lua_getglobal(L1, "decoda_name"); // ... f ... decoda_name
1018 from = lua_tostring(L1, -1); 922 from = lua_tostring(L1, -1);
1019 lua_pop(L1, 1); // ... f ... 923 lua_pop(L1, 1); // L1: ... f ...
1020 lua_getglobal(L2, "decoda_name"); // {} f decoda_name 924 lua_getglobal(L2, "decoda_name"); // L1: ... f ... L2: {} f decoda_name
1021 to = lua_tostring(L2, -1); 925 to = lua_tostring(L2, -1);
1022 lua_pop(L2, 1); // {} f 926 lua_pop(L2, 1); // L2: {} f
1023 // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error 927 // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error
1024 raise_luaL_error( 928 raise_luaL_error(
1025 (mode == LookupMode::FromKeeper) ? L2 : L1 929 (mode == LookupMode::FromKeeper) ? L2 : L1
@@ -1031,38 +935,31 @@ void InterCopyContext::lookup_native_func() const
1031 ); 935 );
1032 return; 936 return;
1033 } 937 }
1034 lua_remove(L2, -2); // f 938 lua_remove(L2, -2); // L2: f
1035 break; 939 break;
1036 940
1037 /* keep it in case I need it someday, who knows... 941 /* keep it in case I need it someday, who knows...
1038 case LookupMode::RawFunctions: 942 case LookupMode::RawFunctions:
1039 { 943 {
1040 int n; 944 int n;
1041 char const* upname; 945 char const* upname;
1042 lua_CFunction f = lua_tocfunction( L, i); 946 lua_CFunction f = lua_tocfunction( L, i);
1043 // copy upvalues 947 // copy upvalues
1044 for (n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != nullptr; ++ n) 948 for (n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != nullptr; ++ n) {
1045 { 949 luaG_inter_move( U, L, L2, 1, mode_); // L2: [up[,up ...]]
1046 luaG_inter_move( U, L, L2, 1, mode_); // [up[,up ...]]
1047 }
1048 lua_pushcclosure( L2, f, n); //
1049 } 950 }
1050 break; 951 lua_pushcclosure( L2, f, n); // L2:
1051 */
1052 } 952 }
1053 STACK_CHECK( L2, 1); 953 break;
954 */
955 }
956 STACK_CHECK(L2, 1);
1054} 957}
1055 958
1056// ################################################################################################# 959// #################################################################################################
1057 960
1058/*
1059 * Copy a function over, which has not been found in the cache.
1060 * L2 has the cache key for this function at the top of the stack
1061*/
1062
1063#if USE_DEBUG_SPEW() 961#if USE_DEBUG_SPEW()
1064static char const* lua_type_names[] = 962static char const* lua_type_names[] = {
1065{
1066 "LUA_TNIL" 963 "LUA_TNIL"
1067 , "LUA_TBOOLEAN" 964 , "LUA_TBOOLEAN"
1068 , "LUA_TLIGHTUSERDATA" 965 , "LUA_TLIGHTUSERDATA"
@@ -1075,9 +972,8 @@ static char const* lua_type_names[] =
1075 , "<LUA_NUMTAGS>" // not really a type 972 , "<LUA_NUMTAGS>" // not really a type
1076 , "LUA_TJITCDATA" // LuaJIT specific 973 , "LUA_TJITCDATA" // LuaJIT specific
1077}; 974};
1078static char const* vt_names[] = 975static char const* vt_names[] = {
1079{ 976 "VT::NORMAL"
1080 "VT::NORMAL"
1081 , "VT::KEY" 977 , "VT::KEY"
1082 , "VT::METATABLE" 978 , "VT::METATABLE"
1083}; 979};
@@ -1092,82 +988,78 @@ static char const* vt_names[] =
1092[[nodiscard]] static int buf_writer(lua_State* L_, void const* b, size_t size, void* ud) 988[[nodiscard]] static int buf_writer(lua_State* L_, void const* b, size_t size, void* ud)
1093{ 989{
1094 luaL_Buffer* B = (luaL_Buffer*) ud; 990 luaL_Buffer* B = (luaL_Buffer*) ud;
1095 if (!B->L) 991 if (!B->L) {
1096 { 992 luaL_buffinit(L_, B);
1097 luaL_buffinit( L_, B);
1098 } 993 }
1099 luaL_addlstring( B, (char const*) b, size); 994 luaL_addlstring(B, (char const*) b, size);
1100 return 0; 995 return 0;
1101} 996}
1102 997
1103// ################################################################################################# 998// #################################################################################################
1104 999
1000// Copy a function over, which has not been found in the cache.
1001// L2 has the cache key for this function at the top of the stack
1105void InterCopyContext::copy_func() const 1002void InterCopyContext::copy_func() const
1106{ 1003{
1107 LUA_ASSERT(L1, L2_cache_i != 0); // ... {cache} ... p 1004 LUA_ASSERT(L1, L2_cache_i != 0); // L2: ... {cache} ... p
1108 STACK_GROW(L1, 2); 1005 STACK_GROW(L1, 2);
1109 STACK_CHECK_START_REL(L1, 0); 1006 STACK_CHECK_START_REL(L1, 0);
1110 1007
1111
1112 // 'lua_dump()' needs the function at top of stack 1008 // 'lua_dump()' needs the function at top of stack
1113 // if already on top of the stack, no need to push again 1009 // if already on top of the stack, no need to push again
1114 bool const needToPush{ L1_i != lua_gettop(L1) }; 1010 bool const needToPush{ L1_i != lua_gettop(L1) };
1115 if (needToPush) 1011 if (needToPush) {
1116 { 1012 lua_pushvalue(L1, L1_i); // L1: ... f
1117 lua_pushvalue(L1, L1_i); // ... f
1118 } 1013 }
1119 1014
1120 // 1015 //
1121 // "value returned is the error code returned by the last call 1016 // "value returned is the error code returned by the last call
1122 // to the writer" (and we only return 0) 1017 // to the writer" (and we only return 0)
1123 // not sure this could ever fail but for memory shortage reasons 1018 // not sure this could ever fail but for memory shortage reasons
1124 // last parameter is Lua 5.4-specific (no stripping) 1019 // last parameter is Lua 5.4-specific (no stripping)
1125 luaL_Buffer B; 1020 luaL_Buffer B;
1126 B.L = nullptr; 1021 B.L = nullptr;
1127 if (lua504_dump(L1, buf_writer, &B, 0) != 0) 1022 if (lua504_dump(L1, buf_writer, &B, 0) != 0) {
1128 {
1129 raise_luaL_error(L1, "internal error: function dump failed."); 1023 raise_luaL_error(L1, "internal error: function dump failed.");
1130 } 1024 }
1131 1025
1132 // pushes dumped string on 'L1' 1026 // pushes dumped string on 'L1'
1133 luaL_pushresult(&B); // ... f b 1027 luaL_pushresult(&B); // L1: ... f b
1134 1028
1135 // if not pushed, no need to pop 1029 // if not pushed, no need to pop
1136 if (needToPush) 1030 if (needToPush) {
1137 { 1031 lua_remove(L1, -2); // L1: ... b
1138 lua_remove(L1, -2); // ... b
1139 } 1032 }
1140 1033
1141 // transfer the bytecode, then the upvalues, to create a similar closure 1034 // transfer the bytecode, then the upvalues, to create a similar closure
1142 { 1035 {
1143 char const* name = nullptr; 1036 char const* name = nullptr;
1144 1037#define LOG_FUNC_INFO 0
1145 #if LOG_FUNC_INFO 1038#if LOG_FUNC_INFO
1146 // "To get information about a function you push it onto the 1039 // "To get information about a function you push it onto the
1147 // stack and start the what string with the character '>'." 1040 // stack and start the what string with the character '>'."
1148 // 1041 //
1149 { 1042 {
1150 lua_Debug ar; 1043 lua_Debug ar;
1151 lua_pushvalue( L, i); // ... b f 1044 lua_pushvalue(L1, L1_i); // L1: ... b f
1152 // fills 'name' 'namewhat' and 'linedefined', pops function 1045 // fills 'name' 'namewhat' and 'linedefined', pops function
1153 lua_getinfo( L, ">nS", &ar); // ... b 1046 lua_getinfo(L1, ">nS", &ar); // L1: ... b
1154 name = ar.namewhat; 1047 name = ar.namewhat;
1155 fprintf( stderr, INDENT_BEGIN "FNAME: %s @ %d\n", i, s_indent, ar.short_src, ar.linedefined); // just gives nullptr 1048 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "FNAME: %s @ %d" INDENT_END(U), ar.short_src, ar.linedefined)); // just gives nullptr
1156 } 1049 }
1157 #endif // LOG_FUNC_INFO 1050#endif // LOG_FUNC_INFO
1158 { 1051 {
1159 size_t sz; 1052 size_t sz;
1160 char const* s = lua_tolstring(L1, -1, &sz); // ... b 1053 char const* s = lua_tolstring(L1, -1, &sz); // L1: ... b
1161 LUA_ASSERT(L1, s && sz); 1054 LUA_ASSERT(L1, s && sz);
1162 STACK_GROW(L2, 2); 1055 STACK_GROW(L2, 2);
1163 // Note: Line numbers seem to be taken precisely from the 1056 // Note: Line numbers seem to be taken precisely from the
1164 // original function. 'name' is not used since the chunk 1057 // original function. 'name' is not used since the chunk
1165 // is precompiled (it seems...). 1058 // is precompiled (it seems...).
1166 // 1059 //
1167 // TBD: Can we get the function's original name through, as well? 1060 // TBD: Can we get the function's original name through, as well?
1168 // 1061 //
1169 if (luaL_loadbuffer(L2, s, sz, name) != 0) // ... {cache} ... p function 1062 if (luaL_loadbuffer(L2, s, sz, name) != 0) { // L2: ... {cache} ... p function
1170 {
1171 // chunk is precompiled so only LUA_ERRMEM can happen 1063 // chunk is precompiled so only LUA_ERRMEM can happen
1172 // "Otherwise, it pushes an error message" 1064 // "Otherwise, it pushes an error message"
1173 // 1065 //
@@ -1175,22 +1067,22 @@ void InterCopyContext::copy_func() const
1175 raise_luaL_error(L1, "%s: %s", name, lua_tostring(L2, -1)); 1067 raise_luaL_error(L1, "%s: %s", name, lua_tostring(L2, -1));
1176 } 1068 }
1177 // remove the dumped string 1069 // remove the dumped string
1178 lua_pop(L1, 1); // ... 1070 lua_pop(L1, 1); // ...
1179 // now set the cache as soon as we can. 1071 // now set the cache as soon as we can.
1180 // this is necessary if one of the function's upvalues references it indirectly 1072 // this is necessary if one of the function's upvalues references it indirectly
1181 // we need to find it in the cache even if it isn't fully transfered yet 1073 // we need to find it in the cache even if it isn't fully transfered yet
1182 lua_insert(L2, -2); // ... {cache} ... function p 1074 lua_insert(L2, -2); // L2: ... {cache} ... function p
1183 lua_pushvalue(L2, -2); // ... {cache} ... function p function 1075 lua_pushvalue(L2, -2); // L2: ... {cache} ... function p function
1184 // cache[p] = function 1076 // cache[p] = function
1185 lua_rawset(L2, L2_cache_i); // ... {cache} ... function 1077 lua_rawset(L2, L2_cache_i); // L2: ... {cache} ... function
1186 } 1078 }
1187 STACK_CHECK(L1, 0); 1079 STACK_CHECK(L1, 0);
1188 1080
1189 /* push over any upvalues; references to this function will come from 1081 /* push over any upvalues; references to this function will come from
1190 * cache so we don't end up in eternal loop. 1082 * cache so we don't end up in eternal loop.
1191 * Lua5.2 and Lua5.3: one of the upvalues is _ENV, which we don't want to copy! 1083 * Lua5.2 and Lua5.3: one of the upvalues is _ENV, which we don't want to copy!
1192 * instead, the function shall have LUA_RIDX_GLOBALS taken in the destination state! 1084 * instead, the function shall have LUA_RIDX_GLOBALS taken in the destination state!
1193 */ 1085 */
1194 int n{ 0 }; 1086 int n{ 0 };
1195 { 1087 {
1196 InterCopyContext c{ U, L2, L1, L2_cache_i, {}, VT::NORMAL, mode, {} }; 1088 InterCopyContext c{ U, L2, L1, L2_cache_i, {}, VT::NORMAL, mode, {} };
@@ -1198,50 +1090,45 @@ void InterCopyContext::copy_func() const
1198 // Starting with Lua 5.2, each Lua function gets its environment as one of its upvalues (named LUA_ENV, aka "_ENV" by default) 1090 // Starting with Lua 5.2, each Lua function gets its environment as one of its upvalues (named LUA_ENV, aka "_ENV" by default)
1199 // Generally this is LUA_RIDX_GLOBALS, which we don't want to copy from the source to the destination state... 1091 // Generally this is LUA_RIDX_GLOBALS, which we don't want to copy from the source to the destination state...
1200 // -> if we encounter an upvalue equal to the global table in the source, bind it to the destination's global table 1092 // -> if we encounter an upvalue equal to the global table in the source, bind it to the destination's global table
1201 lua_pushglobaltable(L1); // ... _G 1093 lua_pushglobaltable(L1); // L1: ... _G
1202#endif // LUA_VERSION_NUM 1094#endif // LUA_VERSION_NUM
1203 for (n = 0; (c.name = lua_getupvalue(L1, L1_i, 1 + n)) != nullptr; ++n) 1095 for (n = 0; (c.name = lua_getupvalue(L1, L1_i, 1 + n)) != nullptr; ++n) { // L1: ... _G up[n]
1204 { // ... _G up[n] 1096 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "UPNAME[%d]: %s -> " INDENT_END(U), n, c.name));
1205 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "UPNAME[%d]: %s -> " INDENT_END, n, c.name));
1206#if LUA_VERSION_NUM >= 502 1097#if LUA_VERSION_NUM >= 502
1207 if (lua_rawequal(L1, -1, -2)) // is the upvalue equal to the global table? 1098 if (lua_rawequal(L1, -1, -2)) { // is the upvalue equal to the global table?
1208 {
1209 DEBUGSPEW_CODE(fprintf(stderr, "pushing destination global scope\n")); 1099 DEBUGSPEW_CODE(fprintf(stderr, "pushing destination global scope\n"));
1210 lua_pushglobaltable(L2); // ... {cache} ... function <upvalues> 1100 lua_pushglobaltable(L2); // L2: ... {cache} ... function <upvalues>
1211 } 1101 } else
1212 else
1213#endif // LUA_VERSION_NUM 1102#endif // LUA_VERSION_NUM
1214 { 1103 {
1215 DEBUGSPEW_CODE(fprintf(stderr, "copying value\n")); 1104 DEBUGSPEW_CODE(fprintf(stderr, "copying value\n"));
1216 c.L1_i = SourceIndex{ lua_gettop(L1) }; 1105 c.L1_i = SourceIndex{ lua_gettop(L1) };
1217 if (!c.inter_copy_one()) // ... {cache} ... function <upvalues> 1106 if (!c.inter_copy_one()) { // L2: ... {cache} ... function <upvalues>
1218 {
1219 raise_luaL_error(L1, "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); 1107 raise_luaL_error(L1, "Cannot copy upvalue type '%s'", luaL_typename(L1, -1));
1220 } 1108 }
1221 } 1109 }
1222 lua_pop(L1, 1); // ... _G 1110 lua_pop(L1, 1); // L1: ... _G
1223 } 1111 }
1224#if LUA_VERSION_NUM >= 502 1112#if LUA_VERSION_NUM >= 502
1225 lua_pop(L1, 1); // ... 1113 lua_pop(L1, 1); // L1: ...
1226#endif // LUA_VERSION_NUM 1114#endif // LUA_VERSION_NUM
1227 } 1115 }
1228 // L2: function + 'n' upvalues (>=0) 1116 // L2: ... {cache} ... function + 'n' upvalues (>=0)
1229 1117
1230 STACK_CHECK(L1, 0); 1118 STACK_CHECK(L1, 0);
1231 1119
1232 // Set upvalues (originally set to 'nil' by 'lua_load') 1120 // Set upvalues (originally set to 'nil' by 'lua_load')
1233 { 1121 {
1234 for (int const func_index{ lua_gettop(L2) - n }; n > 0; --n) 1122 for (int const func_index{ lua_gettop(L2) - n }; n > 0; --n) {
1235 { 1123 char const* rc{ lua_setupvalue(L2, func_index, n) }; // L2: ... {cache} ... function
1236 char const* rc{ lua_setupvalue(L2, func_index, n) }; // ... {cache} ... function
1237 // 1124 //
1238 // "assigns the value at the top of the stack to the upvalue and returns its name. 1125 // "assigns the value at the top of the stack to the upvalue and returns its name.
1239 // It also pops the value from the stack." 1126 // It also pops the value from the stack."
1240 1127
1241 LUA_ASSERT(L1, rc); // not having enough slots? 1128 LUA_ASSERT(L1, rc); // not having enough slots?
1242 } 1129 }
1243 // once all upvalues have been set we are left 1130 // once all upvalues have been set we are left
1244 // with the function at the top of the stack // ... {cache} ... function 1131 // with the function at the top of the stack // L2: ... {cache} ... function
1245 } 1132 }
1246 } 1133 }
1247 STACK_CHECK(L1, 0); 1134 STACK_CHECK(L1, 0);
@@ -1249,16 +1136,12 @@ void InterCopyContext::copy_func() const
1249 1136
1250// ################################################################################################# 1137// #################################################################################################
1251 1138
1252/* 1139// Check if we've already copied the same function from 'L1', and reuse the old copy.
1253 * Check if we've already copied the same function from 'L1', and reuse the old copy. 1140// Always pushes a function to 'L2'.
1254 *
1255 * Always pushes a function to 'L2'.
1256 */
1257void InterCopyContext::copy_cached_func() const 1141void InterCopyContext::copy_cached_func() const
1258{ 1142{
1259 FuncSubType const funcSubType{ luaG_getfuncsubtype(L1, L1_i) }; 1143 FuncSubType const funcSubType{ luaG_getfuncsubtype(L1, L1_i) };
1260 if (funcSubType == FuncSubType::Bytecode) 1144 if (funcSubType == FuncSubType::Bytecode) {
1261 {
1262 void* const aspointer = const_cast<void*>(lua_topointer(L1, L1_i)); 1145 void* const aspointer = const_cast<void*>(lua_topointer(L1, L1_i));
1263 // TBD: Merge this and same code for tables 1146 // TBD: Merge this and same code for tables
1264 LUA_ASSERT(L1, L2_cache_i != 0); 1147 LUA_ASSERT(L1, L2_cache_i != 0);
@@ -1274,33 +1157,28 @@ void InterCopyContext::copy_cached_func() const
1274 // 1157 //
1275 1158
1276 // push a light userdata uniquely representing the function 1159 // push a light userdata uniquely representing the function
1277 lua_pushlightuserdata(L2, aspointer); // ... {cache} ... p 1160 lua_pushlightuserdata(L2, aspointer); // L2: ... {cache} ... p
1278 1161
1279 //fprintf( stderr, "<< ID: %s >>\n", lua_tostring( L2, -1)); 1162 // fprintf( stderr, "<< ID: %s >>\n", lua_tostring( L2, -1));
1280 1163
1281 lua_pushvalue(L2, -1); // ... {cache} ... p p 1164 lua_pushvalue(L2, -1); // L2: ... {cache} ... p p
1282 lua_rawget(L2, L2_cache_i); // ... {cache} ... p function|nil|true 1165 lua_rawget(L2, L2_cache_i); // L2: ... {cache} ... p function|nil|true
1283 1166
1284 if (lua_isnil(L2, -1)) // function is unknown 1167 if (lua_isnil(L2, -1)) { // function is unknown
1285 { 1168 lua_pop(L2, 1); // L2: ... {cache} ... p
1286 lua_pop(L2, 1); // ... {cache} ... p
1287 1169
1288 // Set to 'true' for the duration of creation; need to find self-references 1170 // Set to 'true' for the duration of creation; need to find self-references
1289 // via upvalues 1171 // via upvalues
1290 // 1172 //
1291 // pushes a copy of the func, stores a reference in the cache 1173 // pushes a copy of the func, stores a reference in the cache
1292 copy_func(); // ... {cache} ... function 1174 copy_func(); // L2: ... {cache} ... function
1293 } 1175 } else { // found function in the cache
1294 else // found function in the cache 1176 lua_remove(L2, -2); // L2: ... {cache} ... function
1295 {
1296 lua_remove(L2, -2); // ... {cache} ... function
1297 } 1177 }
1298 STACK_CHECK(L2, 1); 1178 STACK_CHECK(L2, 1);
1299 LUA_ASSERT(L1, lua_isfunction(L2, -1)); 1179 LUA_ASSERT(L1, lua_isfunction(L2, -1));
1300 } 1180 } else { // function is native/LuaJIT: no need to cache
1301 else // function is native/LuaJIT: no need to cache 1181 lookup_native_func(); // L2: ... {cache} ... function
1302 {
1303 lookup_native_func(); // ... {cache} ... function
1304 // if the function was in fact a lookup sentinel, we can either get a function or a table here 1182 // if the function was in fact a lookup sentinel, we can either get a function or a table here
1305 LUA_ASSERT(L1, lua_isfunction(L2, -1) || lua_istable(L2, -1)); 1183 LUA_ASSERT(L1, lua_isfunction(L2, -1) || lua_istable(L2, -1));
1306 } 1184 }
@@ -1311,8 +1189,7 @@ void InterCopyContext::copy_cached_func() const
1311[[nodiscard]] bool InterCopyContext::push_cached_metatable() const 1189[[nodiscard]] bool InterCopyContext::push_cached_metatable() const
1312{ 1190{
1313 STACK_CHECK_START_REL(L1, 0); 1191 STACK_CHECK_START_REL(L1, 0);
1314 if (!lua_getmetatable(L1, L1_i)) // ... mt 1192 if (!lua_getmetatable(L1, L1_i)) { // L1: ... mt
1315 {
1316 STACK_CHECK(L1, 0); 1193 STACK_CHECK(L1, 0);
1317 return false; 1194 return false;
1318 } 1195 }
@@ -1323,35 +1200,33 @@ void InterCopyContext::copy_cached_func() const
1323 STACK_CHECK_START_REL(L2, 0); 1200 STACK_CHECK_START_REL(L2, 0);
1324 STACK_GROW(L2, 4); 1201 STACK_GROW(L2, 4);
1325 // do we already know this metatable? 1202 // do we already know this metatable?
1326 push_registry_subtable(L2, kMtIdRegKey); // _R[kMtIdRegKey] 1203 push_registry_subtable(L2, kMtIdRegKey); // L2: _R[kMtIdRegKey]
1327 lua_pushinteger(L2, mt_id); // _R[kMtIdRegKey] id 1204 lua_pushinteger(L2, mt_id); // L2: _R[kMtIdRegKey] id
1328 lua_rawget(L2, -2); // _R[kMtIdRegKey] mt|nil 1205 lua_rawget(L2, -2); // L2: _R[kMtIdRegKey] mt|nil
1329 STACK_CHECK(L2, 2); 1206 STACK_CHECK(L2, 2);
1330 1207
1331 if (lua_isnil(L2, -1)) 1208 if (lua_isnil(L2, -1)) { // L2 did not know the metatable
1332 { // L2 did not know the metatable 1209 lua_pop(L2, 1); // L2: _R[kMtIdRegKey]
1333 lua_pop(L2, 1); // _R[kMtIdRegKey]
1334 InterCopyContext const c{ U, L2, L1, L2_cache_i, SourceIndex{ lua_gettop(L1) }, VT::METATABLE, mode, name }; 1210 InterCopyContext const c{ U, L2, L1, L2_cache_i, SourceIndex{ lua_gettop(L1) }, VT::METATABLE, mode, name };
1335 if (!c.inter_copy_one()) // _R[kMtIdRegKey] mt? 1211 if (!c.inter_copy_one()) { // L2: _R[kMtIdRegKey] mt?
1336 {
1337 raise_luaL_error(L1, "Error copying a metatable"); 1212 raise_luaL_error(L1, "Error copying a metatable");
1338 } 1213 }
1339 1214
1340 STACK_CHECK(L2, 2); // _R[kMtIdRegKey] mt 1215 STACK_CHECK(L2, 2); // L2: _R[kMtIdRegKey] mt
1341 // mt_id -> metatable 1216 // mt_id -> metatable
1342 lua_pushinteger(L2, mt_id); // _R[kMtIdRegKey] mt id 1217 lua_pushinteger(L2, mt_id); // L2: _R[kMtIdRegKey] mt id
1343 lua_pushvalue(L2, -2); // _R[kMtIdRegKey] mt id mt 1218 lua_pushvalue(L2, -2); // L2: _R[kMtIdRegKey] mt id mt
1344 lua_rawset(L2, -4); // _R[kMtIdRegKey] mt 1219 lua_rawset(L2, -4); // L2: _R[kMtIdRegKey] mt
1345 1220
1346 // metatable -> mt_id 1221 // metatable -> mt_id
1347 lua_pushvalue(L2, -1); // _R[kMtIdRegKey] mt mt 1222 lua_pushvalue(L2, -1); // L2: _R[kMtIdRegKey] mt mt
1348 lua_pushinteger(L2, mt_id); // _R[kMtIdRegKey] mt mt id 1223 lua_pushinteger(L2, mt_id); // L2: _R[kMtIdRegKey] mt mt id
1349 lua_rawset(L2, -4); // _R[kMtIdRegKey] mt 1224 lua_rawset(L2, -4); // L2: _R[kMtIdRegKey] mt
1350 STACK_CHECK(L2, 2); 1225 STACK_CHECK(L2, 2);
1351 } 1226 }
1352 lua_remove(L2, -2); // mt 1227 lua_remove(L2, -2); // L2: mt
1353 1228
1354 lua_pop(L1, 1); // ... 1229 lua_pop(L1, 1); // L1: ...
1355 STACK_CHECK(L2, 1); 1230 STACK_CHECK(L2, 1);
1356 STACK_CHECK(L1, 0); 1231 STACK_CHECK(L1, 0);
1357 return true; 1232 return true;
@@ -1366,49 +1241,40 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1366 1241
1367 // For the key, only basic key types are copied over. others ignored 1242 // For the key, only basic key types are copied over. others ignored
1368 InterCopyContext c{ U, L2, L1, L2_cache_i, key_i, VT::KEY, mode, name }; 1243 InterCopyContext c{ U, L2, L1, L2_cache_i, key_i, VT::KEY, mode, name };
1369 if (!c.inter_copy_one()) 1244 if (!c.inter_copy_one()) {
1370 {
1371 return; 1245 return;
1372 // we could raise an error instead of ignoring the table entry, like so: 1246 // we could raise an error instead of ignoring the table entry, like so:
1373 //raise_luaL_error(L1, "Unable to copy %s key '%s' because of value is of type '%s'", (vt == VT::NORMAL) ? "table" : "metatable", name, luaL_typename(L1, key_i)); 1247 // raise_luaL_error(L1, "Unable to copy %s key '%s' because of value is of type '%s'", (vt == VT::NORMAL) ? "table" : "metatable", name, luaL_typename(L1, key_i));
1374 // maybe offer this possibility as a global configuration option, or a linda setting, or as a parameter of the call causing the transfer? 1248 // maybe offer this possibility as a global configuration option, or a linda setting, or as a parameter of the call causing the transfer?
1375 } 1249 }
1376 1250
1377 char* valPath{ nullptr }; 1251 char* valPath{ nullptr };
1378 if (U->verboseErrors) 1252 if (U->verboseErrors) {
1379 {
1380 // for debug purposes, let's try to build a useful name 1253 // for debug purposes, let's try to build a useful name
1381 if (lua_type(L1, key_i) == LUA_TSTRING) 1254 if (lua_type(L1, key_i) == LUA_TSTRING) {
1382 {
1383 char const* key{ lua_tostring(L1, key_i) }; 1255 char const* key{ lua_tostring(L1, key_i) };
1384 size_t const keyRawLen = lua_rawlen(L1, key_i); 1256 size_t const keyRawLen = lua_rawlen(L1, key_i);
1385 size_t const bufLen = strlen(name) + keyRawLen + 2; 1257 size_t const bufLen = strlen(name) + keyRawLen + 2;
1386 valPath = (char*) alloca( bufLen); 1258 valPath = (char*) alloca(bufLen);
1387 sprintf( valPath, "%s.%*s", name, (int) keyRawLen, key); 1259 sprintf(valPath, "%s.%*s", name, (int) keyRawLen, key);
1388 key = nullptr; 1260 key = nullptr;
1389 } 1261 }
1390#if defined LUA_LNUM || LUA_VERSION_NUM >= 503 1262#if defined LUA_LNUM || LUA_VERSION_NUM >= 503
1391 else if (lua_isinteger(L1, key_i)) 1263 else if (lua_isinteger(L1, key_i)) {
1392 {
1393 lua_Integer const key{ lua_tointeger(L1, key_i) }; 1264 lua_Integer const key{ lua_tointeger(L1, key_i) };
1394 valPath = (char*) alloca(strlen(name) + 32 + 3); 1265 valPath = (char*) alloca(strlen(name) + 32 + 3);
1395 sprintf(valPath, "%s[" LUA_INTEGER_FMT "]", name, key); 1266 sprintf(valPath, "%s[" LUA_INTEGER_FMT "]", name, key);
1396 } 1267 }
1397#endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 1268#endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503
1398 else if (lua_type(L1, key_i) == LUA_TNUMBER) 1269 else if (lua_type(L1, key_i) == LUA_TNUMBER) {
1399 {
1400 lua_Number const key{ lua_tonumber(L1, key_i) }; 1270 lua_Number const key{ lua_tonumber(L1, key_i) };
1401 valPath = (char*) alloca(strlen(name) + 32 + 3); 1271 valPath = (char*) alloca(strlen(name) + 32 + 3);
1402 sprintf(valPath, "%s[" LUA_NUMBER_FMT "]", name, key); 1272 sprintf(valPath, "%s[" LUA_NUMBER_FMT "]", name, key);
1403 } 1273 } else if (lua_type(L1, key_i) == LUA_TLIGHTUSERDATA) {
1404 else if (lua_type( L1, key_i) == LUA_TLIGHTUSERDATA)
1405 {
1406 void* const key{ lua_touserdata(L1, key_i) }; 1274 void* const key{ lua_touserdata(L1, key_i) };
1407 valPath = (char*) alloca(strlen(name) + 16 + 5); 1275 valPath = (char*) alloca(strlen(name) + 16 + 5);
1408 sprintf(valPath, "%s[U:%p]", name, key); 1276 sprintf(valPath, "%s[U:%p]", name, key);
1409 } 1277 } else if (lua_type(L1, key_i) == LUA_TBOOLEAN) {
1410 else if (lua_type( L1, key_i) == LUA_TBOOLEAN)
1411 {
1412 int const key{ lua_toboolean(L1, key_i) }; 1278 int const key{ lua_toboolean(L1, key_i) };
1413 valPath = (char*) alloca(strlen(name) + 8); 1279 valPath = (char*) alloca(strlen(name) + 8);
1414 sprintf(valPath, "%s[%s]", name, key ? "true" : "false"); 1280 sprintf(valPath, "%s[%s]", name, key ? "true" : "false");
@@ -1418,132 +1284,114 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1418 // Contents of metatables are copied with cache checking. important to detect loops. 1284 // Contents of metatables are copied with cache checking. important to detect loops.
1419 c.vt = VT::NORMAL; 1285 c.vt = VT::NORMAL;
1420 c.name = valPath ? valPath : name; 1286 c.name = valPath ? valPath : name;
1421 if (c.inter_copy_one()) 1287 if (c.inter_copy_one()) {
1422 { 1288 LUA_ASSERT(L1, lua_istable(L2, -3));
1423 LUA_ASSERT(L1, lua_istable( L2, -3)); 1289 lua_rawset(L2, -3); // add to table (pops key & val)
1424 lua_rawset(L2, -3); // add to table (pops key & val) 1290 } else {
1425 }
1426 else
1427 {
1428 raise_luaL_error(L1, "Unable to copy %s entry '%s' because of value is of type '%s'", (vt == VT::NORMAL) ? "table" : "metatable", valPath, luaL_typename(L1, val_i)); 1291 raise_luaL_error(L1, "Unable to copy %s entry '%s' because of value is of type '%s'", (vt == VT::NORMAL) ? "table" : "metatable", valPath, luaL_typename(L1, val_i));
1429 } 1292 }
1430} 1293}
1431 1294
1432// ################################################################################################# 1295// #################################################################################################
1433 1296
1434[[nodiscard]] bool InterCopyContext::copyclone() const 1297[[nodiscard]] bool InterCopyContext::copyClonable() const
1435{ 1298{
1436 SourceIndex const L1_i{ lua_absindex(L1, this->L1_i) }; 1299 SourceIndex const L1_i{ lua_absindex(L1, this->L1_i) };
1437 void* const source{ lua_touserdata(L1, L1_i) }; 1300 void* const source{ lua_touserdata(L1, L1_i) };
1438 1301
1439 STACK_CHECK_START_REL(L1, 0); // L1 (source) // L2 (destination) 1302 STACK_CHECK_START_REL(L1, 0);
1440 STACK_CHECK_START_REL(L2, 0); 1303 STACK_CHECK_START_REL(L2, 0);
1441 1304
1442 // Check if the source was already cloned during this copy 1305 // Check if the source was already cloned during this copy
1443 lua_pushlightuserdata(L2, source); // ... source 1306 lua_pushlightuserdata(L2, source); // L2: ... source
1444 lua_rawget(L2, L2_cache_i); // ... clone? 1307 lua_rawget(L2, L2_cache_i); // L2: ... clone?
1445 if (!lua_isnil(L2, -1)) 1308 if (!lua_isnil(L2, -1)) {
1446 {
1447 STACK_CHECK(L2, 1); 1309 STACK_CHECK(L2, 1);
1448 return true; 1310 return true;
1449 } 1311 } else {
1450 else 1312 lua_pop(L2, 1); // L2: ...
1451 {
1452 lua_pop(L2, 1); // ...
1453 } 1313 }
1454 STACK_CHECK(L2, 0); 1314 STACK_CHECK(L2, 0);
1455 1315
1456 // no metatable? -> not clonable 1316 // no metatable? -> not clonable
1457 if (!lua_getmetatable(L1, L1_i)) // ... mt? 1317 if (!lua_getmetatable(L1, L1_i)) { // L1: ... mt?
1458 {
1459 STACK_CHECK(L1, 0); 1318 STACK_CHECK(L1, 0);
1460 return false; 1319 return false;
1461 } 1320 }
1462 1321
1463 // no __lanesclone? -> not clonable 1322 // no __lanesclone? -> not clonable
1464 lua_getfield(L1, -1, "__lanesclone"); // ... mt __lanesclone? 1323 lua_getfield(L1, -1, "__lanesclone"); // L1: ... mt __lanesclone?
1465 if (lua_isnil(L1, -1)) 1324 if (lua_isnil(L1, -1)) {
1466 { 1325 lua_pop(L1, 2); // L1: ...
1467 lua_pop(L1, 2); // ...
1468 STACK_CHECK(L1, 0); 1326 STACK_CHECK(L1, 0);
1469 return false; 1327 return false;
1470 } 1328 }
1471 1329
1472 // we need to copy over the uservalues of the userdata as well 1330 // we need to copy over the uservalues of the userdata as well
1473 { 1331 {
1474 int const mt{ lua_absindex(L1, -2) }; // ... mt __lanesclone 1332 int const mt{ lua_absindex(L1, -2) }; // L1: ... mt __lanesclone
1475 size_t const userdata_size{ lua_rawlen(L1, L1_i) }; 1333 size_t const userdata_size{ lua_rawlen(L1, L1_i) };
1476 // extract all the uservalues, but don't transfer them yet 1334 // extract all the uservalues, but don't transfer them yet
1477 int uvi = 0; 1335 int uvi = 0;
1478 while (lua_getiuservalue( L1, L1_i, ++ uvi) != LUA_TNONE) {} // ... mt __lanesclone [uv]+ nil 1336 while (lua_getiuservalue(L1, L1_i, ++uvi) != LUA_TNONE) {} // L1: ... mt __lanesclone [uv]+ nil
1479 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now 1337 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now
1480 lua_pop(L1, 1); // ... mt __lanesclone [uv]+ 1338 lua_pop(L1, 1); // L1: ... mt __lanesclone [uv]+
1481 -- uvi; 1339 --uvi;
1482 // create the clone userdata with the required number of uservalue slots 1340 // create the clone userdata with the required number of uservalue slots
1483 void* const clone{ lua_newuserdatauv(L2, userdata_size, uvi) }; // ... u 1341 void* const clone{ lua_newuserdatauv(L2, userdata_size, uvi) }; // L2: ... u
1484 // copy the metatable in the target state, and give it to the clone we put there 1342 // copy the metatable in the target state, and give it to the clone we put there
1485 InterCopyContext c{ U, L2, L1, L2_cache_i, SourceIndex{ mt }, VT::NORMAL, mode, name }; 1343 InterCopyContext c{ U, L2, L1, L2_cache_i, SourceIndex{ mt }, VT::NORMAL, mode, name };
1486 if (c.inter_copy_one()) // ... u mt|sentinel 1344 if (c.inter_copy_one()) { // L2: ... u mt|sentinel
1487 { 1345 if (LookupMode::ToKeeper == mode) { // L2: ... u sentinel
1488 if (LookupMode::ToKeeper == mode) // ... u sentinel
1489 {
1490 LUA_ASSERT(L1, lua_tocfunction(L2, -1) == table_lookup_sentinel); 1346 LUA_ASSERT(L1, lua_tocfunction(L2, -1) == table_lookup_sentinel);
1491 // we want to create a new closure with a 'clone sentinel' function, where the upvalues are the userdata and the metatable fqn 1347 // we want to create a new closure with a 'clone sentinel' function, where the upvalues are the userdata and the metatable fqn
1492 lua_getupvalue(L2, -1, 1); // ... u sentinel fqn 1348 lua_getupvalue(L2, -1, 1); // L2: ... u sentinel fqn
1493 lua_remove(L2, -2); // ... u fqn 1349 lua_remove(L2, -2); // L2: ... u fqn
1494 lua_insert(L2, -2); // ... fqn u 1350 lua_insert(L2, -2); // L2: ... fqn u
1495 lua_pushcclosure(L2, userdata_clone_sentinel, 2); // ... userdata_clone_sentinel 1351 lua_pushcclosure(L2, userdata_clone_sentinel, 2); // L2: ... userdata_clone_sentinel
1496 } 1352 } else { // from keeper or direct // L2: ... u mt
1497 else // from keeper or direct // ... u mt
1498 {
1499 LUA_ASSERT(L1, lua_istable(L2, -1)); 1353 LUA_ASSERT(L1, lua_istable(L2, -1));
1500 lua_setmetatable(L2, -2); // ... u 1354 lua_setmetatable(L2, -2); // L2: ... u
1501 } 1355 }
1502 STACK_CHECK(L2, 1); 1356 STACK_CHECK(L2, 1);
1503 } 1357 } else {
1504 else
1505 {
1506 raise_luaL_error(L1, "Error copying a metatable"); 1358 raise_luaL_error(L1, "Error copying a metatable");
1507 } 1359 }
1508 // first, add the entry in the cache (at this point it is either the actual userdata or the keeper sentinel 1360 // first, add the entry in the cache (at this point it is either the actual userdata or the keeper sentinel
1509 lua_pushlightuserdata( L2, source); // ... u source 1361 lua_pushlightuserdata(L2, source); // L2: ... u source
1510 lua_pushvalue( L2, -2); // ... u source u 1362 lua_pushvalue(L2, -2); // L2: ... u source u
1511 lua_rawset( L2, L2_cache_i); // ... u 1363 lua_rawset(L2, L2_cache_i); // L2: ... u
1512 // make sure we have the userdata now 1364 // make sure we have the userdata now
1513 if (LookupMode::ToKeeper == mode) // ... userdata_clone_sentinel 1365 if (LookupMode::ToKeeper == mode) { // L2: ... userdata_clone_sentinel
1514 { 1366 lua_getupvalue(L2, -1, 2); // L2: ... userdata_clone_sentinel u
1515 lua_getupvalue(L2, -1, 2); // ... userdata_clone_sentinel u
1516 } 1367 }
1517 // assign uservalues 1368 // assign uservalues
1518 while (uvi > 0) 1369 while (uvi > 0) {
1519 {
1520 c.L1_i = SourceIndex{ lua_absindex(L1, -1) }; 1370 c.L1_i = SourceIndex{ lua_absindex(L1, -1) };
1521 if (!c.inter_copy_one()) // ... u uv 1371 if (!c.inter_copy_one()) { // L2: ... u uv
1522 {
1523 raise_luaL_error(L1, "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); 1372 raise_luaL_error(L1, "Cannot copy upvalue type '%s'", luaL_typename(L1, -1));
1524 } 1373 }
1525 lua_pop(L1, 1); // ... mt __lanesclone [uv]* 1374 lua_pop(L1, 1); // L1: ... mt __lanesclone [uv]*
1526 // this pops the value from the stack 1375 // this pops the value from the stack
1527 lua_setiuservalue(L2, -2, uvi); // ... u 1376 lua_setiuservalue(L2, -2, uvi); // L2: ... u
1528 -- uvi; 1377 --uvi;
1529 } 1378 }
1530 // when we are done, all uservalues are popped from the source stack, and we want only the single transferred value in the destination 1379 // when we are done, all uservalues are popped from the source stack, and we want only the single transferred value in the destination
1531 if (LookupMode::ToKeeper == mode) // ... userdata_clone_sentinel u 1380 if (LookupMode::ToKeeper == mode) { // L2: ... userdata_clone_sentinel u
1532 { 1381 lua_pop(L2, 1); // L2: ... userdata_clone_sentinel
1533 lua_pop(L2, 1); // ... userdata_clone_sentinel
1534 } 1382 }
1535 STACK_CHECK(L2, 1); 1383 STACK_CHECK(L2, 1);
1536 STACK_CHECK(L1, 2); 1384 STACK_CHECK(L1, 2);
1537 // call cloning function in source state to perform the actual memory cloning 1385 // call cloning function in source state to perform the actual memory cloning
1538 lua_pushlightuserdata(L1, clone); // ... mt __lanesclone clone 1386 lua_pushlightuserdata(L1, clone); // L1: ... mt __lanesclone clone
1539 lua_pushlightuserdata(L1, source); // ... mt __lanesclone clone source 1387 lua_pushlightuserdata(L1, source); // L1: ... mt __lanesclone clone source
1540 lua_pushinteger(L1, static_cast<lua_Integer>(userdata_size)); // ... mt __lanesclone clone source size 1388 lua_pushinteger(L1, static_cast<lua_Integer>(userdata_size)); // L1: ... mt __lanesclone clone source size
1541 lua_call(L1, 3, 0); // ... mt 1389 lua_call(L1, 3, 0); // L1: ... mt
1542 STACK_CHECK(L1, 1); 1390 STACK_CHECK(L1, 1);
1543 } 1391 }
1544 1392
1545 STACK_CHECK(L2, 1); 1393 STACK_CHECK(L2, 1);
1546 lua_pop(L1, 1); // ... 1394 lua_pop(L1, 1); // L1: ...
1547 STACK_CHECK(L1, 0); 1395 STACK_CHECK(L1, 0);
1548 return true; 1396 return true;
1549} 1397}
@@ -1554,14 +1402,12 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1554{ 1402{
1555 STACK_CHECK_START_REL(L1, 0); 1403 STACK_CHECK_START_REL(L1, 0);
1556 STACK_CHECK_START_REL(L2, 0); 1404 STACK_CHECK_START_REL(L2, 0);
1557 if (vt == VT::KEY) 1405 if (vt == VT::KEY) {
1558 {
1559 return false; 1406 return false;
1560 } 1407 }
1561 1408
1562 // try clonable userdata first 1409 // try clonable userdata first
1563 if (copyclone()) 1410 if (copyClonable()) {
1564 {
1565 STACK_CHECK(L1, 0); 1411 STACK_CHECK(L1, 0);
1566 STACK_CHECK(L2, 1); 1412 STACK_CHECK(L2, 1);
1567 return true; 1413 return true;
@@ -1572,8 +1418,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1572 1418
1573 // Allow only deep userdata entities to be copied across 1419 // Allow only deep userdata entities to be copied across
1574 DEBUGSPEW_CODE(fprintf(stderr, "USERDATA\n")); 1420 DEBUGSPEW_CODE(fprintf(stderr, "USERDATA\n"));
1575 if (copydeep()) 1421 if (copyDeep()) {
1576 {
1577 STACK_CHECK(L1, 0); 1422 STACK_CHECK(L1, 0);
1578 STACK_CHECK(L2, 1); 1423 STACK_CHECK(L2, 1);
1579 return true; 1424 return true;
@@ -1583,13 +1428,10 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1583 STACK_CHECK(L2, 0); 1428 STACK_CHECK(L2, 0);
1584 1429
1585 // Not a deep or clonable full userdata 1430 // Not a deep or clonable full userdata
1586 if (U->demoteFullUserdata) // attempt demotion to light userdata 1431 if (U->demoteFullUserdata) { // attempt demotion to light userdata
1587 {
1588 void* const lud{ lua_touserdata(L1, L1_i) }; 1432 void* const lud{ lua_touserdata(L1, L1_i) };
1589 lua_pushlightuserdata(L2, lud); 1433 lua_pushlightuserdata(L2, lud);
1590 } 1434 } else { // raise an error
1591 else // raise an error
1592 {
1593 raise_luaL_error(L1, "can't copy non-deep full userdata across lanes"); 1435 raise_luaL_error(L1, "can't copy non-deep full userdata across lanes");
1594 } 1436 }
1595 1437
@@ -1602,37 +1444,33 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1602 1444
1603[[nodiscard]] bool InterCopyContext::inter_copy_function() const 1445[[nodiscard]] bool InterCopyContext::inter_copy_function() const
1604{ 1446{
1605 if (vt == VT::KEY) 1447 if (vt == VT::KEY) {
1606 {
1607 return false; 1448 return false;
1608 } 1449 }
1609 1450
1610 STACK_CHECK_START_REL(L1, 0); // L1 (source) // L2 (destination) 1451 STACK_CHECK_START_REL(L1, 0);
1611 STACK_CHECK_START_REL(L2, 0); 1452 STACK_CHECK_START_REL(L2, 0);
1612 DEBUGSPEW_CODE(fprintf(stderr, "FUNCTION %s\n", name)); 1453 DEBUGSPEW_CODE(fprintf(stderr, "FUNCTION %s\n", name));
1613 1454
1614 if (lua_tocfunction(L1, L1_i) == userdata_clone_sentinel) // we are actually copying a clonable full userdata from a keeper 1455 if (lua_tocfunction(L1, L1_i) == userdata_clone_sentinel) { // we are actually copying a clonable full userdata from a keeper
1615 {
1616 // clone the full userdata again 1456 // clone the full userdata again
1617 1457
1618 // let's see if we already restored this userdata 1458 // let's see if we already restored this userdata
1619 lua_getupvalue(L1, L1_i, 2); // ... u 1459 lua_getupvalue(L1, L1_i, 2); // L1: ... u
1620 void* source = lua_touserdata(L1, -1); 1460 void* source = lua_touserdata(L1, -1);
1621 lua_pushlightuserdata(L2, source); // ... source 1461 lua_pushlightuserdata(L2, source); // L2: ... source
1622 lua_rawget(L2, L2_cache_i); // ... u? 1462 lua_rawget(L2, L2_cache_i); // L2: ... u?
1623 if (!lua_isnil(L2, -1)) 1463 if (!lua_isnil(L2, -1)) {
1624 { 1464 lua_pop(L1, 1); // L1: ...
1625 lua_pop(L1, 1); // ...
1626 STACK_CHECK(L1, 0); 1465 STACK_CHECK(L1, 0);
1627 STACK_CHECK(L2, 1); 1466 STACK_CHECK(L2, 1);
1628 return true; 1467 return true;
1629 } 1468 }
1630 lua_pop(L2, 1); // ... 1469 lua_pop(L2, 1); // L2: ...
1631 1470
1632 // userdata_clone_sentinel has 2 upvalues: the fqn of its metatable, and the userdata itself 1471 // userdata_clone_sentinel has 2 upvalues: the fqn of its metatable, and the userdata itself
1633 bool const found{ lookup_table() }; // ... mt? 1472 bool const found{ lookup_table() }; // L2: ... mt?
1634 if (!found) 1473 if (!found) {
1635 {
1636 STACK_CHECK(L2, 0); 1474 STACK_CHECK(L2, 0);
1637 return false; 1475 return false;
1638 } 1476 }
@@ -1645,55 +1483,51 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1645 { 1483 {
1646 // extract uservalues (don't transfer them yet) 1484 // extract uservalues (don't transfer them yet)
1647 int uvi = 0; 1485 int uvi = 0;
1648 while (lua_getiuservalue(L1, source_i, ++uvi) != LUA_TNONE) {} // ... u uv 1486 while (lua_getiuservalue(L1, source_i, ++uvi) != LUA_TNONE) {} // L1: ... u uv
1649 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now 1487 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now
1650 lua_pop(L1, 1); // ... u [uv]* 1488 lua_pop(L1, 1); // L1: ... u [uv]*
1651 --uvi; 1489 --uvi;
1652 STACK_CHECK(L1, uvi + 1); 1490 STACK_CHECK(L1, uvi + 1);
1653 // create the clone userdata with the required number of uservalue slots 1491 // create the clone userdata with the required number of uservalue slots
1654 clone = lua_newuserdatauv(L2, userdata_size, uvi); // ... mt u 1492 clone = lua_newuserdatauv(L2, userdata_size, uvi); // L2: ... mt u
1655 // add it in the cache 1493 // add it in the cache
1656 lua_pushlightuserdata(L2, source); // ... mt u source 1494 lua_pushlightuserdata(L2, source); // L2: ... mt u source
1657 lua_pushvalue(L2, -2); // ... mt u source u 1495 lua_pushvalue(L2, -2); // L2: ... mt u source u
1658 lua_rawset(L2, L2_cache_i); // ... mt u 1496 lua_rawset(L2, L2_cache_i); // L2: ... mt u
1659 // set metatable 1497 // set metatable
1660 lua_pushvalue(L2, -2); // ... mt u mt 1498 lua_pushvalue(L2, -2); // L2: ... mt u mt
1661 lua_setmetatable(L2, -2); // ... mt u 1499 lua_setmetatable(L2, -2); // L2: ... mt u
1662 // transfer and assign uservalues 1500 // transfer and assign uservalues
1663 InterCopyContext c{ *this }; 1501 InterCopyContext c{ *this };
1664 while (uvi > 0) 1502 while (uvi > 0) {
1665 {
1666 c.L1_i = SourceIndex{ lua_absindex(L1, -1) }; 1503 c.L1_i = SourceIndex{ lua_absindex(L1, -1) };
1667 if (!c.inter_copy_one()) // ... mt u uv 1504 if (!c.inter_copy_one()) { // L2: ... mt u uv
1668 {
1669 raise_luaL_error(L1, "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); 1505 raise_luaL_error(L1, "Cannot copy upvalue type '%s'", luaL_typename(L1, -1));
1670 } 1506 }
1671 lua_pop(L1, 1); // ... u [uv]* 1507 lua_pop(L1, 1); // L1: ... u [uv]*
1672 // this pops the value from the stack 1508 // this pops the value from the stack
1673 lua_setiuservalue(L2, -2, uvi); // ... mt u 1509 lua_setiuservalue(L2, -2, uvi); // L2: ... mt u
1674 -- uvi; 1510 --uvi;
1675 } 1511 }
1676 // when we are done, all uservalues are popped from the stack, we can pop the source as well 1512 // when we are done, all uservalues are popped from the stack, we can pop the source as well
1677 lua_pop(L1, 1); // ... 1513 lua_pop(L1, 1); // L1: ...
1678 STACK_CHECK(L1, 0); 1514 STACK_CHECK(L1, 0);
1679 STACK_CHECK(L2, 2); // ... mt u 1515 STACK_CHECK(L2, 2); // L2: ... mt u
1680 } 1516 }
1681 // perform the custom cloning part 1517 // perform the custom cloning part
1682 lua_insert(L2, -2); // ... u mt 1518 lua_insert(L2, -2); // L2: ... u mt
1683 // __lanesclone should always exist because we wouldn't be restoring data from a userdata_clone_sentinel closure to begin with 1519 // __lanesclone should always exist because we wouldn't be restoring data from a userdata_clone_sentinel closure to begin with
1684 lua_getfield(L2, -1, "__lanesclone"); // ... u mt __lanesclone 1520 lua_getfield(L2, -1, "__lanesclone"); // L2: ... u mt __lanesclone
1685 lua_remove(L2, -2); // ... u __lanesclone 1521 lua_remove(L2, -2); // L2: ... u __lanesclone
1686 lua_pushlightuserdata(L2, clone); // ... u __lanesclone clone 1522 lua_pushlightuserdata(L2, clone); // L2: ... u __lanesclone clone
1687 lua_pushlightuserdata(L2, source); // ... u __lanesclone clone source 1523 lua_pushlightuserdata(L2, source); // L2: ... u __lanesclone clone source
1688 lua_pushinteger(L2, userdata_size); // ... u __lanesclone clone source size 1524 lua_pushinteger(L2, userdata_size); // L2: ... u __lanesclone clone source size
1689 // clone:__lanesclone(dest, source, size) 1525 // clone:__lanesclone(dest, source, size)
1690 lua_call(L2, 3, 0); // ... u 1526 lua_call(L2, 3, 0); // L2: ... u
1691 } 1527 } else { // regular function
1692 else // regular function 1528 DEBUGSPEW_CODE(fprintf(stderr, "FUNCTION %s\n", name));
1693 {
1694 DEBUGSPEW_CODE(fprintf( stderr, "FUNCTION %s\n", name));
1695 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); 1529 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U });
1696 copy_cached_func(); // ... f 1530 copy_cached_func(); // L2: ... f
1697 } 1531 }
1698 STACK_CHECK(L2, 1); 1532 STACK_CHECK(L2, 1);
1699 STACK_CHECK(L1, 0); 1533 STACK_CHECK(L1, 0);
@@ -1704,8 +1538,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1704 1538
1705[[nodiscard]] bool InterCopyContext::inter_copy_table() const 1539[[nodiscard]] bool InterCopyContext::inter_copy_table() const
1706{ 1540{
1707 if (vt == VT::KEY) 1541 if (vt == VT::KEY) {
1708 {
1709 return false; 1542 return false;
1710 } 1543 }
1711 1544
@@ -1717,24 +1550,22 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1717 * First, let's try to see if this table is special (aka is it some table that we registered in our lookup databases during module registration?) 1550 * First, let's try to see if this table is special (aka is it some table that we registered in our lookup databases during module registration?)
1718 * Note that this table CAN be a module table, but we just didn't register it, in which case we'll send it through the table cloning mechanism 1551 * Note that this table CAN be a module table, but we just didn't register it, in which case we'll send it through the table cloning mechanism
1719 */ 1552 */
1720 if (lookup_table()) 1553 if (lookup_table()) {
1721 {
1722 LUA_ASSERT(L1, lua_istable(L2, -1) || (lua_tocfunction(L2, -1) == table_lookup_sentinel)); // from lookup data. can also be table_lookup_sentinel if this is a table we know 1554 LUA_ASSERT(L1, lua_istable(L2, -1) || (lua_tocfunction(L2, -1) == table_lookup_sentinel)); // from lookup data. can also be table_lookup_sentinel if this is a table we know
1723 return true; 1555 return true;
1724 } 1556 }
1725 1557
1726 /* Check if we've already copied the same table from 'L1' (during this transmission), and 1558 /* Check if we've already copied the same table from 'L1' (during this transmission), and
1727 * reuse the old copy. This allows table upvalues shared by multiple 1559 * reuse the old copy. This allows table upvalues shared by multiple
1728 * local functions to point to the same table, also in the target. 1560 * local functions to point to the same table, also in the target.
1729 * Also, this takes care of cyclic tables and multiple references 1561 * Also, this takes care of cyclic tables and multiple references
1730 * to the same subtable. 1562 * to the same subtable.
1731 * 1563 *
1732 * Note: Even metatables need to go through this test; to detect 1564 * Note: Even metatables need to go through this test; to detect
1733 * loops such as those in required module tables (getmetatable(lanes).lanes == lanes) 1565 * loops such as those in required module tables (getmetatable(lanes).lanes == lanes)
1734 */ 1566 */
1735 if (push_cached_table(L2, L2_cache_i, L1, L1_i)) 1567 if (push_cached_table(L2, L2_cache_i, L1, L1_i)) {
1736 { 1568 LUA_ASSERT(L1, lua_istable(L2, -1)); // from cache
1737 LUA_ASSERT(L1, lua_istable(L2, -1)); // from cache
1738 return true; 1569 return true;
1739 } 1570 }
1740 LUA_ASSERT(L1, lua_istable(L2, -1)); 1571 LUA_ASSERT(L1, lua_istable(L2, -1));
@@ -1743,19 +1574,17 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1743 STACK_GROW(L2, 2); 1574 STACK_GROW(L2, 2);
1744 1575
1745 lua_pushnil(L1); // start iteration 1576 lua_pushnil(L1); // start iteration
1746 while (lua_next(L1, L1_i)) 1577 while (lua_next(L1, L1_i)) {
1747 {
1748 // need a function to prevent overflowing the stack with verboseErrors-induced alloca() 1578 // need a function to prevent overflowing the stack with verboseErrors-induced alloca()
1749 inter_copy_keyvaluepair(); 1579 inter_copy_keyvaluepair();
1750 lua_pop(L1, 1); // pop value (next round) 1580 lua_pop(L1, 1); // pop value (next round)
1751 } 1581 }
1752 STACK_CHECK(L1, 0); 1582 STACK_CHECK(L1, 0);
1753 STACK_CHECK(L2, 1); 1583 STACK_CHECK(L2, 1);
1754 1584
1755 // Metatables are expected to be immutable, and copied only once. 1585 // Metatables are expected to be immutable, and copied only once.
1756 if (push_cached_metatable()) // ... t mt? 1586 if (push_cached_metatable()) { // L2: ... t mt?
1757 { 1587 lua_setmetatable(L2, -2); // L2: ... t
1758 lua_setmetatable(L2, -2); // ... t
1759 } 1588 }
1760 STACK_CHECK(L2, 1); 1589 STACK_CHECK(L2, 1);
1761 STACK_CHECK(L1, 0); 1590 STACK_CHECK(L1, 0);
@@ -1786,8 +1615,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1786 1615
1787[[nodiscard]] bool InterCopyContext::inter_copy_nil() const 1616[[nodiscard]] bool InterCopyContext::inter_copy_nil() const
1788{ 1617{
1789 if (vt == VT::KEY) 1618 if (vt == VT::KEY) {
1790 {
1791 return false; 1619 return false;
1792 } 1620 }
1793 lua_pushnil(L2); 1621 lua_pushnil(L2);
@@ -1798,15 +1626,13 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1798 1626
1799[[nodiscard]] bool InterCopyContext::inter_copy_number() const 1627[[nodiscard]] bool InterCopyContext::inter_copy_number() const
1800{ 1628{
1801 /* LNUM patch support (keeping integer accuracy) */ 1629 // LNUM patch support (keeping integer accuracy)
1802#if defined LUA_LNUM || LUA_VERSION_NUM >= 503 1630#if defined LUA_LNUM || LUA_VERSION_NUM >= 503
1803 if (lua_isinteger(L1, L1_i)) 1631 if (lua_isinteger(L1, L1_i)) {
1804 {
1805 lua_Integer const v{ lua_tointeger(L1, L1_i) }; 1632 lua_Integer const v{ lua_tointeger(L1, L1_i) };
1806 DEBUGSPEW_CODE(fprintf(stderr, LUA_INTEGER_FMT "\n", v)); 1633 DEBUGSPEW_CODE(fprintf(stderr, LUA_INTEGER_FMT "\n", v));
1807 lua_pushinteger(L2, v); 1634 lua_pushinteger(L2, v);
1808 } 1635 } else
1809 else
1810#endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 1636#endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503
1811 { 1637 {
1812 lua_Number const v{ lua_tonumber(L1, L1_i) }; 1638 lua_Number const v{ lua_tonumber(L1, L1_i) };
@@ -1830,63 +1656,78 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1830// ################################################################################################# 1656// #################################################################################################
1831 1657
1832/* 1658/*
1833* Copies a value from 'L1' state (at index 'i') to 'L2' state. Does not remove 1659 * Copies a value from 'L1' state (at index 'i') to 'L2' state. Does not remove
1834* the original value. 1660 * the original value.
1835* 1661 *
1836* NOTE: Both the states must be solely in the current OS thread's possession. 1662 * NOTE: Both the states must be solely in the current OS thread's possession.
1837* 1663 *
1838* 'i' is an absolute index (no -1, ...) 1664 * 'i' is an absolute index (no -1, ...)
1839* 1665 *
1840* Returns true if value was pushed, false if its type is non-supported. 1666 * Returns true if value was pushed, false if its type is non-supported.
1841*/ 1667 */
1842[[nodiscard]] bool InterCopyContext::inter_copy_one() const 1668[[nodiscard]] bool InterCopyContext::inter_copy_one() const
1843{ 1669{
1844 static constexpr int kPODmask = (1 << LUA_TNIL) | (1 << LUA_TBOOLEAN) | (1 << LUA_TLIGHTUSERDATA) | (1 << LUA_TNUMBER) | (1 << LUA_TSTRING); 1670 static constexpr int kPODmask = (1 << LUA_TNIL) | (1 << LUA_TBOOLEAN) | (1 << LUA_TLIGHTUSERDATA) | (1 << LUA_TNUMBER) | (1 << LUA_TSTRING);
1845 STACK_GROW(L2, 1); 1671 STACK_GROW(L2, 1);
1846 STACK_CHECK_START_REL(L1, 0); // L1 // L2 1672 STACK_CHECK_START_REL(L1, 0);
1847 STACK_CHECK_START_REL(L2, 0); // L1 // L2 1673 STACK_CHECK_START_REL(L2, 0);
1848 1674
1849 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "inter_copy_one()\n" INDENT_END)); 1675 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "inter_copy_one()\n" INDENT_END(U)));
1850 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); 1676 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U });
1851 1677
1852 LuaType val_type{ lua_type_as_enum(L1, L1_i) }; 1678 LuaType val_type{ lua_type_as_enum(L1, L1_i) };
1853 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%s %s: " INDENT_END, lua_type_names[static_cast<int>(val_type)], vt_names[static_cast<int>(vt)])); 1679 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%s %s: " INDENT_END(U), lua_type_names[static_cast<int>(val_type)], vt_names[static_cast<int>(vt)]));
1854 1680
1855 // Non-POD can be skipped if its metatable contains { __lanesignore = true } 1681 // Non-POD can be skipped if its metatable contains { __lanesignore = true }
1856 if (((1 << static_cast<int>(val_type)) & kPODmask) == 0) 1682 if (((1 << static_cast<int>(val_type)) & kPODmask) == 0) {
1857 { 1683 if (lua_getmetatable(L1, L1_i)) { // L1: ... mt
1858 if (lua_getmetatable(L1, L1_i)) // ... mt 1684 lua_getfield(L1, -1, "__lanesignore"); // L1: ... mt ignore?
1859 { 1685 if (lua_isboolean(L1, -1) && lua_toboolean(L1, -1)) {
1860 lua_getfield(L1, -1, "__lanesignore"); // ... mt ignore? 1686 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "__lanesignore -> LUA_TNIL\n" INDENT_END(U)));
1861 if (lua_isboolean(L1, -1) && lua_toboolean(L1, -1))
1862 {
1863 DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "__lanesignore -> LUA_TNIL\n" INDENT_END));
1864 val_type = LuaType::NIL; 1687 val_type = LuaType::NIL;
1865 } 1688 }
1866 lua_pop(L1, 2); // ... 1689 lua_pop(L1, 2); // L1: ...
1867 } 1690 }
1868 } 1691 }
1869 STACK_CHECK(L1, 0); 1692 STACK_CHECK(L1, 0);
1870 1693
1871 /* Lets push nil to L2 if the object should be ignored */ 1694 // Lets push nil to L2 if the object should be ignored
1872 bool ret{ true }; 1695 bool ret{ true };
1873 switch (val_type) 1696 switch (val_type) {
1874 { 1697 // Basic types allowed both as values, and as table keys
1875 // Basic types allowed both as values, and as table keys 1698 case LuaType::BOOLEAN:
1876 case LuaType::BOOLEAN: ret = inter_copy_boolean(); break; 1699 ret = inter_copy_boolean();
1877 case LuaType::NUMBER: ret = inter_copy_number(); break; 1700 break;
1878 case LuaType::STRING: ret = inter_copy_string(); break; 1701 case LuaType::NUMBER:
1879 case LuaType::LIGHTUSERDATA: ret = inter_copy_lightuserdata();break; 1702 ret = inter_copy_number();
1880 1703 break;
1881 // The following types are not allowed as table keys 1704 case LuaType::STRING:
1882 case LuaType::USERDATA: ret = inter_copy_userdata(); break; 1705 ret = inter_copy_string();
1883 case LuaType::NIL: ret = inter_copy_nil(); break; 1706 break;
1884 case LuaType::FUNCTION: ret = inter_copy_function(); break; 1707 case LuaType::LIGHTUSERDATA:
1885 case LuaType::TABLE: ret = inter_copy_table(); break; 1708 ret = inter_copy_lightuserdata();
1886 1709 break;
1887 // The following types cannot be copied 1710
1888 case LuaType::CDATA: [[fallthrough]]; 1711 // The following types are not allowed as table keys
1889 case LuaType::THREAD: ret = false; break; 1712 case LuaType::USERDATA:
1713 ret = inter_copy_userdata();
1714 break;
1715 case LuaType::NIL:
1716 ret = inter_copy_nil();
1717 break;
1718 case LuaType::FUNCTION:
1719 ret = inter_copy_function();
1720 break;
1721 case LuaType::TABLE:
1722 ret = inter_copy_table();
1723 break;
1724
1725 // The following types cannot be copied
1726 case LuaType::CDATA:
1727 [[fallthrough]];
1728 case LuaType::THREAD:
1729 ret = false;
1730 break;
1890 } 1731 }
1891 1732
1892 STACK_CHECK(L2, ret ? 1 : 0); 1733 STACK_CHECK(L2, ret ? 1 : 0);
@@ -1902,14 +1743,13 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1902{ 1743{
1903 LUA_ASSERT(L1, vt == VT::NORMAL); 1744 LUA_ASSERT(L1, vt == VT::NORMAL);
1904 1745
1905 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "InterCopyContext::inter_copy()\n" INDENT_END)); 1746 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "InterCopyContext::inter_copy()\n" INDENT_END(U)));
1906 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); 1747 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U });
1907 1748
1908 int const top_L1{ lua_gettop(L1) }; 1749 int const top_L1{ lua_gettop(L1) };
1909 if (n_ > top_L1) 1750 if (n_ > top_L1) {
1910 {
1911 // requesting to copy more than is available? 1751 // requesting to copy more than is available?
1912 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "nothing to copy()\n" INDENT_END)); 1752 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "nothing to copy()\n" INDENT_END(U)));
1913 return InterCopyResult::NotEnoughValues; 1753 return InterCopyResult::NotEnoughValues;
1914 } 1754 }
1915 1755
@@ -1917,35 +1757,31 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1917 STACK_GROW(L2, n_ + 1); 1757 STACK_GROW(L2, n_ + 1);
1918 1758
1919 /* 1759 /*
1920 * Make a cache table for the duration of this copy. Collects tables and 1760 * Make a cache table for the duration of this copy. Collects tables and
1921 * function entries, avoiding the same entries to be passed on as multiple 1761 * function entries, avoiding the same entries to be passed on as multiple
1922 * copies. ESSENTIAL i.e. for handling upvalue tables in the right manner! 1762 * copies. ESSENTIAL i.e. for handling upvalue tables in the right manner!
1923 */ 1763 */
1924 int const top_L2{ lua_gettop(L2) }; // ... 1764 int const top_L2{ lua_gettop(L2) }; // L2: ...
1925 lua_newtable(L2); // ... cache 1765 lua_newtable(L2); // L2: ... cache
1926 1766
1927 char tmpBuf[16]; 1767 char tmpBuf[16];
1928 char const* const pBuf{ U->verboseErrors ? tmpBuf : "?" }; 1768 char const* const pBuf{ U->verboseErrors ? tmpBuf : "?" };
1929 InterCopyContext c{ U, L2, L1, CacheIndex{ top_L2 + 1 }, {}, VT::NORMAL, mode, pBuf }; 1769 InterCopyContext c{ U, L2, L1, CacheIndex{ top_L2 + 1 }, {}, VT::NORMAL, mode, pBuf };
1930 bool copyok{ true }; 1770 bool copyok{ true };
1931 STACK_CHECK_START_REL(L1, 0); 1771 STACK_CHECK_START_REL(L1, 0);
1932 for (int i{ top_L1 - n_ + 1 }, j{ 1 }; i <= top_L1; ++i, ++j) 1772 for (int i{ top_L1 - n_ + 1 }, j{ 1 }; i <= top_L1; ++i, ++j) {
1933 { 1773 if (U->verboseErrors) {
1934 if (U->verboseErrors)
1935 {
1936 sprintf(tmpBuf, "arg_%d", j); 1774 sprintf(tmpBuf, "arg_%d", j);
1937 } 1775 }
1938 c.L1_i = SourceIndex{ i }; 1776 c.L1_i = SourceIndex{ i };
1939 copyok = c.inter_copy_one(); // ... cache {}n 1777 copyok = c.inter_copy_one(); // L2: ... cache {}n
1940 if (!copyok) 1778 if (!copyok) {
1941 {
1942 break; 1779 break;
1943 } 1780 }
1944 } 1781 }
1945 STACK_CHECK(L1, 0); 1782 STACK_CHECK(L1, 0);
1946 1783
1947 if (copyok) 1784 if (copyok) {
1948 {
1949 STACK_CHECK(L2, n_ + 1); 1785 STACK_CHECK(L2, n_ + 1);
1950 // Remove the cache table. Persistent caching would cause i.e. multiple 1786 // Remove the cache table. Persistent caching would cause i.e. multiple
1951 // messages passed in the same table to use the same table also in receiving end. 1787 // messages passed in the same table to use the same table also in receiving end.
@@ -1964,7 +1800,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1964[[nodiscard]] InterCopyResult InterCopyContext::inter_move(int n_) const 1800[[nodiscard]] InterCopyResult InterCopyContext::inter_move(int n_) const
1965{ 1801{
1966 InterCopyResult const ret{ inter_copy(n_) }; 1802 InterCopyResult const ret{ inter_copy(n_) };
1967 lua_pop( L1, n_); 1803 lua_pop(L1, n_);
1968 return ret; 1804 return ret;
1969} 1805}
1970 1806
@@ -1976,22 +1812,19 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1976// else raise an error in L1 1812// else raise an error in L1
1977[[nodiscard]] InterCopyResult InterCopyContext::inter_copy_package() const 1813[[nodiscard]] InterCopyResult InterCopyContext::inter_copy_package() const
1978{ 1814{
1979 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "InterCopyContext::inter_copy_package()\n" INDENT_END)); 1815 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "InterCopyContext::inter_copy_package()\n" INDENT_END(U)));
1980 1816
1981 class OnExit 1817 class OnExit
1982 { 1818 {
1983 private: 1819 private:
1984
1985 lua_State* const L2; 1820 lua_State* const L2;
1986 int const top_L2; 1821 int const top_L2;
1987 DEBUGSPEW_CODE(DebugSpewIndentScope m_scope); 1822 DEBUGSPEW_CODE(DebugSpewIndentScope m_scope);
1988 1823
1989 public: 1824 public:
1990
1991 OnExit(Universe* U_, lua_State* L2_) 1825 OnExit(Universe* U_, lua_State* L2_)
1992 : L2{ L2_ } 1826 : L2{ L2_ }
1993 , top_L2{ lua_gettop(L2) } 1827 , top_L2{ lua_gettop(L2) } DEBUGSPEW_COMMA_PARAM(m_scope{ U_ })
1994 DEBUGSPEW_COMMA_PARAM(m_scope{ U_ })
1995 { 1828 {
1996 } 1829 }
1997 1830
@@ -2002,21 +1835,18 @@ void InterCopyContext::inter_copy_keyvaluepair() const
2002 } onExit{ U, L2 }; 1835 } onExit{ U, L2 };
2003 1836
2004 STACK_CHECK_START_REL(L1, 0); 1837 STACK_CHECK_START_REL(L1, 0);
2005 if (lua_type_as_enum(L1, L1_i) != LuaType::TABLE) 1838 if (lua_type_as_enum(L1, L1_i) != LuaType::TABLE) {
2006 {
2007 lua_pushfstring(L1, "expected package as table, got %s", luaL_typename(L1, L1_i)); 1839 lua_pushfstring(L1, "expected package as table, got %s", luaL_typename(L1, L1_i));
2008 STACK_CHECK(L1, 1); 1840 STACK_CHECK(L1, 1);
2009 // raise the error when copying from lane to lane, else just leave it on the stack to be raised later 1841 // raise the error when copying from lane to lane, else just leave it on the stack to be raised later
2010 if (mode == LookupMode::LaneBody) 1842 if (mode == LookupMode::LaneBody) {
2011 {
2012 raise_lua_error(L1); 1843 raise_lua_error(L1);
2013 } 1844 }
2014 return InterCopyResult::Error; 1845 return InterCopyResult::Error;
2015 } 1846 }
2016 lua_getglobal(L2, "package"); // TODO: use _R._LOADED.package instead of _G.package 1847 lua_getglobal(L2, "package"); // TODO: use _R._LOADED.package instead of _G.package
2017 if (lua_isnil(L2, -1)) // package library not loaded: do nothing 1848 if (lua_isnil(L2, -1)) { // package library not loaded: do nothing
2018 { 1849 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "'package' not loaded, nothing to do\n" INDENT_END(U)));
2019 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "'package' not loaded, nothing to do\n" INDENT_END));
2020 STACK_CHECK(L1, 0); 1850 STACK_CHECK(L1, 0);
2021 return InterCopyResult::Success; 1851 return InterCopyResult::Success;
2022 } 1852 }
@@ -2027,35 +1857,26 @@ void InterCopyContext::inter_copy_keyvaluepair() const
2027 // users should provide an on_state_create function to setup custom loaders instead 1857 // users should provide an on_state_create function to setup custom loaders instead
2028 // don't copy package.preload in keeper states (they don't know how to translate functions) 1858 // don't copy package.preload in keeper states (they don't know how to translate functions)
2029 char const* entries[] = { "path", "cpath", (mode == LookupMode::LaneBody) ? "preload" : nullptr /*, (LUA_VERSION_NUM == 501) ? "loaders" : "searchers"*/, nullptr }; 1859 char const* entries[] = { "path", "cpath", (mode == LookupMode::LaneBody) ? "preload" : nullptr /*, (LUA_VERSION_NUM == 501) ? "loaders" : "searchers"*/, nullptr };
2030 for (char const* const entry : entries) 1860 for (char const* const entry : entries) {
2031 { 1861 if (!entry) {
2032 if (!entry)
2033 {
2034 continue; 1862 continue;
2035 } 1863 }
2036 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "package.%s\n" INDENT_END, entry)); 1864 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "package.%s\n" INDENT_END(U), entry));
2037 lua_getfield(L1, L1_i, entry); 1865 lua_getfield(L1, L1_i, entry);
2038 if (lua_isnil(L1, -1)) 1866 if (lua_isnil(L1, -1)) {
2039 {
2040 lua_pop(L1, 1); 1867 lua_pop(L1, 1);
2041 } 1868 } else {
2042 else
2043 {
2044 { 1869 {
2045 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); 1870 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U });
2046 result = inter_move(1); // moves the entry to L2 1871 result = inter_move(1); // moves the entry to L2
2047 STACK_CHECK(L1, 0); 1872 STACK_CHECK(L1, 0);
2048 } 1873 }
2049 if (result == InterCopyResult::Success) 1874 if (result == InterCopyResult::Success) {
2050 {
2051 lua_setfield(L2, -2, entry); // set package[entry] 1875 lua_setfield(L2, -2, entry); // set package[entry]
2052 } 1876 } else {
2053 else
2054 {
2055 lua_pushfstring(L1, "failed to copy package entry %s", entry); 1877 lua_pushfstring(L1, "failed to copy package entry %s", entry);
2056 // raise the error when copying from lane to lane, else just leave it on the stack to be raised later 1878 // raise the error when copying from lane to lane, else just leave it on the stack to be raised later
2057 if (mode == LookupMode::LaneBody) 1879 if (mode == LookupMode::LaneBody) {
2058 {
2059 raise_lua_error(L1); 1880 raise_lua_error(L1);
2060 } 1881 }
2061 lua_pop(L1, 1); 1882 lua_pop(L1, 1);