diff options
Diffstat (limited to 'src/tools.cpp')
-rw-r--r-- | src/tools.cpp | 669 |
1 files changed, 298 insertions, 371 deletions
diff --git a/src/tools.cpp b/src/tools.cpp index ad706be..cd25eda 100644 --- a/src/tools.cpp +++ b/src/tools.cpp | |||
@@ -35,13 +35,12 @@ THE SOFTWARE. | |||
35 | 35 | ||
36 | #include "universe.h" | 36 | #include "universe.h" |
37 | 37 | ||
38 | // functions implemented in deep.c | ||
39 | extern void push_registry_subtable( lua_State* L, UniqueKey key_); | ||
40 | |||
41 | DEBUGSPEW_CODE(char const* const DebugSpewIndentScope::debugspew_indent = "----+----!----+----!----+----!----+----!----+----!----+----!----+----!----+"); | 38 | DEBUGSPEW_CODE(char const* const DebugSpewIndentScope::debugspew_indent = "----+----!----+----!----+----!----+----!----+----!----+----!----+----!----+"); |
42 | 39 | ||
40 | // crc64/we of string "LOOKUPCACHE_REGKEY" generated at http://www.nitrxgen.net/hashgen/ | ||
41 | static constexpr UniqueKey LOOKUPCACHE_REGKEY{ 0x837a68dfc6fcb716ull }; | ||
43 | 42 | ||
44 | // ################################################################################################ | 43 | // ################################################################################################# |
45 | 44 | ||
46 | /* | 45 | /* |
47 | * 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 |
@@ -76,7 +75,7 @@ void push_registry_subtable_mode( lua_State* L, UniqueKey key_, const char* mode | |||
76 | ASSERT_L(lua_istable(L, -1)); | 75 | ASSERT_L(lua_istable(L, -1)); |
77 | } | 76 | } |
78 | 77 | ||
79 | // ################################################################################################ | 78 | // ################################################################################################# |
80 | 79 | ||
81 | /* | 80 | /* |
82 | * Push a registry subtable (keyed by unique 'key_') onto the stack. | 81 | * Push a registry subtable (keyed by unique 'key_') onto the stack. |
@@ -87,60 +86,7 @@ void push_registry_subtable( lua_State* L, UniqueKey key_) | |||
87 | push_registry_subtable_mode(L, key_, nullptr); | 86 | push_registry_subtable_mode(L, key_, nullptr); |
88 | } | 87 | } |
89 | 88 | ||
90 | // ################################################################################################ | 89 | // ################################################################################################# |
91 | |||
92 | /*---=== luaG_dump ===---*/ | ||
93 | #ifdef _DEBUG | ||
94 | void luaG_dump( lua_State* L) | ||
95 | { | ||
96 | int top = lua_gettop( L); | ||
97 | int i; | ||
98 | |||
99 | fprintf( stderr, "\n\tDEBUG STACK:\n"); | ||
100 | |||
101 | if( top == 0) | ||
102 | fprintf( stderr, "\t(none)\n"); | ||
103 | |||
104 | for( i = 1; i <= top; ++ i) | ||
105 | { | ||
106 | LuaType type{ lua_type_as_enum(L, i) }; | ||
107 | |||
108 | fprintf( stderr, "\t[%d]= (%s) ", i, lua_typename( L, type)); | ||
109 | |||
110 | // Print item contents here... | ||
111 | // | ||
112 | // Note: this requires 'tostring()' to be defined. If it is NOT, | ||
113 | // enable it for more debugging. | ||
114 | // | ||
115 | STACK_CHECK_START_REL(L, 0); | ||
116 | STACK_GROW( L, 2); | ||
117 | |||
118 | lua_getglobal( L, "tostring"); | ||
119 | // | ||
120 | // [-1]: tostring function, or nil | ||
121 | |||
122 | if( !lua_isfunction( L, -1)) | ||
123 | { | ||
124 | fprintf( stderr, "('tostring' not available)"); | ||
125 | } | ||
126 | else | ||
127 | { | ||
128 | lua_pushvalue( L, i); | ||
129 | lua_call( L, 1 /*args*/, 1 /*retvals*/); | ||
130 | |||
131 | // Don't trust the string contents | ||
132 | // | ||
133 | fprintf( stderr, "%s", lua_tostring( L, -1)); | ||
134 | } | ||
135 | lua_pop( L, 1); | ||
136 | STACK_CHECK( L, 0); | ||
137 | fprintf( stderr, "\n"); | ||
138 | } | ||
139 | fprintf( stderr, "\n"); | ||
140 | } | ||
141 | #endif // _DEBUG | ||
142 | |||
143 | // ################################################################################################ | ||
144 | 90 | ||
145 | // same as PUC-Lua l_alloc | 91 | // same as PUC-Lua l_alloc |
146 | extern "C" [[nodiscard]] static void* libc_lua_Alloc([[maybe_unused]] void* ud, [[maybe_unused]] void* ptr_, [[maybe_unused]] size_t osize_, size_t nsize_) | 92 | extern "C" [[nodiscard]] static void* libc_lua_Alloc([[maybe_unused]] void* ud, [[maybe_unused]] void* ptr_, [[maybe_unused]] size_t osize_, size_t nsize_) |
@@ -231,7 +177,7 @@ void initialize_allocator_function(Universe* U, lua_State* L) | |||
231 | STACK_CHECK(L, 1); | 177 | STACK_CHECK(L, 1); |
232 | } | 178 | } |
233 | 179 | ||
234 | // ################################################################################################ | 180 | // ################################################################################################# |
235 | 181 | ||
236 | [[nodiscard]] static int dummy_writer(lua_State* L, void const* p, size_t sz, void* ud) | 182 | [[nodiscard]] static int dummy_writer(lua_State* L, void const* p, size_t sz, void* ud) |
237 | { | 183 | { |
@@ -239,7 +185,6 @@ void initialize_allocator_function(Universe* U, lua_State* L) | |||
239 | return 666; | 185 | return 666; |
240 | } | 186 | } |
241 | 187 | ||
242 | |||
243 | /* | 188 | /* |
244 | * differentiation between C, bytecode and JIT-fast functions | 189 | * differentiation between C, bytecode and JIT-fast functions |
245 | * | 190 | * |
@@ -262,25 +207,25 @@ enum FuncSubType | |||
262 | FST_FastJIT | 207 | FST_FastJIT |
263 | } ; | 208 | } ; |
264 | 209 | ||
265 | FuncSubType luaG_getfuncsubtype( lua_State *L, int _i) | 210 | FuncSubType luaG_getfuncsubtype(lua_State* L, int _i) |
266 | { | 211 | { |
267 | if( lua_tocfunction( L, _i)) | 212 | if (lua_tocfunction(L, _i)) // nullptr for LuaJIT-fast && bytecode functions |
268 | { | 213 | { |
269 | return FST_Native; | 214 | return FST_Native; |
270 | } | 215 | } |
271 | { | 216 | { |
272 | int mustpush = 0, dumpres; | 217 | int mustpush{ 0 }; |
273 | if( lua_absindex( L, _i) != lua_gettop( L)) | 218 | if (lua_absindex(L, _i) != lua_gettop(L)) |
274 | { | 219 | { |
275 | lua_pushvalue( L, _i); | 220 | lua_pushvalue(L, _i); |
276 | mustpush = 1; | 221 | mustpush = 1; |
277 | } | 222 | } |
278 | // the provided writer fails with code 666 | 223 | // the provided writer fails with code 666 |
279 | // therefore, anytime we get 666, this means that lua_dump() attempted a dump | 224 | // therefore, anytime we get 666, this means that lua_dump() attempted a dump |
280 | // all other cases mean this is either a C or LuaJIT-fast function | 225 | // all other cases mean this is either a C or LuaJIT-fast function |
281 | dumpres = lua504_dump(L, dummy_writer, nullptr, 0); | 226 | int const dumpres{ lua504_dump(L, dummy_writer, nullptr, 0) }; |
282 | lua_pop( L, mustpush); | 227 | lua_pop(L, mustpush); |
283 | if( dumpres == 666) | 228 | if (dumpres == 666) |
284 | { | 229 | { |
285 | return FST_Bytecode; | 230 | return FST_Bytecode; |
286 | } | 231 | } |
@@ -290,40 +235,28 @@ FuncSubType luaG_getfuncsubtype( lua_State *L, int _i) | |||
290 | 235 | ||
291 | // ################################################################################################# | 236 | // ################################################################################################# |
292 | 237 | ||
293 | [[nodiscard]] static lua_CFunction luaG_tocfunction(lua_State* L, int _i, FuncSubType* _out) | ||
294 | { | ||
295 | lua_CFunction p = lua_tocfunction( L, _i); | ||
296 | *_out = luaG_getfuncsubtype( L, _i); | ||
297 | return p; | ||
298 | } | ||
299 | |||
300 | // crc64/we of string "LOOKUPCACHE_REGKEY" generated at http://www.nitrxgen.net/hashgen/ | ||
301 | static constexpr UniqueKey LOOKUPCACHE_REGKEY{ 0x837a68dfc6fcb716ull }; | ||
302 | |||
303 | // ################################################################################################# | ||
304 | |||
305 | // inspired from tconcat() in ltablib.c | 238 | // inspired from tconcat() in ltablib.c |
306 | [[nodiscard]] static char const* luaG_pushFQN(lua_State* L, int t, int last, size_t* length) | 239 | [[nodiscard]] static char const* luaG_pushFQN(lua_State* L, int t, int last, size_t* length) |
307 | { | 240 | { |
308 | int i = 1; | ||
309 | luaL_Buffer b; | 241 | luaL_Buffer b; |
310 | STACK_CHECK_START_REL(L, 0); | 242 | STACK_CHECK_START_REL(L, 0); |
311 | // Lua 5.4 pushes &b as light userdata on the stack. be aware of it... | 243 | // Lua 5.4 pushes &b as light userdata on the stack. be aware of it... |
312 | luaL_buffinit( L, &b); // ... {} ... &b? | 244 | luaL_buffinit(L, &b); // ... {} ... &b? |
313 | for( ; i < last; ++ i) | 245 | int i = 1; |
246 | for (; i < last; ++i) | ||
314 | { | 247 | { |
315 | lua_rawgeti( L, t, i); | 248 | lua_rawgeti( L, t, i); |
316 | luaL_addvalue( &b); | 249 | luaL_addvalue( &b); |
317 | luaL_addlstring(&b, "/", 1); | 250 | luaL_addlstring(&b, "/", 1); |
318 | } | 251 | } |
319 | if( i == last) // add last value (if interval was not empty) | 252 | if (i == last) // add last value (if interval was not empty) |
320 | { | 253 | { |
321 | lua_rawgeti( L, t, i); | 254 | lua_rawgeti(L, t, i); |
322 | luaL_addvalue( &b); | 255 | luaL_addvalue(&b); |
323 | } | 256 | } |
324 | // &b is popped at that point (-> replaced by the result) | 257 | // &b is popped at that point (-> replaced by the result) |
325 | luaL_pushresult( &b); // ... {} ... "<result>" | 258 | luaL_pushresult(&b); // ... {} ... "<result>" |
326 | STACK_CHECK( L, 1); | 259 | STACK_CHECK(L, 1); |
327 | return lua_tolstring( L, -1, length); | 260 | return lua_tolstring( L, -1, length); |
328 | } | 261 | } |
329 | 262 | ||
@@ -337,12 +270,12 @@ static constexpr UniqueKey LOOKUPCACHE_REGKEY{ 0x837a68dfc6fcb716ull }; | |||
337 | * if we already had an entry of type [o] = ..., replace the name if the new one is shorter | 270 | * if we already had an entry of type [o] = ..., replace the name if the new one is shorter |
338 | * pops the processed object from the stack | 271 | * pops the processed object from the stack |
339 | */ | 272 | */ |
340 | static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L, int _ctx_base, int _depth) | 273 | static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, int _ctx_base, int _depth) |
341 | { | 274 | { |
342 | // slot 1 in the stack contains the table that receives everything we found | 275 | // slot 1 in the stack contains the table that receives everything we found |
343 | int const dest = _ctx_base; | 276 | int const dest{ _ctx_base }; |
344 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i | 277 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i |
345 | int const fqn = _ctx_base + 1; | 278 | int const fqn{ _ctx_base + 1 }; |
346 | 279 | ||
347 | size_t prevNameLength, newNameLength; | 280 | size_t prevNameLength, newNameLength; |
348 | char const* prevName; | 281 | char const* prevName; |
@@ -352,16 +285,16 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L | |||
352 | 285 | ||
353 | STACK_CHECK_START_REL(L, 0); | 286 | STACK_CHECK_START_REL(L, 0); |
354 | // first, raise an error if the function is already known | 287 | // first, raise an error if the function is already known |
355 | lua_pushvalue( L, -1); // ... {bfc} k o o | 288 | lua_pushvalue(L, -1); // ... {bfc} k o o |
356 | lua_rawget( L, dest); // ... {bfc} k o name? | 289 | lua_rawget(L, dest); // ... {bfc} k o name? |
357 | prevName = lua_tolstring( L, -1, &prevNameLength); // nullptr if we got nil (first encounter of this object) | 290 | prevName = lua_tolstring( L, -1, &prevNameLength); // nullptr if we got nil (first encounter of this object) |
358 | // push name in fqn stack (note that concatenation will crash if name is a not string or a number) | 291 | // push name in fqn stack (note that concatenation will crash if name is a not string or a number) |
359 | lua_pushvalue( L, -3); // ... {bfc} k o name? k | 292 | lua_pushvalue(L, -3); // ... {bfc} k o name? k |
360 | ASSERT_L( lua_type( L, -1) == LUA_TNUMBER || lua_type( L, -1) == LUA_TSTRING); | 293 | ASSERT_L(lua_type(L, -1) == LUA_TNUMBER || lua_type(L, -1) == LUA_TSTRING); |
361 | ++ _depth; | 294 | ++_depth; |
362 | lua_rawseti( L, fqn, _depth); // ... {bfc} k o name? | 295 | lua_rawseti(L, fqn, _depth); // ... {bfc} k o name? |
363 | // generate name | 296 | // generate name |
364 | DEBUGSPEW_OR_NOT(newName, std::ignore) = luaG_pushFQN(L, fqn, _depth, &newNameLength);// ... {bfc} k o name? "f.q.n" | 297 | DEBUGSPEW_OR_NOT(newName, std::ignore) = luaG_pushFQN(L, fqn, _depth, &newNameLength); // ... {bfc} k o name? "f.q.n" |
365 | // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order | 298 | // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order |
366 | // on different VMs even when the tables are populated the exact same way. | 299 | // on different VMs even when the tables are populated the exact same way. |
367 | // When Lua is built with compatibility options (such as LUA_COMPAT_ALL), | 300 | // When Lua is built with compatibility options (such as LUA_COMPAT_ALL), |
@@ -375,36 +308,36 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L | |||
375 | { | 308 | { |
376 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -3)), newName, prevName)); | 309 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -3)), newName, prevName)); |
377 | // the previous name is 'smaller' than the one we just generated: keep it! | 310 | // the previous name is 'smaller' than the one we just generated: keep it! |
378 | lua_pop( L, 3); // ... {bfc} k | 311 | lua_pop(L, 3); // ... {bfc} k |
379 | } | 312 | } |
380 | else | 313 | else |
381 | { | 314 | { |
382 | // the name we generated is either the first one, or a better fit for our purposes | 315 | // the name we generated is either the first one, or a better fit for our purposes |
383 | if( prevName) | 316 | if (prevName) |
384 | { | 317 | { |
385 | // clear the previous name for the database to avoid clutter | 318 | // clear the previous name for the database to avoid clutter |
386 | lua_insert( L, -2); // ... {bfc} k o "f.q.n" prevName | 319 | lua_insert(L, -2); // ... {bfc} k o "f.q.n" prevName |
387 | // t[prevName] = nil | 320 | // t[prevName] = nil |
388 | lua_pushnil( L); // ... {bfc} k o "f.q.n" prevName nil | 321 | lua_pushnil(L); // ... {bfc} k o "f.q.n" prevName nil |
389 | lua_rawset( L, dest); // ... {bfc} k o "f.q.n" | 322 | lua_rawset(L, dest); // ... {bfc} k o "f.q.n" |
390 | } | 323 | } |
391 | else | 324 | else |
392 | { | 325 | { |
393 | lua_remove( L, -2); // ... {bfc} k o "f.q.n" | 326 | lua_remove(L, -2); // ... {bfc} k o "f.q.n" |
394 | } | 327 | } |
395 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -2)), newName)); | 328 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END, lua_typename(L, lua_type( L, -2)), newName)); |
396 | // prepare the stack for database feed | 329 | // prepare the stack for database feed |
397 | lua_pushvalue( L, -1); // ... {bfc} k o "f.q.n" "f.q.n" | 330 | lua_pushvalue(L, -1); // ... {bfc} k o "f.q.n" "f.q.n" |
398 | lua_pushvalue( L, -3); // ... {bfc} k o "f.q.n" "f.q.n" o | 331 | lua_pushvalue(L, -3); // ... {bfc} k o "f.q.n" "f.q.n" o |
399 | ASSERT_L( lua_rawequal( L, -1, -4)); | 332 | ASSERT_L(lua_rawequal(L, -1, -4)); |
400 | ASSERT_L( lua_rawequal( L, -2, -3)); | 333 | ASSERT_L(lua_rawequal(L, -2, -3)); |
401 | // t["f.q.n"] = o | 334 | // t["f.q.n"] = o |
402 | lua_rawset( L, dest); // ... {bfc} k o "f.q.n" | 335 | lua_rawset(L, dest); // ... {bfc} k o "f.q.n" |
403 | // t[o] = "f.q.n" | 336 | // t[o] = "f.q.n" |
404 | lua_rawset( L, dest); // ... {bfc} k | 337 | lua_rawset(L, dest); // ... {bfc} k |
405 | // remove table name from fqn stack | 338 | // remove table name from fqn stack |
406 | lua_pushnil( L); // ... {bfc} k nil | 339 | lua_pushnil(L); // ... {bfc} k nil |
407 | lua_rawseti( L, fqn, _depth); // ... {bfc} k | 340 | lua_rawseti(L, fqn, _depth); // ... {bfc} k |
408 | } | 341 | } |
409 | -- _depth; | 342 | -- _depth; |
410 | STACK_CHECK(L, -1); | 343 | STACK_CHECK(L, -1); |
@@ -414,122 +347,121 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L | |||
414 | 347 | ||
415 | static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, int _ctx_base, int _i, int _depth) | 348 | static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, int _ctx_base, int _i, int _depth) |
416 | { | 349 | { |
417 | lua_Integer visit_count; | ||
418 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i | 350 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i |
419 | int const fqn = _ctx_base + 1; | 351 | int const fqn = _ctx_base + 1; |
420 | // slot 3 contains a cache that stores all already visited tables to avoid infinite recursion loops | 352 | // slot 3 contains a cache that stores all already visited tables to avoid infinite recursion loops |
421 | int const cache = _ctx_base + 2; | 353 | int const cache = _ctx_base + 2; |
422 | // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search) | 354 | // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search) |
423 | int const breadth_first_cache = lua_gettop( L) + 1; | 355 | int const breadth_first_cache = lua_gettop(L) + 1; |
424 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "populate_func_lookup_table_recur()\n" INDENT_END)); | 356 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "populate_func_lookup_table_recur()\n" INDENT_END)); |
425 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); | 357 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); |
426 | 358 | ||
427 | STACK_GROW( L, 6); | 359 | STACK_GROW(L, 6); |
428 | // slot _i contains a table where we search for functions (or a full userdata with a metatable) | 360 | // slot _i contains a table where we search for functions (or a full userdata with a metatable) |
429 | STACK_CHECK_START_REL(L, 0); // ... {_i} | 361 | STACK_CHECK_START_REL(L, 0); // ... {_i} |
430 | 362 | ||
431 | // if object is a userdata, replace it by its metatable | 363 | // if object is a userdata, replace it by its metatable |
432 | if( lua_type( L, _i) == LUA_TUSERDATA) | 364 | if (lua_type(L, _i) == LUA_TUSERDATA) |
433 | { | 365 | { |
434 | lua_getmetatable( L, _i); // ... {_i} mt | 366 | lua_getmetatable(L, _i); // ... {_i} mt |
435 | lua_replace( L, _i); // ... {_i} | 367 | lua_replace(L, _i); // ... {_i} |
436 | } | 368 | } |
437 | 369 | ||
438 | // if table is already visited, we are done | 370 | // if table is already visited, we are done |
439 | lua_pushvalue( L, _i); // ... {_i} {} | 371 | lua_pushvalue(L, _i); // ... {_i} {} |
440 | lua_rawget( L, cache); // ... {_i} nil|n | 372 | lua_rawget(L, cache); // ... {_i} nil|n |
441 | visit_count = lua_tointeger( L, -1); // 0 if nil, else n | 373 | lua_Integer visit_count{ lua_tointeger(L, -1) }; // 0 if nil, else n |
442 | lua_pop( L, 1); // ... {_i} | 374 | lua_pop(L, 1); // ... {_i} |
443 | STACK_CHECK( L, 0); | 375 | STACK_CHECK(L, 0); |
444 | if( visit_count > 0) | 376 | if (visit_count > 0) |
445 | { | 377 | { |
446 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "already visited\n" INDENT_END)); | 378 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "already visited\n" INDENT_END)); |
447 | return; | 379 | return; |
448 | } | 380 | } |
449 | 381 | ||
450 | // remember we visited this table (1-visit count) | 382 | // remember we visited this table (1-visit count) |
451 | lua_pushvalue( L, _i); // ... {_i} {} | 383 | lua_pushvalue(L, _i); // ... {_i} {} |
452 | lua_pushinteger( L, visit_count + 1); // ... {_i} {} 1 | 384 | lua_pushinteger(L, visit_count + 1); // ... {_i} {} 1 |
453 | lua_rawset( L, cache); // ... {_i} | 385 | lua_rawset(L, cache); // ... {_i} |
454 | STACK_CHECK( L, 0); | 386 | STACK_CHECK(L, 0); |
455 | 387 | ||
456 | // this table is at breadth_first_cache index | 388 | // this table is at breadth_first_cache index |
457 | lua_newtable( L); // ... {_i} {bfc} | 389 | lua_newtable(L); // ... {_i} {bfc} |
458 | ASSERT_L( lua_gettop( L) == breadth_first_cache); | 390 | ASSERT_L( lua_gettop(L) == breadth_first_cache); |
459 | // iterate over all entries in the processed table | 391 | // iterate over all entries in the processed table |
460 | lua_pushnil( L); // ... {_i} {bfc} nil | 392 | lua_pushnil(L); // ... {_i} {bfc} nil |
461 | while( lua_next( L, _i) != 0) // ... {_i} {bfc} k v | 393 | while( lua_next(L, _i) != 0) // ... {_i} {bfc} k v |
462 | { | 394 | { |
463 | // just for debug, not actually needed | 395 | // just for debug, not actually needed |
464 | //char const* key = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : "not a string"; | 396 | //char const* key = (lua_type(L, -2) == LUA_TSTRING) ? lua_tostring(L, -2) : "not a string"; |
465 | // subtable: process it recursively | 397 | // subtable: process it recursively |
466 | if( lua_istable( L, -1)) // ... {_i} {bfc} k {} | 398 | if (lua_istable(L, -1)) // ... {_i} {bfc} k {} |
467 | { | 399 | { |
468 | // increment visit count to make sure we will actually scan it at this recursive level | 400 | // increment visit count to make sure we will actually scan it at this recursive level |
469 | lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} | 401 | lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {} |
470 | lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} {} | 402 | lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {} {} |
471 | lua_rawget( L, cache); // ... {_i} {bfc} k {} {} n? | 403 | lua_rawget(L, cache); // ... {_i} {bfc} k {} {} n? |
472 | visit_count = lua_tointeger( L, -1) + 1; // 1 if we got nil, else n+1 | 404 | visit_count = lua_tointeger(L, -1) + 1; // 1 if we got nil, else n+1 |
473 | lua_pop( L, 1); // ... {_i} {bfc} k {} {} | 405 | lua_pop(L, 1); // ... {_i} {bfc} k {} {} |
474 | lua_pushinteger( L, visit_count); // ... {_i} {bfc} k {} {} n | 406 | lua_pushinteger(L, visit_count); // ... {_i} {bfc} k {} {} n |
475 | lua_rawset( L, cache); // ... {_i} {bfc} k {} | 407 | lua_rawset(L, cache); // ... {_i} {bfc} k {} |
476 | // store the table in the breadth-first cache | 408 | // store the table in the breadth-first cache |
477 | lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k | 409 | lua_pushvalue(L, -2); // ... {_i} {bfc} k {} k |
478 | lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k {} | 410 | lua_pushvalue(L, -2); // ... {_i} {bfc} k {} k {} |
479 | lua_rawset( L, breadth_first_cache); // ... {_i} {bfc} k {} | 411 | lua_rawset(L, breadth_first_cache); // ... {_i} {bfc} k {} |
480 | // generate a name, and if we already had one name, keep whichever is the shorter | 412 | // generate a name, and if we already had one name, keep whichever is the shorter |
481 | update_lookup_entry( DEBUGSPEW_PARAM_COMMA( U) L, _ctx_base, _depth); // ... {_i} {bfc} k | 413 | update_lookup_entry( DEBUGSPEW_PARAM_COMMA(U) L, _ctx_base, _depth); // ... {_i} {bfc} k |
482 | } | 414 | } |
483 | else if( lua_isfunction( L, -1) && (luaG_getfuncsubtype( L, -1) != FST_Bytecode)) // ... {_i} {bfc} k func | 415 | else if (lua_isfunction(L, -1) && (luaG_getfuncsubtype(L, -1) != FST_Bytecode)) // ... {_i} {bfc} k func |
484 | { | 416 | { |
485 | // generate a name, and if we already had one name, keep whichever is the shorter | 417 | // generate a name, and if we already had one name, keep whichever is the shorter |
486 | update_lookup_entry( DEBUGSPEW_PARAM_COMMA( U) L, _ctx_base, _depth); // ... {_i} {bfc} k | 418 | update_lookup_entry( DEBUGSPEW_PARAM_COMMA(U) L, _ctx_base, _depth); // ... {_i} {bfc} k |
487 | } | 419 | } |
488 | else | 420 | else |
489 | { | 421 | { |
490 | lua_pop( L, 1); // ... {_i} {bfc} k | 422 | lua_pop(L, 1); // ... {_i} {bfc} k |
491 | } | 423 | } |
492 | STACK_CHECK( L, 2); | 424 | STACK_CHECK(L, 2); |
493 | } | 425 | } |
494 | // now process the tables we encountered at that depth | 426 | // now process the tables we encountered at that depth |
495 | ++ _depth; | 427 | ++ _depth; |
496 | lua_pushnil( L); // ... {_i} {bfc} nil | 428 | lua_pushnil(L); // ... {_i} {bfc} nil |
497 | while( lua_next( L, breadth_first_cache) != 0) // ... {_i} {bfc} k {} | 429 | while (lua_next(L, breadth_first_cache) != 0) // ... {_i} {bfc} k {} |
498 | { | 430 | { |
499 | DEBUGSPEW_CODE( char const* key = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : "not a string"); | 431 | DEBUGSPEW_CODE(char const* key = (lua_type(L, -2) == LUA_TSTRING) ? lua_tostring(L, -2) : "not a string"); |
500 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "table '%s'\n" INDENT_END, key)); | 432 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "table '%s'\n" INDENT_END, key)); |
501 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); | 433 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); |
502 | // un-visit this table in case we do need to process it | 434 | // un-visit this table in case we do need to process it |
503 | lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} | 435 | lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {} |
504 | lua_rawget( L, cache); // ... {_i} {bfc} k {} n | 436 | lua_rawget(L, cache); // ... {_i} {bfc} k {} n |
505 | ASSERT_L( lua_type( L, -1) == LUA_TNUMBER); | 437 | ASSERT_L(lua_type(L, -1) == LUA_TNUMBER); |
506 | visit_count = lua_tointeger( L, -1) - 1; | 438 | visit_count = lua_tointeger(L, -1) - 1; |
507 | lua_pop( L, 1); // ... {_i} {bfc} k {} | 439 | lua_pop(L, 1); // ... {_i} {bfc} k {} |
508 | lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} | 440 | lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {} |
509 | if( visit_count > 0) | 441 | if (visit_count > 0) |
510 | { | 442 | { |
511 | lua_pushinteger( L, visit_count); // ... {_i} {bfc} k {} {} n | 443 | lua_pushinteger(L, visit_count); // ... {_i} {bfc} k {} {} n |
512 | } | 444 | } |
513 | else | 445 | else |
514 | { | 446 | { |
515 | lua_pushnil( L); // ... {_i} {bfc} k {} {} nil | 447 | lua_pushnil(L); // ... {_i} {bfc} k {} {} nil |
516 | } | 448 | } |
517 | lua_rawset( L, cache); // ... {_i} {bfc} k {} | 449 | lua_rawset(L, cache); // ... {_i} {bfc} k {} |
518 | // push table name in fqn stack (note that concatenation will crash if name is a not string!) | 450 | // push table name in fqn stack (note that concatenation will crash if name is a not string!) |
519 | lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k | 451 | lua_pushvalue(L, -2); // ... {_i} {bfc} k {} k |
520 | lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k {} | 452 | lua_rawseti(L, fqn, _depth); // ... {_i} {bfc} k {} |
521 | populate_func_lookup_table_recur( DEBUGSPEW_PARAM_COMMA( U) L, _ctx_base, lua_gettop( L), _depth); | 453 | populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U) L, _ctx_base, lua_gettop(L), _depth); |
522 | lua_pop( L, 1); // ... {_i} {bfc} k | 454 | lua_pop(L, 1); // ... {_i} {bfc} k |
523 | STACK_CHECK( L, 2); | 455 | STACK_CHECK(L, 2); |
524 | } | 456 | } |
525 | // remove table name from fqn stack | 457 | // remove table name from fqn stack |
526 | lua_pushnil( L); // ... {_i} {bfc} nil | 458 | lua_pushnil(L); // ... {_i} {bfc} nil |
527 | lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} | 459 | lua_rawseti(L, fqn, _depth); // ... {_i} {bfc} |
528 | -- _depth; | 460 | -- _depth; |
529 | // we are done with our cache | 461 | // we are done with our cache |
530 | lua_pop( L, 1); // ... {_i} | 462 | lua_pop(L, 1); // ... {_i} |
531 | STACK_CHECK( L, 0); | 463 | STACK_CHECK(L, 0); |
532 | // we are done // ... {_i} {bfc} | 464 | // we are done // ... {_i} {bfc} |
533 | } | 465 | } |
534 | 466 | ||
535 | // ################################################################################################# | 467 | // ################################################################################################# |
@@ -542,59 +474,59 @@ void populate_func_lookup_table(lua_State* L, int i_, char const* name_) | |||
542 | int const ctx_base = lua_gettop(L) + 1; | 474 | int const ctx_base = lua_gettop(L) + 1; |
543 | int const in_base = lua_absindex(L, i_); | 475 | int const in_base = lua_absindex(L, i_); |
544 | int start_depth = 0; | 476 | int start_depth = 0; |
545 | DEBUGSPEW_CODE( Universe* U = universe_get( L)); | 477 | DEBUGSPEW_CODE(Universe* U = universe_get(L)); |
546 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "nullptr")); | 478 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "nullptr")); |
547 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); | 479 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); |
548 | STACK_GROW(L, 3); | 480 | STACK_GROW(L, 3); |
549 | STACK_CHECK_START_REL(L, 0); | 481 | STACK_CHECK_START_REL(L, 0); |
550 | LOOKUP_REGKEY.pushValue(L); // {} | 482 | LOOKUP_REGKEY.pushValue(L); // {} |
551 | STACK_CHECK( L, 1); | 483 | STACK_CHECK(L, 1); |
552 | ASSERT_L( lua_istable( L, -1)); | 484 | ASSERT_L(lua_istable(L, -1)); |
553 | if( lua_type( L, in_base) == LUA_TFUNCTION) // for example when a module is a simple function | 485 | if (lua_type(L, in_base) == LUA_TFUNCTION) // for example when a module is a simple function |
554 | { | 486 | { |
555 | name_ = name_ ? name_ : "nullptr"; | 487 | name_ = name_ ? name_ : "nullptr"; |
556 | lua_pushvalue( L, in_base); // {} f | 488 | lua_pushvalue(L, in_base); // {} f |
557 | lua_pushstring( L, name_); // {} f _name | 489 | lua_pushstring(L, name_); // {} f _name |
558 | lua_rawset( L, -3); // {} | 490 | lua_rawset(L, -3); // {} |
559 | lua_pushstring( L, name_); // {} _name | 491 | lua_pushstring(L, name_); // {} _name |
560 | lua_pushvalue( L, in_base); // {} _name f | 492 | lua_pushvalue(L, in_base); // {} _name f |
561 | lua_rawset( L, -3); // {} | 493 | lua_rawset(L, -3); // {} |
562 | lua_pop( L, 1); // | 494 | lua_pop(L, 1); // |
563 | } | 495 | } |
564 | else if( lua_type( L, in_base) == LUA_TTABLE) | 496 | else if (lua_type(L, in_base) == LUA_TTABLE) |
565 | { | 497 | { |
566 | lua_newtable(L); // {} {fqn} | 498 | lua_newtable(L); // {} {fqn} |
567 | if( name_) | 499 | if (name_) |
568 | { | 500 | { |
569 | STACK_CHECK( L, 2); | 501 | STACK_CHECK(L, 2); |
570 | lua_pushstring( L, name_); // {} {fqn} "name" | 502 | lua_pushstring(L, name_); // {} {fqn} "name" |
571 | // generate a name, and if we already had one name, keep whichever is the shorter | 503 | // generate a name, and if we already had one name, keep whichever is the shorter |
572 | lua_pushvalue( L, in_base); // {} {fqn} "name" t | 504 | lua_pushvalue(L, in_base); // {} {fqn} "name" t |
573 | update_lookup_entry( DEBUGSPEW_PARAM_COMMA( U) L, ctx_base, start_depth); // {} {fqn} "name" | 505 | update_lookup_entry(DEBUGSPEW_PARAM_COMMA(U) L, ctx_base, start_depth); // {} {fqn} "name" |
574 | // don't forget to store the name at the bottom of the fqn stack | 506 | // don't forget to store the name at the bottom of the fqn stack |
575 | ++ start_depth; | 507 | ++ start_depth; |
576 | lua_rawseti( L, -2, start_depth); // {} {fqn} | 508 | lua_rawseti(L, -2, start_depth); // {} {fqn} |
577 | STACK_CHECK( L, 2); | 509 | STACK_CHECK(L, 2); |
578 | } | 510 | } |
579 | // retrieve the cache, create it if we haven't done it yet | 511 | // retrieve the cache, create it if we haven't done it yet |
580 | LOOKUPCACHE_REGKEY.pushValue(L); // {} {fqn} {cache}? | 512 | LOOKUPCACHE_REGKEY.pushValue(L); // {} {fqn} {cache}? |
581 | if( lua_isnil( L, -1)) | 513 | if (lua_isnil(L, -1)) |
582 | { | 514 | { |
583 | lua_pop( L, 1); // {} {fqn} | 515 | lua_pop(L, 1); // {} {fqn} |
584 | lua_newtable( L); // {} {fqn} {cache} | 516 | lua_newtable(L); // {} {fqn} {cache} |
585 | LOOKUPCACHE_REGKEY.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); | 517 | LOOKUPCACHE_REGKEY.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); |
586 | STACK_CHECK( L, 3); | 518 | STACK_CHECK(L, 3); |
587 | } | 519 | } |
588 | // process everything we find in that table, filling in lookup data for all functions and tables we see there | 520 | // process everything we find in that table, filling in lookup data for all functions and tables we see there |
589 | populate_func_lookup_table_recur( DEBUGSPEW_PARAM_COMMA( U) L, ctx_base, in_base, start_depth); | 521 | populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U) L, ctx_base, in_base, start_depth); |
590 | lua_pop( L, 3); | 522 | lua_pop(L, 3); |
591 | } | 523 | } |
592 | else | 524 | else |
593 | { | 525 | { |
594 | lua_pop( L, 1); // | 526 | lua_pop(L, 1); // |
595 | (void) luaL_error( L, "unsupported module type %s", lua_typename( L, lua_type( L, in_base))); | 527 | luaL_error(L, "unsupported module type %s", lua_typename(L, lua_type(L, in_base))); // doesn't return |
596 | } | 528 | } |
597 | STACK_CHECK( L, 0); | 529 | STACK_CHECK(L, 0); |
598 | } | 530 | } |
599 | 531 | ||
600 | // ################################################################################################# | 532 | // ################################################################################################# |
@@ -609,38 +541,34 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
609 | */ | 541 | */ |
610 | [[nodiscard]] static lua_Integer get_mt_id(Universe* U, lua_State* L, int i) | 542 | [[nodiscard]] static lua_Integer get_mt_id(Universe* U, lua_State* L, int i) |
611 | { | 543 | { |
612 | lua_Integer id; | 544 | i = lua_absindex(L, i); |
613 | 545 | ||
614 | i = lua_absindex( L, i); | 546 | STACK_GROW(L, 3); |
615 | |||
616 | STACK_GROW( L, 3); | ||
617 | 547 | ||
618 | STACK_CHECK_START_REL(L, 0); | 548 | STACK_CHECK_START_REL(L, 0); |
619 | push_registry_subtable( L, REG_MTID); // ... _R[REG_MTID] | 549 | push_registry_subtable(L, REG_MTID); // ... _R[REG_MTID] |
620 | lua_pushvalue( L, i); // ... _R[REG_MTID] {mt} | 550 | lua_pushvalue(L, i); // ... _R[REG_MTID] {mt} |
621 | lua_rawget( L, -2); // ... _R[REG_MTID] mtk? | 551 | lua_rawget(L, -2); // ... _R[REG_MTID] mtk? |
622 | 552 | ||
623 | id = lua_tointeger( L, -1); // 0 for nil | 553 | lua_Integer id{ lua_tointeger(L, -1) }; // 0 for nil |
624 | lua_pop( L, 1); // ... _R[REG_MTID] | 554 | lua_pop(L, 1); // ... _R[REG_MTID] |
625 | STACK_CHECK( L, 1); | 555 | STACK_CHECK(L, 1); |
626 | 556 | ||
627 | if( id == 0) | 557 | if (id == 0) |
628 | { | 558 | { |
629 | 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); |
630 | 560 | ||
631 | /* Create two-way references: id_uint <-> table | 561 | // Create two-way references: id_uint <-> table |
632 | */ | 562 | lua_pushvalue(L, i); // ... _R[REG_MTID] {mt} |
633 | lua_pushvalue( L, i); // ... _R[REG_MTID] {mt} | 563 | lua_pushinteger(L, id); // ... _R[REG_MTID] {mt} id |
634 | lua_pushinteger( L, id); // ... _R[REG_MTID] {mt} id | 564 | lua_rawset(L, -3); // ... _R[REG_MTID] |
635 | lua_rawset( L, -3); // ... _R[REG_MTID] | ||
636 | 565 | ||
637 | lua_pushinteger( L, id); // ... _R[REG_MTID] id | 566 | lua_pushinteger(L, id); // ... _R[REG_MTID] id |
638 | lua_pushvalue( L, i); // ... _R[REG_MTID] id {mt} | 567 | lua_pushvalue(L, i); // ... _R[REG_MTID] id {mt} |
639 | lua_rawset( L, -3); // ... _R[REG_MTID] | 568 | lua_rawset(L, -3); // ... _R[REG_MTID] |
640 | } | 569 | } |
641 | lua_pop( L, 1); // ... | 570 | lua_pop(L, 1); // ... |
642 | 571 | STACK_CHECK(L, 0); | |
643 | STACK_CHECK( L, 0); | ||
644 | 572 | ||
645 | return id; | 573 | return id; |
646 | } | 574 | } |
@@ -684,7 +612,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
684 | if (mode_ == LookupMode::FromKeeper) | 612 | if (mode_ == LookupMode::FromKeeper) |
685 | { | 613 | { |
686 | 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! |
687 | 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) |
688 | { | 616 | { |
689 | lua_getupvalue( L, i, 1); // ... v ... "f.q.n" | 617 | lua_getupvalue( L, i, 1); // ... v ... "f.q.n" |
690 | } | 618 | } |
@@ -722,7 +650,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
722 | typewhat = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : luaL_typename( L, -2); | 650 | typewhat = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : luaL_typename( L, -2); |
723 | // second return value can be nil if the table was not found | 651 | // second return value can be nil if the table was not found |
724 | // probable reason: the function was removed from the source Lua state before Lanes was required. | 652 | // probable reason: the function was removed from the source Lua state before Lanes was required. |
725 | if( lua_isnil( L, -1)) | 653 | if (lua_isnil( L, -1)) |
726 | { | 654 | { |
727 | gotchaA = " referenced by"; | 655 | gotchaA = " referenced by"; |
728 | gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)"; | 656 | gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)"; |
@@ -744,22 +672,20 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
744 | 672 | ||
745 | // ################################################################################################# | 673 | // ################################################################################################# |
746 | 674 | ||
747 | /* | 675 | // Push a looked-up table, or nothing if we found nothing |
748 | * Push a looked-up table, or nothing if we found nothing | 676 | [[nodiscard]] bool InterCopyContext::lookup_table() const |
749 | */ | ||
750 | [[nodiscard]] static bool lookup_table(Dest L2, Source L1, SourceIndex i_, LookupMode mode_, char const* upName_) | ||
751 | { | 677 | { |
752 | // get the name of the table we want to send | 678 | // get the name of the table we want to send |
753 | size_t len; | 679 | size_t len; |
754 | char const* fqn = find_lookup_name(L1, i_, mode_, upName_, &len); | 680 | char const* fqn = find_lookup_name(L1, L1_i, mode, name, &len); |
755 | if (nullptr == fqn) // name not found, it is some user-created table | 681 | if (nullptr == fqn) // name not found, it is some user-created table |
756 | { | 682 | { |
757 | return false; | 683 | return false; |
758 | } | 684 | } |
759 | // push the equivalent table in the destination's stack, retrieved from the lookup table | 685 | // push the equivalent table in the destination's stack, retrieved from the lookup table |
760 | STACK_CHECK_START_REL(L2, 0); // L // L2 | 686 | STACK_CHECK_START_REL(L2, 0); // L // L2 |
761 | STACK_GROW( L2, 3); // up to 3 slots are necessary on error | 687 | STACK_GROW(L2, 3); // up to 3 slots are necessary on error |
762 | switch( mode_) | 688 | switch (mode) |
763 | { | 689 | { |
764 | default: // shouldn't happen, in theory... | 690 | default: // shouldn't happen, in theory... |
765 | luaL_error(L1, "internal error: unknown lookup mode"); // doesn't return | 691 | luaL_error(L1, "internal error: unknown lookup mode"); // doesn't return |
@@ -780,7 +706,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
780 | lua_rawget(L2, -2); // {} t | 706 | lua_rawget(L2, -2); // {} t |
781 | // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead) | 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) |
782 | // but not when we extract something out of a keeper, as there is nothing to clone! | 708 | // but not when we extract something out of a keeper, as there is nothing to clone! |
783 | if (lua_isnil(L2, -1) && mode_ == LookupMode::LaneBody) | 709 | if (lua_isnil(L2, -1) && mode == LookupMode::LaneBody) |
784 | { | 710 | { |
785 | lua_pop(L2, 2); // | 711 | lua_pop(L2, 2); // |
786 | STACK_CHECK(L2, 0); | 712 | STACK_CHECK(L2, 0); |
@@ -797,7 +723,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
797 | lua_pop(L2, 1); // {} t | 723 | lua_pop(L2, 1); // {} t |
798 | // 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 | 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 |
799 | luaL_error( | 725 | luaL_error( |
800 | (mode_ == LookupMode::FromKeeper) ? L2 : L1 | 726 | (mode == LookupMode::FromKeeper) ? L2 : L1 |
801 | , "INTERNAL ERROR IN %s: table '%s' not found in %s destination transfer database." | 727 | , "INTERNAL ERROR IN %s: table '%s' not found in %s destination transfer database." |
802 | , from ? from : "main" | 728 | , from ? from : "main" |
803 | , fqn | 729 | , fqn |
@@ -808,7 +734,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
808 | lua_remove(L2, -2); // t | 734 | lua_remove(L2, -2); // t |
809 | break; | 735 | break; |
810 | } | 736 | } |
811 | STACK_CHECK( L2, 1); | 737 | STACK_CHECK(L2, 1); |
812 | return true; | 738 | return true; |
813 | } | 739 | } |
814 | 740 | ||
@@ -877,7 +803,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
877 | lua_pushvalue(L, -1); // o "r" {c} {fqn} ... {?} {?} | 803 | lua_pushvalue(L, -1); // o "r" {c} {fqn} ... {?} {?} |
878 | lua_rawget(L, cache); // o "r" {c} {fqn} ... {?} nil/1 | 804 | lua_rawget(L, cache); // o "r" {c} {fqn} ... {?} nil/1 |
879 | // if table is already visited, we are done | 805 | // if table is already visited, we are done |
880 | if( !lua_isnil(L, -1)) | 806 | if (!lua_isnil(L, -1)) |
881 | { | 807 | { |
882 | lua_pop(L, 1); // o "r" {c} {fqn} ... {?} | 808 | lua_pop(L, 1); // o "r" {c} {fqn} ... {?} |
883 | return shortest_; | 809 | return shortest_; |
@@ -902,7 +828,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
902 | { | 828 | { |
903 | STACK_CHECK(L, 2); | 829 | STACK_CHECK(L, 2); |
904 | // update shortest name | 830 | // update shortest name |
905 | if( depth_ < shortest_) | 831 | if (depth_ < shortest_) |
906 | { | 832 | { |
907 | shortest_ = depth_; | 833 | shortest_ = depth_; |
908 | std::ignore = luaG_pushFQN(L, fqn, depth_, nullptr); // o "r" {c} {fqn} ... {?} k v "fqn" | 834 | std::ignore = luaG_pushFQN(L, fqn, depth_, nullptr); // o "r" {c} {fqn} ... {?} k v "fqn" |
@@ -924,7 +850,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
924 | // search in the table's metatable too | 850 | // search in the table's metatable too |
925 | if (lua_getmetatable(L, -1)) // o "r" {c} {fqn} ... {?} k {} {mt} | 851 | if (lua_getmetatable(L, -1)) // o "r" {c} {fqn} ... {?} k {} {mt} |
926 | { | 852 | { |
927 | if( lua_istable(L, -1)) | 853 | if (lua_istable(L, -1)) |
928 | { | 854 | { |
929 | ++ depth_; | 855 | ++ depth_; |
930 | lua_pushliteral(L, "__metatable"); // o "r" {c} {fqn} ... {?} k {} {mt} "__metatable" | 856 | lua_pushliteral(L, "__metatable"); // o "r" {c} {fqn} ... {?} k {} {mt} "__metatable" |
@@ -966,7 +892,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
966 | int uvi = 1; | 892 | int uvi = 1; |
967 | while (lua_getiuservalue(L, -1, uvi) != LUA_TNONE) // o "r" {c} {fqn} ... {?} k U {u} | 893 | while (lua_getiuservalue(L, -1, uvi) != LUA_TNONE) // o "r" {c} {fqn} ... {?} k U {u} |
968 | { | 894 | { |
969 | 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 |
970 | { | 896 | { |
971 | ++ depth_; | 897 | ++ depth_; |
972 | lua_pushliteral(L, "uservalue"); // o "r" {c} {fqn} ... {?} k v {u} "uservalue" | 898 | lua_pushliteral(L, "uservalue"); // o "r" {c} {fqn} ... {?} k v {u} "uservalue" |
@@ -1010,13 +936,13 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
1010 | int luaG_nameof( lua_State* L) | 936 | int luaG_nameof( lua_State* L) |
1011 | { | 937 | { |
1012 | int what = lua_gettop( L); | 938 | int what = lua_gettop( L); |
1013 | if( what > 1) | 939 | if (what > 1) |
1014 | { | 940 | { |
1015 | luaL_argerror( L, what, "too many arguments."); | 941 | luaL_argerror( L, what, "too many arguments."); |
1016 | } | 942 | } |
1017 | 943 | ||
1018 | // nil, boolean, light userdata, number and string aren't identifiable | 944 | // nil, boolean, light userdata, number and string aren't identifiable |
1019 | if( lua_type( L, 1) < LUA_TTABLE) | 945 | if (lua_type( L, 1) < LUA_TTABLE) |
1020 | { | 946 | { |
1021 | lua_pushstring( L, luaL_typename( L, 1)); // o "type" | 947 | lua_pushstring( L, luaL_typename( L, 1)); // o "type" |
1022 | lua_insert( L, -2); // "type" o | 948 | lua_insert( L, -2); // "type" o |
@@ -1036,7 +962,7 @@ int luaG_nameof( lua_State* L) | |||
1036 | // this is where we start the search | 962 | // this is where we start the search |
1037 | lua_pushglobaltable( L); // o nil {c} {fqn} _G | 963 | lua_pushglobaltable( L); // o nil {c} {fqn} _G |
1038 | (void) discover_object_name_recur( L, 6666, 1); | 964 | (void) discover_object_name_recur( L, 6666, 1); |
1039 | if( lua_isnil( L, 2)) // try again with registry, just in case... | 965 | if (lua_isnil( L, 2)) // try again with registry, just in case... |
1040 | { | 966 | { |
1041 | lua_pop( L, 1); // o nil {c} {fqn} | 967 | lua_pop( L, 1); // o nil {c} {fqn} |
1042 | lua_pushliteral( L, "_R"); // o nil {c} {fqn} "_R" | 968 | lua_pushliteral( L, "_R"); // o nil {c} {fqn} "_R" |
@@ -1056,56 +982,56 @@ int luaG_nameof( lua_State* L) | |||
1056 | /* | 982 | /* |
1057 | * Push a looked-up native/LuaJIT function. | 983 | * Push a looked-up native/LuaJIT function. |
1058 | */ | 984 | */ |
1059 | static void lookup_native_func(lua_State* L2, lua_State* L, int i, LookupMode mode_, char const* upName_) | 985 | void InterCopyContext::lookup_native_func() const |
1060 | { | 986 | { |
1061 | // get the name of the function we want to send | 987 | // get the name of the function we want to send |
1062 | size_t len; | 988 | size_t len; |
1063 | char const* fqn = find_lookup_name( L, i, mode_, upName_, &len); | 989 | char const* fqn = find_lookup_name(L1, L1_i, mode, name, &len); |
1064 | // push the equivalent function in the destination's stack, retrieved from the lookup table | 990 | // push the equivalent function in the destination's stack, retrieved from the lookup table |
1065 | STACK_CHECK_START_REL(L2, 0); // L // L2 | 991 | STACK_CHECK_START_REL(L2, 0); // L1 // L2 |
1066 | STACK_GROW( L2, 3); // up to 3 slots are necessary on error | 992 | STACK_GROW(L2, 3); // up to 3 slots are necessary on error |
1067 | switch( mode_) | 993 | switch (mode) |
1068 | { | 994 | { |
1069 | default: // shouldn't happen, in theory... | 995 | default: // shouldn't happen, in theory... |
1070 | (void) luaL_error( L, "internal error: unknown lookup mode"); | 996 | luaL_error(L1, "internal error: unknown lookup mode"); // doesn't return |
1071 | return; | 997 | break; |
1072 | 998 | ||
1073 | case LookupMode::ToKeeper: | 999 | case LookupMode::ToKeeper: |
1074 | // push a sentinel closure that holds the lookup name as upvalue | 1000 | // push a sentinel closure that holds the lookup name as upvalue |
1075 | lua_pushlstring( L2, fqn, len); // "f.q.n" | 1001 | lua_pushlstring(L2, fqn, len); // "f.q.n" |
1076 | lua_pushcclosure( L2, func_lookup_sentinel, 1); // f | 1002 | lua_pushcclosure(L2, func_lookup_sentinel, 1); // f |
1077 | break; | 1003 | break; |
1078 | 1004 | ||
1079 | case LookupMode::LaneBody: | 1005 | case LookupMode::LaneBody: |
1080 | case LookupMode::FromKeeper: | 1006 | case LookupMode::FromKeeper: |
1081 | LOOKUP_REGKEY.pushValue(L2); // {} | 1007 | LOOKUP_REGKEY.pushValue(L2); // {} |
1082 | STACK_CHECK( L2, 1); | 1008 | STACK_CHECK(L2, 1); |
1083 | ASSERT_L( lua_istable( L2, -1)); | 1009 | _ASSERT_L(L1, lua_istable(L2, -1)); |
1084 | lua_pushlstring( L2, fqn, len); // {} "f.q.n" | 1010 | lua_pushlstring(L2, fqn, len); // {} "f.q.n" |
1085 | lua_rawget( L2, -2); // {} f | 1011 | lua_rawget(L2, -2); // {} f |
1086 | // nil means we don't know how to transfer stuff: user should do something | 1012 | // nil means we don't know how to transfer stuff: user should do something |
1087 | // anything other than function or table should not happen! | 1013 | // anything other than function or table should not happen! |
1088 | if( !lua_isfunction( L2, -1) && !lua_istable( L2, -1)) | 1014 | if (!lua_isfunction( L2, -1) && !lua_istable( L2, -1)) |
1089 | { | 1015 | { |
1090 | char const* from, * to; | 1016 | char const* from, * to; |
1091 | lua_getglobal( L, "decoda_name"); // ... f ... decoda_name | 1017 | lua_getglobal(L1, "decoda_name"); // ... f ... decoda_name |
1092 | from = lua_tostring( L, -1); | 1018 | from = lua_tostring(L1, -1); |
1093 | lua_pop( L, 1); // ... f ... | 1019 | lua_pop(L1, 1); // ... f ... |
1094 | lua_getglobal( L2, "decoda_name"); // {} f decoda_name | 1020 | lua_getglobal(L2, "decoda_name"); // {} f decoda_name |
1095 | to = lua_tostring( L2, -1); | 1021 | to = lua_tostring(L2, -1); |
1096 | lua_pop( L2, 1); // {} f | 1022 | lua_pop(L2, 1); // {} f |
1097 | // 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 | 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 |
1098 | (void) luaL_error( | 1024 | (void) luaL_error( |
1099 | (mode_ == LookupMode::FromKeeper) ? L2 : L | 1025 | (mode == LookupMode::FromKeeper) ? L2 : L1 |
1100 | , "%s%s: function '%s' not found in %s destination transfer database." | 1026 | , "%s%s: function '%s' not found in %s destination transfer database." |
1101 | , lua_isnil( L2, -1) ? "" : "INTERNAL ERROR IN " | 1027 | , lua_isnil(L2, -1) ? "" : "INTERNAL ERROR IN " |
1102 | , from ? from : "main" | 1028 | , from ? from : "main" |
1103 | , fqn | 1029 | , fqn |
1104 | , to ? to : "main" | 1030 | , to ? to : "main" |
1105 | ); | 1031 | ); |
1106 | return; | 1032 | return; |
1107 | } | 1033 | } |
1108 | lua_remove( L2, -2); // f | 1034 | lua_remove(L2, -2); // f |
1109 | break; | 1035 | break; |
1110 | 1036 | ||
1111 | /* keep it in case I need it someday, who knows... | 1037 | /* keep it in case I need it someday, who knows... |
@@ -1115,7 +1041,7 @@ static void lookup_native_func(lua_State* L2, lua_State* L, int i, LookupMode mo | |||
1115 | char const* upname; | 1041 | char const* upname; |
1116 | lua_CFunction f = lua_tocfunction( L, i); | 1042 | lua_CFunction f = lua_tocfunction( L, i); |
1117 | // copy upvalues | 1043 | // copy upvalues |
1118 | for( n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != nullptr; ++ n) | 1044 | for (n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != nullptr; ++ n) |
1119 | { | 1045 | { |
1120 | luaG_inter_move( U, L, L2, 1, mode_); // [up[,up ...]] | 1046 | luaG_inter_move( U, L, L2, 1, mode_); // [up[,up ...]] |
1121 | } | 1047 | } |
@@ -1166,7 +1092,7 @@ static char const* vt_names[] = | |||
1166 | [[nodiscard]] static int buf_writer(lua_State* L, void const* b, size_t size, void* ud) | 1092 | [[nodiscard]] static int buf_writer(lua_State* L, void const* b, size_t size, void* ud) |
1167 | { | 1093 | { |
1168 | luaL_Buffer* B = (luaL_Buffer*) ud; | 1094 | luaL_Buffer* B = (luaL_Buffer*) ud; |
1169 | if( !B->L) | 1095 | if (!B->L) |
1170 | { | 1096 | { |
1171 | luaL_buffinit( L, B); | 1097 | luaL_buffinit( L, B); |
1172 | } | 1098 | } |
@@ -1278,7 +1204,7 @@ void InterCopyContext::copy_func() const | |||
1278 | { // ... _G up[n] | 1204 | { // ... _G up[n] |
1279 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "UPNAME[%d]: %s -> " INDENT_END, n, c.name)); | 1205 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "UPNAME[%d]: %s -> " INDENT_END, n, c.name)); |
1280 | #if LUA_VERSION_NUM >= 502 | 1206 | #if LUA_VERSION_NUM >= 502 |
1281 | if( lua_rawequal(L1, -1, -2)) // is the upvalue equal to the global table? | 1207 | if (lua_rawequal(L1, -1, -2)) // is the upvalue equal to the global table? |
1282 | { | 1208 | { |
1283 | DEBUGSPEW_CODE(fprintf(stderr, "pushing destination global scope\n")); | 1209 | DEBUGSPEW_CODE(fprintf(stderr, "pushing destination global scope\n")); |
1284 | lua_pushglobaltable(L2); // ... {cache} ... function <upvalues> | 1210 | lua_pushglobaltable(L2); // ... {cache} ... function <upvalues> |
@@ -1331,8 +1257,7 @@ void InterCopyContext::copy_func() const | |||
1331 | */ | 1257 | */ |
1332 | void InterCopyContext::copy_cached_func() const | 1258 | void InterCopyContext::copy_cached_func() const |
1333 | { | 1259 | { |
1334 | FuncSubType funcSubType; | 1260 | FuncSubType const funcSubType{ luaG_getfuncsubtype(L1, L1_i) }; |
1335 | std::ignore = luaG_tocfunction(L1, L1_i, &funcSubType); // nullptr for LuaJIT-fast && bytecode functions | ||
1336 | if (funcSubType == FST_Bytecode) | 1261 | if (funcSubType == FST_Bytecode) |
1337 | { | 1262 | { |
1338 | void* const aspointer = const_cast<void*>(lua_topointer(L1, L1_i)); | 1263 | void* const aspointer = const_cast<void*>(lua_topointer(L1, L1_i)); |
@@ -1376,7 +1301,7 @@ void InterCopyContext::copy_cached_func() const | |||
1376 | } | 1301 | } |
1377 | else // function is native/LuaJIT: no need to cache | 1302 | else // function is native/LuaJIT: no need to cache |
1378 | { | 1303 | { |
1379 | lookup_native_func(L2, L1, L1_i, mode, name); // ... {cache} ... function | 1304 | lookup_native_func(); // ... {cache} ... function |
1380 | // if the function was in fact a lookup sentinel, we can either get a function or a table here | 1305 | // if the function was in fact a lookup sentinel, we can either get a function or a table here |
1381 | _ASSERT_L(L1, lua_isfunction(L2, -1) || lua_istable(L2, -1)); | 1306 | _ASSERT_L(L1, lua_isfunction(L2, -1) || lua_istable(L2, -1)); |
1382 | } | 1307 | } |
@@ -1440,7 +1365,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const | |||
1440 | SourceIndex const val_i{ lua_gettop(L1) }; | 1365 | SourceIndex const val_i{ lua_gettop(L1) }; |
1441 | SourceIndex const key_i{ val_i - 1 }; | 1366 | SourceIndex const key_i{ val_i - 1 }; |
1442 | 1367 | ||
1443 | // Only basic key types are copied over; others ignored | 1368 | // For the key, only basic key types are copied over. others ignored |
1444 | InterCopyContext c{ U, L2, L1, L2_cache_i, key_i, VT::KEY, mode, name }; | 1369 | InterCopyContext c{ U, L2, L1, L2_cache_i, key_i, VT::KEY, mode, name }; |
1445 | if (!c.inter_copy_one()) | 1370 | if (!c.inter_copy_one()) |
1446 | { | 1371 | { |
@@ -1451,7 +1376,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const | |||
1451 | } | 1376 | } |
1452 | 1377 | ||
1453 | char* valPath{ nullptr }; | 1378 | char* valPath{ nullptr }; |
1454 | if( U->verboseErrors) | 1379 | if (U->verboseErrors) |
1455 | { | 1380 | { |
1456 | // for debug purposes, let's try to build a useful name | 1381 | // for debug purposes, let's try to build a useful name |
1457 | if (lua_type(L1, key_i) == LUA_TSTRING) | 1382 | if (lua_type(L1, key_i) == LUA_TSTRING) |
@@ -1483,20 +1408,17 @@ void InterCopyContext::inter_copy_keyvaluepair() const | |||
1483 | valPath = (char*) alloca(strlen(name) + 16 + 5); | 1408 | valPath = (char*) alloca(strlen(name) + 16 + 5); |
1484 | sprintf(valPath, "%s[U:%p]", name, key); | 1409 | sprintf(valPath, "%s[U:%p]", name, key); |
1485 | } | 1410 | } |
1486 | else if( lua_type( L1, key_i) == LUA_TBOOLEAN) | 1411 | else if (lua_type( L1, key_i) == LUA_TBOOLEAN) |
1487 | { | 1412 | { |
1488 | int const key{ lua_toboolean(L1, key_i) }; | 1413 | int const key{ lua_toboolean(L1, key_i) }; |
1489 | valPath = (char*) alloca(strlen(name) + 8); | 1414 | valPath = (char*) alloca(strlen(name) + 8); |
1490 | sprintf(valPath, "%s[%s]", name, key ? "true" : "false"); | 1415 | sprintf(valPath, "%s[%s]", name, key ? "true" : "false"); |
1491 | } | 1416 | } |
1492 | } | 1417 | } |
1493 | /* | ||
1494 | * Contents of metatables are copied with cache checking; | ||
1495 | * important to detect loops. | ||
1496 | */ | ||
1497 | c.L1_i = SourceIndex{ val_i }; | 1418 | c.L1_i = SourceIndex{ val_i }; |
1498 | c.name = valPath ? valPath : name; | 1419 | // Contents of metatables are copied with cache checking. important to detect loops. |
1499 | c.vt = VT::NORMAL; | 1420 | c.vt = VT::NORMAL; |
1421 | c.name = valPath ? valPath : name; | ||
1500 | if (c.inter_copy_one()) | 1422 | if (c.inter_copy_one()) |
1501 | { | 1423 | { |
1502 | _ASSERT_L(L1, lua_istable( L2, -3)); | 1424 | _ASSERT_L(L1, lua_istable( L2, -3)); |
@@ -1539,7 +1461,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
1539 | STACK_CHECK(L2, 0); | 1461 | STACK_CHECK(L2, 0); |
1540 | 1462 | ||
1541 | // no metatable? -> not clonable | 1463 | // no metatable? -> not clonable |
1542 | if( !lua_getmetatable(L1, L1_i)) // ... mt? | 1464 | if (!lua_getmetatable(L1, L1_i)) // ... mt? |
1543 | { | 1465 | { |
1544 | STACK_CHECK(L1, 0); | 1466 | STACK_CHECK(L1, 0); |
1545 | return false; | 1467 | return false; |
@@ -1547,7 +1469,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
1547 | 1469 | ||
1548 | // no __lanesclone? -> not clonable | 1470 | // no __lanesclone? -> not clonable |
1549 | lua_getfield(L1, -1, "__lanesclone"); // ... mt __lanesclone? | 1471 | lua_getfield(L1, -1, "__lanesclone"); // ... mt __lanesclone? |
1550 | if( lua_isnil(L1, -1)) | 1472 | if (lua_isnil(L1, -1)) |
1551 | { | 1473 | { |
1552 | lua_pop(L1, 2); // ... | 1474 | lua_pop(L1, 2); // ... |
1553 | STACK_CHECK(L1, 0); | 1475 | STACK_CHECK(L1, 0); |
@@ -1565,12 +1487,12 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
1565 | lua_pop(L1, 1); // ... mt __lanesclone [uv]+ | 1487 | lua_pop(L1, 1); // ... mt __lanesclone [uv]+ |
1566 | -- uvi; | 1488 | -- uvi; |
1567 | // create the clone userdata with the required number of uservalue slots | 1489 | // create the clone userdata with the required number of uservalue slots |
1568 | void* clone = lua_newuserdatauv(L2, userdata_size, uvi); // ... u | 1490 | void* const clone{ lua_newuserdatauv(L2, userdata_size, uvi) }; // ... u |
1569 | // copy the metatable in the target state, and give it to the clone we put there | 1491 | // copy the metatable in the target state, and give it to the clone we put there |
1570 | InterCopyContext c{ U, L2, L1, L2_cache_i, SourceIndex{ mt }, VT::NORMAL, mode, name }; | 1492 | InterCopyContext c{ U, L2, L1, L2_cache_i, SourceIndex{ mt }, VT::NORMAL, mode, name }; |
1571 | if (c.inter_copy_one()) // ... u mt|sentinel | 1493 | if (c.inter_copy_one()) // ... u mt|sentinel |
1572 | { | 1494 | { |
1573 | if( LookupMode::ToKeeper == mode) // ... u sentinel | 1495 | if (LookupMode::ToKeeper == mode) // ... u sentinel |
1574 | { | 1496 | { |
1575 | _ASSERT_L(L1, lua_tocfunction(L2, -1) == table_lookup_sentinel); | 1497 | _ASSERT_L(L1, lua_tocfunction(L2, -1) == table_lookup_sentinel); |
1576 | // we want to create a new closure with a 'clone sentinel' function, where the upvalues are the userdata and the metatable fqn | 1498 | // we want to create a new closure with a 'clone sentinel' function, where the upvalues are the userdata and the metatable fqn |
@@ -1645,7 +1567,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
1645 | } | 1567 | } |
1646 | 1568 | ||
1647 | // try clonable userdata first | 1569 | // try clonable userdata first |
1648 | if( copyclone()) | 1570 | if (copyclone()) |
1649 | { | 1571 | { |
1650 | STACK_CHECK(L1, 0); | 1572 | STACK_CHECK(L1, 0); |
1651 | STACK_CHECK(L2, 1); | 1573 | STACK_CHECK(L2, 1); |
@@ -1714,8 +1636,8 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
1714 | } | 1636 | } |
1715 | lua_pop(L2, 1); // ... | 1637 | lua_pop(L2, 1); // ... |
1716 | 1638 | ||
1717 | // this function has 2 upvalues: the fqn of its metatable, and the userdata itself | 1639 | // userdata_clone_sentinel has 2 upvalues: the fqn of its metatable, and the userdata itself |
1718 | bool const found{ lookup_table(L2, L1, L1_i, mode, name) }; // ... mt? | 1640 | bool const found{ lookup_table() }; // ... mt? |
1719 | if (!found) | 1641 | if (!found) |
1720 | { | 1642 | { |
1721 | STACK_CHECK(L2, 0); | 1643 | STACK_CHECK(L2, 0); |
@@ -1802,7 +1724,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
1802 | * 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?) | 1724 | * 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?) |
1803 | * 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 | 1725 | * 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 |
1804 | */ | 1726 | */ |
1805 | if (lookup_table(L2, L1, L1_i, mode, name)) | 1727 | if (lookup_table()) |
1806 | { | 1728 | { |
1807 | _ASSERT_L(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 | 1729 | _ASSERT_L(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 |
1808 | return true; | 1730 | return true; |
@@ -1849,6 +1771,71 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
1849 | 1771 | ||
1850 | // ################################################################################################# | 1772 | // ################################################################################################# |
1851 | 1773 | ||
1774 | [[nodiscard]] bool InterCopyContext::inter_copy_boolean() const | ||
1775 | { | ||
1776 | int const v{ lua_toboolean(L1, L1_i) }; | ||
1777 | DEBUGSPEW_CODE(fprintf(stderr, "%s\n", v ? "true" : "false")); | ||
1778 | lua_pushboolean(L2, v); | ||
1779 | return true; | ||
1780 | } | ||
1781 | |||
1782 | // ################################################################################################# | ||
1783 | |||
1784 | [[nodiscard]] bool InterCopyContext::inter_copy_lightuserdata() const | ||
1785 | { | ||
1786 | void* const p{ lua_touserdata(L1, L1_i) }; | ||
1787 | DEBUGSPEW_CODE(fprintf(stderr, "%p\n", p)); | ||
1788 | lua_pushlightuserdata(L2, p); | ||
1789 | return true; | ||
1790 | } | ||
1791 | |||
1792 | // ################################################################################################# | ||
1793 | |||
1794 | [[nodiscard]] bool InterCopyContext::inter_copy_nil() const | ||
1795 | { | ||
1796 | if (vt == VT::KEY) | ||
1797 | { | ||
1798 | return false; | ||
1799 | } | ||
1800 | lua_pushnil(L2); | ||
1801 | return true; | ||
1802 | } | ||
1803 | |||
1804 | // ################################################################################################# | ||
1805 | |||
1806 | [[nodiscard]] bool InterCopyContext::inter_copy_number() const | ||
1807 | { | ||
1808 | /* LNUM patch support (keeping integer accuracy) */ | ||
1809 | #if defined LUA_LNUM || LUA_VERSION_NUM >= 503 | ||
1810 | if (lua_isinteger(L1, L1_i)) | ||
1811 | { | ||
1812 | lua_Integer const v{ lua_tointeger(L1, L1_i) }; | ||
1813 | DEBUGSPEW_CODE(fprintf(stderr, LUA_INTEGER_FMT "\n", v)); | ||
1814 | lua_pushinteger(L2, v); | ||
1815 | } | ||
1816 | else | ||
1817 | #endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 | ||
1818 | { | ||
1819 | lua_Number const v{ lua_tonumber(L1, L1_i) }; | ||
1820 | DEBUGSPEW_CODE(fprintf(stderr, LUA_NUMBER_FMT "\n", v)); | ||
1821 | lua_pushnumber(L2, v); | ||
1822 | } | ||
1823 | return true; | ||
1824 | } | ||
1825 | |||
1826 | // ################################################################################################# | ||
1827 | |||
1828 | [[nodiscard]] bool InterCopyContext::inter_copy_string() const | ||
1829 | { | ||
1830 | size_t len; | ||
1831 | char const* const s{ lua_tolstring(L1, L1_i, &len) }; | ||
1832 | DEBUGSPEW_CODE(fprintf(stderr, "'%s'\n", s)); | ||
1833 | lua_pushlstring(L2, s, len); | ||
1834 | return true; | ||
1835 | } | ||
1836 | |||
1837 | // ################################################################################################# | ||
1838 | |||
1852 | /* | 1839 | /* |
1853 | * Copies a value from 'L1' state (at index 'i') to 'L2' state. Does not remove | 1840 | * Copies a value from 'L1' state (at index 'i') to 'L2' state. Does not remove |
1854 | * the original value. | 1841 | * the original value. |
@@ -1878,7 +1865,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
1878 | if (lua_getmetatable(L1, L1_i)) // ... mt | 1865 | if (lua_getmetatable(L1, L1_i)) // ... mt |
1879 | { | 1866 | { |
1880 | lua_getfield(L1, -1, "__lanesignore"); // ... mt ignore? | 1867 | lua_getfield(L1, -1, "__lanesignore"); // ... mt ignore? |
1881 | if( lua_isboolean(L1, -1) && lua_toboolean(L1, -1)) | 1868 | if (lua_isboolean(L1, -1) && lua_toboolean(L1, -1)) |
1882 | { | 1869 | { |
1883 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "__lanesignore -> LUA_TNIL\n" INDENT_END)); | 1870 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "__lanesignore -> LUA_TNIL\n" INDENT_END)); |
1884 | val_type = LuaType::NIL; | 1871 | val_type = LuaType::NIL; |
@@ -1892,81 +1879,21 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
1892 | bool ret{ true }; | 1879 | bool ret{ true }; |
1893 | switch (val_type) | 1880 | switch (val_type) |
1894 | { | 1881 | { |
1895 | /* Basic types allowed both as values, and as table keys */ | 1882 | // Basic types allowed both as values, and as table keys |
1896 | 1883 | case LuaType::BOOLEAN: ret = inter_copy_boolean(); break; | |
1897 | case LuaType::BOOLEAN: | 1884 | case LuaType::NUMBER: ret = inter_copy_number(); break; |
1898 | { | 1885 | case LuaType::STRING: ret = inter_copy_string(); break; |
1899 | int const v{ lua_toboolean(L1, L1_i) }; | 1886 | case LuaType::LIGHTUSERDATA: ret = inter_copy_lightuserdata();break; |
1900 | DEBUGSPEW_CODE( fprintf(stderr, "%s\n", v ? "true" : "false")); | 1887 | |
1901 | lua_pushboolean(L2, v); | 1888 | // The following types are not allowed as table keys |
1902 | } | 1889 | case LuaType::USERDATA: ret = inter_copy_userdata(); break; |
1903 | break; | 1890 | case LuaType::NIL: ret = inter_copy_nil(); break; |
1904 | 1891 | case LuaType::FUNCTION: ret = inter_copy_function(); break; | |
1905 | case LuaType::NUMBER: | 1892 | case LuaType::TABLE: ret = inter_copy_table(); break; |
1906 | /* LNUM patch support (keeping integer accuracy) */ | 1893 | |
1907 | #if defined LUA_LNUM || LUA_VERSION_NUM >= 503 | 1894 | // The following types cannot be copied |
1908 | if( lua_isinteger(L1, L1_i)) | 1895 | case LuaType::CDATA: [[fallthrough]]; |
1909 | { | 1896 | case LuaType::THREAD: ret = false; break; |
1910 | lua_Integer const v{ lua_tointeger(L1, L1_i) }; | ||
1911 | DEBUGSPEW_CODE(fprintf(stderr, LUA_INTEGER_FMT "\n", v)); | ||
1912 | lua_pushinteger(L2, v); | ||
1913 | break; | ||
1914 | } | ||
1915 | else | ||
1916 | #endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 | ||
1917 | { | ||
1918 | lua_Number const v{ lua_tonumber(L1, L1_i) }; | ||
1919 | DEBUGSPEW_CODE(fprintf(stderr, LUA_NUMBER_FMT "\n", v)); | ||
1920 | lua_pushnumber(L2, v); | ||
1921 | } | ||
1922 | break; | ||
1923 | |||
1924 | case LuaType::STRING: | ||
1925 | { | ||
1926 | size_t len; | ||
1927 | char const* const s{ lua_tolstring(L1, L1_i, &len) }; | ||
1928 | DEBUGSPEW_CODE(fprintf(stderr, "'%s'\n", s)); | ||
1929 | lua_pushlstring(L2, s, len); | ||
1930 | } | ||
1931 | break; | ||
1932 | |||
1933 | case LuaType::LIGHTUSERDATA: | ||
1934 | { | ||
1935 | void* const p{ lua_touserdata(L1, L1_i) }; | ||
1936 | DEBUGSPEW_CODE(fprintf(stderr, "%p\n", p)); | ||
1937 | lua_pushlightuserdata(L2, p); | ||
1938 | } | ||
1939 | break; | ||
1940 | |||
1941 | /* The following types are not allowed as table keys */ | ||
1942 | |||
1943 | case LuaType::USERDATA: | ||
1944 | ret = inter_copy_userdata(); | ||
1945 | break; | ||
1946 | |||
1947 | case LuaType::NIL: | ||
1948 | if (vt == VT::KEY) | ||
1949 | { | ||
1950 | ret = false; | ||
1951 | break; | ||
1952 | } | ||
1953 | lua_pushnil( L2); | ||
1954 | break; | ||
1955 | |||
1956 | case LuaType::FUNCTION: | ||
1957 | ret = inter_copy_function(); | ||
1958 | break; | ||
1959 | |||
1960 | case LuaType::TABLE: | ||
1961 | ret = inter_copy_table(); | ||
1962 | break; | ||
1963 | |||
1964 | /* The following types cannot be copied */ | ||
1965 | |||
1966 | case LuaType::CDATA: | ||
1967 | case LuaType::THREAD: | ||
1968 | ret = false; | ||
1969 | break; | ||
1970 | } | 1897 | } |
1971 | 1898 | ||
1972 | STACK_CHECK(L2, ret ? 1 : 0); | 1899 | STACK_CHECK(L2, ret ? 1 : 0); |