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