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