aboutsummaryrefslogtreecommitdiff
path: root/src/tools.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools.cpp')
-rw-r--r--src/tools.cpp1309
1 files changed, 4 insertions, 1305 deletions
diff --git a/src/tools.cpp b/src/tools.cpp
index 73efda9..2623da6 100644
--- a/src/tools.cpp
+++ b/src/tools.cpp
@@ -1,5 +1,6 @@
1/* 1/*
2 * TOOLS.C Copyright (c) 2002-10, Asko Kauppi 2 * TOOLS.CPP Copyright (c) 2002-10, Asko Kauppi
3 * Copyright (C) 2010-24, Benoit Germain
3 * 4 *
4 * Lua tools to support Lanes. 5 * Lua tools to support Lanes.
5 */ 6 */
@@ -8,7 +9,7 @@
8=============================================================================== 9===============================================================================
9 10
10Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com> 11Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com>
11 2011-17 benoit Germain <bnt.germain@gmail.com> 12 2011-24 benoit Germain <bnt.germain@gmail.com>
12 13
13Permission is hereby granted, free of charge, to any person obtaining a copy 14Permission is hereby granted, free of charge, to any person obtaining a copy
14of this software and associated documentation files (the "Software"), to deal 15of this software and associated documentation files (the "Software"), to deal
@@ -42,82 +43,6 @@ static constexpr RegistryUniqueKey kLookupCacheRegKey{ 0x9BF75F84E54B691Bull };
42 43
43// ################################################################################################# 44// #################################################################################################
44 45
45// same as PUC-Lua l_alloc
46extern "C" [[nodiscard]] static void* libc_lua_Alloc([[maybe_unused]] void* ud, [[maybe_unused]] void* ptr_, [[maybe_unused]] size_t osize_, size_t nsize_)
47{
48 if (nsize_ == 0) {
49 free(ptr_);
50 return nullptr;
51 } else {
52 return realloc(ptr_, nsize_);
53 }
54}
55
56// #################################################################################################
57
58[[nodiscard]] static int luaG_provide_protected_allocator(lua_State* L_)
59{
60 Universe* const U{ universe_get(L_) };
61 // push a new full userdata on the stack, giving access to the universe's protected allocator
62 [[maybe_unused]] AllocatorDefinition* const def{ new (L_) AllocatorDefinition{ U->protectedAllocator.makeDefinition() } };
63 return 1;
64}
65
66// #################################################################################################
67
68// called once at the creation of the universe (therefore L is the master Lua state everything originates from)
69// Do I need to disable this when compiling for LuaJIT to prevent issues?
70void initialize_allocator_function(Universe* U_, lua_State* L_)
71{
72 STACK_CHECK_START_REL(L_, 1); // L_: settings
73 lua_getfield(L_, -1, "allocator"); // L_: settings allocator|nil|"protected"
74 if (!lua_isnil(L_, -1)) {
75 // store C function pointer in an internal variable
76 U_->provideAllocator = lua_tocfunction(L_, -1); // L_: settings allocator
77 if (U_->provideAllocator != nullptr) {
78 // make sure the function doesn't have upvalues
79 char const* upname = lua_getupvalue(L_, -1, 1); // L_: settings allocator upval?
80 if (upname != nullptr) { // should be "" for C functions with upvalues if any
81 raise_luaL_error(L_, "config.allocator() shouldn't have upvalues");
82 }
83 // remove this C function from the config table so that it doesn't cause problems
84 // when we transfer the config table in newly created Lua states
85 lua_pushnil(L_); // L_: settings allocator nil
86 lua_setfield(L_, -3, "allocator"); // L_: settings allocator
87 } else if (lua_type(L_, -1) == LUA_TSTRING) { // should be "protected"
88 LUA_ASSERT(L_, strcmp(lua_tostring(L_, -1), "protected") == 0);
89 // set the original allocator to call from inside protection by the mutex
90 U_->protectedAllocator.initFrom(L_);
91 U_->protectedAllocator.installIn(L_);
92 // before a state is created, this function will be called to obtain the allocator
93 U_->provideAllocator = luaG_provide_protected_allocator;
94 }
95 } else {
96 // just grab whatever allocator was provided to lua_newstate
97 U_->protectedAllocator.initFrom(L_);
98 }
99 lua_pop(L_, 1); // L_: settings
100 STACK_CHECK(L_, 1);
101
102 lua_getfield(L_, -1, "internal_allocator"); // L_: settings "libc"|"allocator"
103 {
104 char const* allocator = lua_tostring(L_, -1);
105 if (strcmp(allocator, "libc") == 0) {
106 U_->internalAllocator = AllocatorDefinition{ libc_lua_Alloc, nullptr };
107 } else if (U_->provideAllocator == luaG_provide_protected_allocator) {
108 // user wants mutex protection on the state's allocator. Use protection for our own allocations too, just in case.
109 U_->internalAllocator = U_->protectedAllocator.makeDefinition();
110 } else {
111 // no protection required, just use whatever we have as-is.
112 U_->internalAllocator = U_->protectedAllocator;
113 }
114 }
115 lua_pop(L_, 1); // L_: settings
116 STACK_CHECK(L_, 1);
117}
118
119// #################################################################################################
120
121[[nodiscard]] static int dummy_writer([[maybe_unused]] lua_State* L_, [[maybe_unused]] void const* p_, [[maybe_unused]] size_t sz_, [[maybe_unused]] void* ud_) 46[[nodiscard]] static int dummy_writer([[maybe_unused]] lua_State* L_, [[maybe_unused]] void const* p_, [[maybe_unused]] size_t sz_, [[maybe_unused]] void* ud_)
122{ 47{
123 return 666; 48 return 666;
@@ -138,14 +63,7 @@ void initialize_allocator_function(Universe* U_, lua_State* L_)
138 * +-----------------+----------+------------+----------+ 63 * +-----------------+----------+------------+----------+
139 */ 64 */
140 65
141enum class FuncSubType 66[[nodiscard]] FuncSubType luaG_getfuncsubtype(lua_State* L_, int _i)
142{
143 Bytecode,
144 Native,
145 FastJIT
146};
147
148FuncSubType luaG_getfuncsubtype(lua_State* L_, int _i)
149{ 67{
150 if (lua_tocfunction(L_, _i)) { // nullptr for LuaJIT-fast && bytecode functions 68 if (lua_tocfunction(L_, _i)) { // nullptr for LuaJIT-fast && bytecode functions
151 return FuncSubType::Native; 69 return FuncSubType::Native;
@@ -430,227 +348,6 @@ void populate_func_lookup_table(lua_State* L_, int i_, char const* name_)
430 348
431// ################################################################################################# 349// #################################################################################################
432 350
433/*---=== Inter-state copying ===---*/
434
435// xxh64 of string "kMtIdRegKey" generated at https://www.pelock.com/products/hash-calculator
436static constexpr RegistryUniqueKey kMtIdRegKey{ 0xA8895DCF4EC3FE3Cull };
437
438// get a unique ID for metatable at [i].
439[[nodiscard]] static lua_Integer get_mt_id(Universe* U_, lua_State* L_, int idx_)
440{
441 idx_ = lua_absindex(L_, idx_);
442
443 STACK_GROW(L_, 3);
444
445 STACK_CHECK_START_REL(L_, 0);
446 std::ignore = kMtIdRegKey.getSubTable(L_, 0, 0); // L_: ... _R[kMtIdRegKey]
447 lua_pushvalue(L_, idx_); // L_: ... _R[kMtIdRegKey] {mt}
448 lua_rawget(L_, -2); // L_: ... _R[kMtIdRegKey] mtk?
449
450 lua_Integer id{ lua_tointeger(L_, -1) }; // 0 for nil
451 lua_pop(L_, 1); // L_: ... _R[kMtIdRegKey]
452 STACK_CHECK(L_, 1);
453
454 if (id == 0) {
455 id = U_->nextMetatableId.fetch_add(1, std::memory_order_relaxed);
456
457 // Create two-way references: id_uint <-> table
458 lua_pushvalue(L_, idx_); // L_: ... _R[kMtIdRegKey] {mt}
459 lua_pushinteger(L_, id); // L_: ... _R[kMtIdRegKey] {mt} id
460 lua_rawset(L_, -3); // L_: ... _R[kMtIdRegKey]
461
462 lua_pushinteger(L_, id); // L_: ... _R[kMtIdRegKey] id
463 lua_pushvalue(L_, idx_); // L_: ... _R[kMtIdRegKey] id {mt}
464 lua_rawset(L_, -3); // L_: ... _R[kMtIdRegKey]
465 }
466 lua_pop(L_, 1); // L_: ...
467 STACK_CHECK(L_, 0);
468
469 return id;
470}
471
472// #################################################################################################
473
474// function sentinel used to transfer native functions from/to keeper states
475[[nodiscard]] static int func_lookup_sentinel(lua_State* L_)
476{
477 raise_luaL_error(L_, "function lookup sentinel for %s, should never be called", lua_tostring(L_, lua_upvalueindex(1)));
478}
479
480// #################################################################################################
481
482// function sentinel used to transfer native table from/to keeper states
483[[nodiscard]] static int table_lookup_sentinel(lua_State* L_)
484{
485 raise_luaL_error(L_, "table lookup sentinel for %s, should never be called", lua_tostring(L_, lua_upvalueindex(1)));
486}
487
488// #################################################################################################
489
490// function sentinel used to transfer cloned full userdata from/to keeper states
491[[nodiscard]] static int userdata_clone_sentinel(lua_State* L_)
492{
493 raise_luaL_error(L_, "userdata clone sentinel for %s, should never be called", lua_tostring(L_, lua_upvalueindex(1)));
494}
495
496// #################################################################################################
497
498// retrieve the name of a function/table in the lookup database
499[[nodiscard]] static char const* find_lookup_name(lua_State* L_, int i_, LookupMode mode_, char const* upName_, size_t* len_)
500{
501 LUA_ASSERT(L_, lua_isfunction(L_, i_) || lua_istable(L_, i_)); // L_: ... v ...
502 STACK_CHECK_START_REL(L_, 0);
503 STACK_GROW(L_, 3); // up to 3 slots are necessary on error
504 if (mode_ == LookupMode::FromKeeper) {
505 lua_CFunction f = lua_tocfunction(L_, i_); // should *always* be one of the function sentinels
506 if (f == func_lookup_sentinel || f == table_lookup_sentinel || f == userdata_clone_sentinel) {
507 lua_getupvalue(L_, i_, 1); // L_: ... v ... "f.q.n"
508 } else {
509 // if this is not a sentinel, this is some user-created table we wanted to lookup
510 LUA_ASSERT(L_, nullptr == f && lua_istable(L_, i_));
511 // push anything that will convert to nullptr string
512 lua_pushnil(L_); // L_: ... v ... nil
513 }
514 } else {
515 // fetch the name from the source state's lookup table
516 kLookupRegKey.pushValue(L_); // L_: ... v ... {}
517 STACK_CHECK(L_, 1);
518 LUA_ASSERT(L_, lua_istable(L_, -1));
519 lua_pushvalue(L_, i_); // L_: ... v ... {} v
520 lua_rawget(L_, -2); // L_: ... v ... {} "f.q.n"
521 }
522 char const* fqn{ lua_tolstring(L_, -1, len_) };
523 DEBUGSPEW_CODE(Universe* const U = universe_get(L_));
524 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END(U), fqn));
525 // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database
526 lua_pop(L_, (mode_ == LookupMode::FromKeeper) ? 1 : 2); // L_: ... v ...
527 STACK_CHECK(L_, 0);
528 if (nullptr == fqn && !lua_istable(L_, i_)) { // raise an error if we try to send an unknown function (but not for tables)
529 *len_ = 0; // just in case
530 // try to discover the name of the function we want to send
531 lua_getglobal(L_, "decoda_name"); // L_: ... v ... decoda_name
532 char const* from{ lua_tostring(L_, -1) };
533 lua_pushcfunction(L_, luaG_nameof); // L_: ... v ... decoda_name luaG_nameof
534 lua_pushvalue(L_, i_); // L_: ... v ... decoda_name luaG_nameof t
535 lua_call(L_, 1, 2); // L_: ... v ... decoda_name "type" "name"|nil
536 char const* typewhat{ (lua_type(L_, -2) == LUA_TSTRING) ? lua_tostring(L_, -2) : luaL_typename(L_, -2) };
537 // second return value can be nil if the table was not found
538 // probable reason: the function was removed from the source Lua state before Lanes was required.
539 char const *what, *gotchaA, *gotchaB;
540 if (lua_isnil(L_, -1)) {
541 gotchaA = " referenced by";
542 gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)";
543 what = upName_;
544 } else {
545 gotchaA = "";
546 gotchaB = "";
547 what = (lua_type(L_, -1) == LUA_TSTRING) ? lua_tostring(L_, -1) : luaL_typename(L_, -1);
548 }
549 raise_luaL_error(L_, "%s%s '%s' not found in %s origin transfer database.%s", typewhat, gotchaA, what, from ? from : "main", gotchaB);
550 }
551 STACK_CHECK(L_, 0);
552 return fqn;
553}
554
555// #################################################################################################
556
557// Push a looked-up table, or nothing if we found nothing
558[[nodiscard]] bool InterCopyContext::lookup_table() const
559{
560 // get the name of the table we want to send
561 size_t len;
562 char const* fqn = find_lookup_name(L1, L1_i, mode, name, &len);
563 if (nullptr == fqn) { // name not found, it is some user-created table
564 return false;
565 }
566 // push the equivalent table in the destination's stack, retrieved from the lookup table
567 STACK_CHECK_START_REL(L2, 0);
568 STACK_GROW(L2, 3); // up to 3 slots are necessary on error
569 switch (mode) {
570 default: // shouldn't happen, in theory...
571 raise_luaL_error(getErrL(), "internal error: unknown lookup mode");
572 break;
573
574 case LookupMode::ToKeeper:
575 // push a sentinel closure that holds the lookup name as upvalue
576 lua_pushlstring(L2, fqn, len); // L1: ... t ... L2: "f.q.n"
577 lua_pushcclosure(L2, table_lookup_sentinel, 1); // L1: ... t ... L2: f
578 break;
579
580 case LookupMode::LaneBody:
581 case LookupMode::FromKeeper:
582 kLookupRegKey.pushValue(L2); // L1: ... t ... L2: {}
583 STACK_CHECK(L2, 1);
584 LUA_ASSERT(L1, lua_istable(L2, -1));
585 lua_pushlstring(L2, fqn, len); // L2: {} "f.q.n"
586 lua_rawget(L2, -2); // L2: {} t
587 // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead)
588 // but not when we extract something out of a keeper, as there is nothing to clone!
589 if (lua_isnil(L2, -1) && mode == LookupMode::LaneBody) {
590 lua_pop(L2, 2); // L1: ... t ... L2:
591 STACK_CHECK(L2, 0);
592 return false;
593 } else if (!lua_istable(L2, -1)) { // this can happen if someone decides to replace same already registered item (for a example a standard lib function) with a table
594 lua_getglobal(L1, "decoda_name"); // L1: ... t ... decoda_name
595 char const* from{ lua_tostring(L1, -1) };
596 lua_pop(L1, 1); // L1: ... t ...
597 lua_getglobal(L2, "decoda_name"); // L1: ... t ... L2: {} t decoda_name
598 char const* to{ lua_tostring(L2, -1) };
599 lua_pop(L2, 1); // L1: ... t ... L2: {} t
600 raise_luaL_error(
601 getErrL(),
602 "%s: source table '%s' found as %s in %s destination transfer database.",
603 from ? from : "main",
604 fqn,
605 lua_typename(L2, lua_type_as_enum(L2, -1)),
606 to ? to : "main"
607 );
608 }
609 lua_remove(L2, -2); // L1: ... t ... L2: t
610 break;
611 }
612 STACK_CHECK(L2, 1);
613 return true;
614}
615
616// #################################################################################################
617
618// Check if we've already copied the same table from 'L1', and reuse the old copy. This allows table upvalues shared by multiple
619// local functions to point to the same table, also in the target.
620// Always pushes a table to 'L2'.
621// Returns true if the table was cached (no need to fill it!); false if it's a virgin.
622[[nodiscard]] bool InterCopyContext::push_cached_table() const
623{
624 void const* p{ lua_topointer(L1, L1_i) };
625
626 LUA_ASSERT(L1, L2_cache_i != 0);
627 STACK_GROW(L2, 3);
628 STACK_CHECK_START_REL(L2, 0);
629
630 // We don't need to use the from state ('L1') in ID since the life span
631 // is only for the duration of a copy (both states are locked).
632 // push a light userdata uniquely representing the table
633 lua_pushlightuserdata(L2, const_cast<void*>(p)); // L1: ... t ... L2: ... p
634
635 // fprintf(stderr, "<< ID: %s >>\n", lua_tostring(L2, -1));
636
637 lua_rawget(L2, L2_cache_i); // L1: ... t ... L2: ... {cached|nil}
638 bool const not_found_in_cache{ lua_isnil(L2, -1) };
639 if (not_found_in_cache) {
640 // create a new entry in the cache
641 lua_pop(L2, 1); // L1: ... t ... L2: ...
642 lua_newtable(L2); // L1: ... t ... L2: ... {}
643 lua_pushlightuserdata(L2, const_cast<void*>(p)); // L1: ... t ... L2: ... {} p
644 lua_pushvalue(L2, -2); // L1: ... t ... L2: ... {} p {}
645 lua_rawset(L2, L2_cache_i); // L1: ... t ... L2: ... {}
646 }
647 STACK_CHECK(L2, 1);
648 LUA_ASSERT(L1, lua_istable(L2, -1));
649 return !not_found_in_cache;
650}
651
652// #################################################################################################
653
654// Return some name helping to identify an object 351// Return some name helping to identify an object
655[[nodiscard]] static int DiscoverObjectNameRecur(lua_State* L_, int shortest_, int depth_) 352[[nodiscard]] static int DiscoverObjectNameRecur(lua_State* L_, int shortest_, int depth_)
656{ 353{
@@ -826,1001 +523,3 @@ int luaG_nameof(lua_State* L_)
826 lua_replace(L_, -3); // L_: "type" "result" 523 lua_replace(L_, -3); // L_: "type" "result"
827 return 2; 524 return 2;
828} 525}
829
830// #################################################################################################
831
832// Push a looked-up native/LuaJIT function.
833void InterCopyContext::lookup_native_func() const
834{
835 // get the name of the function we want to send
836 size_t len;
837 char const* const fqn{ find_lookup_name(L1, L1_i, mode, name, &len) };
838 // push the equivalent function in the destination's stack, retrieved from the lookup table
839 STACK_CHECK_START_REL(L2, 0);
840 STACK_GROW(L2, 3); // up to 3 slots are necessary on error
841 switch (mode) {
842 default: // shouldn't happen, in theory...
843 raise_luaL_error(getErrL(), "internal error: unknown lookup mode");
844 break;
845
846 case LookupMode::ToKeeper:
847 // push a sentinel closure that holds the lookup name as upvalue
848 lua_pushlstring(L2, fqn, len); // L1: ... f ... L2: "f.q.n"
849 lua_pushcclosure(L2, func_lookup_sentinel, 1); // L1: ... f ... L2: f
850 break;
851
852 case LookupMode::LaneBody:
853 case LookupMode::FromKeeper:
854 kLookupRegKey.pushValue(L2); // L1: ... f ... L2: {}
855 STACK_CHECK(L2, 1);
856 LUA_ASSERT(L1, lua_istable(L2, -1));
857 lua_pushlstring(L2, fqn, len); // L1: ... f ... L2: {} "f.q.n"
858 lua_rawget(L2, -2); // L1: ... f ... L2: {} f
859 // nil means we don't know how to transfer stuff: user should do something
860 // anything other than function or table should not happen!
861 if (!lua_isfunction(L2, -1) && !lua_istable(L2, -1)) {
862 lua_getglobal(L1, "decoda_name"); // L1: ... f ... decoda_name
863 char const* const from{ lua_tostring(L1, -1) };
864 lua_pop(L1, 1); // L1: ... f ...
865 lua_getglobal(L2, "decoda_name"); // L1: ... f ... L2: {} f decoda_name
866 char const* const to{ lua_tostring(L2, -1) };
867 lua_pop(L2, 1); // L2: {} f
868 // 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
869 raise_luaL_error(
870 getErrL()
871 , "%s%s: function '%s' not found in %s destination transfer database."
872 , lua_isnil(L2, -1) ? "" : "INTERNAL ERROR IN "
873 , from ? from : "main"
874 , fqn
875 , to ? to : "main"
876 );
877 return;
878 }
879 lua_remove(L2, -2); // L2: f
880 break;
881
882 /* keep it in case I need it someday, who knows...
883 case LookupMode::RawFunctions:
884 {
885 int n;
886 char const* upname;
887 lua_CFunction f = lua_tocfunction( L, i);
888 // copy upvalues
889 for (n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != nullptr; ++ n) {
890 luaG_inter_move( U, L, L2, 1, mode_); // L2: [up[,up ...]]
891 }
892 lua_pushcclosure( L2, f, n); // L2:
893 }
894 break;
895 */
896 }
897 STACK_CHECK(L2, 1);
898}
899
900// #################################################################################################
901
902#if USE_DEBUG_SPEW()
903static char const* lua_type_names[] = {
904 "LUA_TNIL"
905 , "LUA_TBOOLEAN"
906 , "LUA_TLIGHTUSERDATA"
907 , "LUA_TNUMBER"
908 , "LUA_TSTRING"
909 , "LUA_TTABLE"
910 , "LUA_TFUNCTION"
911 , "LUA_TUSERDATA"
912 , "LUA_TTHREAD"
913 , "<LUA_NUMTAGS>" // not really a type
914 , "LUA_TJITCDATA" // LuaJIT specific
915};
916static char const* vt_names[] = {
917 "VT::NORMAL"
918 , "VT::KEY"
919 , "VT::METATABLE"
920};
921#endif // USE_DEBUG_SPEW()
922
923// #################################################################################################
924
925// Lua 5.4.3 style of dumping (see lstrlib.c)
926// we have to do it that way because we can't unbalance the stack between buffer operations
927// namely, this means we can't push a function on top of the stack *after* we initialize the buffer!
928// luckily, this also works with earlier Lua versions
929[[nodiscard]] static int buf_writer(lua_State* L_, void const* b_, size_t size_, void* ud_)
930{
931 luaL_Buffer* const B{ static_cast<luaL_Buffer*>(ud_) };
932 if (!B->L) {
933 luaL_buffinit(L_, B);
934 }
935 luaL_addlstring(B, static_cast<char const*>(b_), size_);
936 return 0;
937}
938
939// #################################################################################################
940
941// Copy a function over, which has not been found in the cache.
942// L2 has the cache key for this function at the top of the stack
943void InterCopyContext::copy_func() const
944{
945 LUA_ASSERT(L1, L2_cache_i != 0); // L2: ... {cache} ... p
946 STACK_GROW(L1, 2);
947 STACK_CHECK_START_REL(L1, 0);
948
949 // 'lua_dump()' needs the function at top of stack
950 // if already on top of the stack, no need to push again
951 bool const needToPush{ L1_i != lua_gettop(L1) };
952 if (needToPush) {
953 lua_pushvalue(L1, L1_i); // L1: ... f
954 }
955
956 //
957 // "value returned is the error code returned by the last call
958 // to the writer" (and we only return 0)
959 // not sure this could ever fail but for memory shortage reasons
960 // last parameter is Lua 5.4-specific (no stripping)
961 luaL_Buffer B;
962 B.L = nullptr;
963 if (lua504_dump(L1, buf_writer, &B, 0) != 0) {
964 raise_luaL_error(getErrL(), "internal error: function dump failed.");
965 }
966
967 // pushes dumped string on 'L1'
968 luaL_pushresult(&B); // L1: ... f b
969
970 // if not pushed, no need to pop
971 if (needToPush) {
972 lua_remove(L1, -2); // L1: ... b
973 }
974
975 // transfer the bytecode, then the upvalues, to create a similar closure
976 {
977 char const* fname = nullptr;
978#define LOG_FUNC_INFO 0
979#if LOG_FUNC_INFO
980 // "To get information about a function you push it onto the
981 // stack and start the what string with the character '>'."
982 //
983 {
984 lua_Debug ar;
985 lua_pushvalue(L1, L1_i); // L1: ... b f
986 // fills 'fname' 'namewhat' and 'linedefined', pops function
987 lua_getinfo(L1, ">nS", &ar); // L1: ... b
988 fname = ar.namewhat;
989 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "FNAME: %s @ %d" INDENT_END(U), ar.short_src, ar.linedefined)); // just gives nullptr
990 }
991#endif // LOG_FUNC_INFO
992 {
993 size_t sz;
994 char const* s = lua_tolstring(L1, -1, &sz); // L1: ... b
995 LUA_ASSERT(L1, s && sz);
996 STACK_GROW(L2, 2);
997 // Note: Line numbers seem to be taken precisely from the
998 // original function. 'fname' is not used since the chunk
999 // is precompiled (it seems...).
1000 //
1001 // TBD: Can we get the function's original name through, as well?
1002 //
1003 if (luaL_loadbuffer(L2, s, sz, fname) != 0) { // L2: ... {cache} ... p function
1004 // chunk is precompiled so only LUA_ERRMEM can happen
1005 // "Otherwise, it pushes an error message"
1006 //
1007 STACK_GROW(L1, 1);
1008 raise_luaL_error(getErrL(), "%s: %s", fname, lua_tostring(L2, -1));
1009 }
1010 // remove the dumped string
1011 lua_pop(L1, 1); // ...
1012 // now set the cache as soon as we can.
1013 // this is necessary if one of the function's upvalues references it indirectly
1014 // we need to find it in the cache even if it isn't fully transfered yet
1015 lua_insert(L2, -2); // L2: ... {cache} ... function p
1016 lua_pushvalue(L2, -2); // L2: ... {cache} ... function p function
1017 // cache[p] = function
1018 lua_rawset(L2, L2_cache_i); // L2: ... {cache} ... function
1019 }
1020 STACK_CHECK(L1, 0);
1021
1022 /* push over any upvalues; references to this function will come from
1023 * cache so we don't end up in eternal loop.
1024 * Lua5.2 and Lua5.3: one of the upvalues is _ENV, which we don't want to copy!
1025 * instead, the function shall have LUA_RIDX_GLOBALS taken in the destination state!
1026 */
1027 int n{ 0 };
1028 {
1029 InterCopyContext c{ U, L2, L1, L2_cache_i, {}, VT::NORMAL, mode, {} };
1030#if LUA_VERSION_NUM >= 502
1031 // Starting with Lua 5.2, each Lua function gets its environment as one of its upvalues (named LUA_ENV, aka "_ENV" by default)
1032 // Generally this is LUA_RIDX_GLOBALS, which we don't want to copy from the source to the destination state...
1033 // -> if we encounter an upvalue equal to the global table in the source, bind it to the destination's global table
1034 lua_pushglobaltable(L1); // L1: ... _G
1035#endif // LUA_VERSION_NUM
1036 for (n = 0; (c.name = lua_getupvalue(L1, L1_i, 1 + n)) != nullptr; ++n) { // L1: ... _G up[n]
1037 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "UPNAME[%d]: %s -> " INDENT_END(U), n, c.name));
1038#if LUA_VERSION_NUM >= 502
1039 if (lua_rawequal(L1, -1, -2)) { // is the upvalue equal to the global table?
1040 DEBUGSPEW_CODE(fprintf(stderr, "pushing destination global scope\n"));
1041 lua_pushglobaltable(L2); // L2: ... {cache} ... function <upvalues>
1042 } else
1043#endif // LUA_VERSION_NUM
1044 {
1045 DEBUGSPEW_CODE(fprintf(stderr, "copying value\n"));
1046 c.L1_i = SourceIndex{ lua_gettop(L1) };
1047 if (!c.inter_copy_one()) { // L2: ... {cache} ... function <upvalues>
1048 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1));
1049 }
1050 }
1051 lua_pop(L1, 1); // L1: ... _G
1052 }
1053#if LUA_VERSION_NUM >= 502
1054 lua_pop(L1, 1); // L1: ...
1055#endif // LUA_VERSION_NUM
1056 }
1057 // L2: ... {cache} ... function + 'n' upvalues (>=0)
1058
1059 STACK_CHECK(L1, 0);
1060
1061 // Set upvalues (originally set to 'nil' by 'lua_load')
1062 for (int const func_index{ lua_gettop(L2) - n }; n > 0; --n) {
1063 char const* rc{ lua_setupvalue(L2, func_index, n) }; // L2: ... {cache} ... function
1064 //
1065 // "assigns the value at the top of the stack to the upvalue and returns its name.
1066 // It also pops the value from the stack."
1067
1068 LUA_ASSERT(L1, rc); // not having enough slots?
1069 }
1070 // once all upvalues have been set we are left
1071 // with the function at the top of the stack // L2: ... {cache} ... function
1072 }
1073 STACK_CHECK(L1, 0);
1074}
1075
1076// #################################################################################################
1077
1078// Check if we've already copied the same function from 'L1', and reuse the old copy.
1079// Always pushes a function to 'L2'.
1080void InterCopyContext::copy_cached_func() const
1081{
1082 FuncSubType const funcSubType{ luaG_getfuncsubtype(L1, L1_i) };
1083 if (funcSubType == FuncSubType::Bytecode) {
1084 void* const aspointer = const_cast<void*>(lua_topointer(L1, L1_i));
1085 // TBD: Merge this and same code for tables
1086 LUA_ASSERT(L1, L2_cache_i != 0);
1087
1088 STACK_GROW(L2, 2);
1089
1090 // L2_cache[id_str]= function
1091 //
1092 STACK_CHECK_START_REL(L2, 0);
1093
1094 // We don't need to use the from state ('L1') in ID since the life span
1095 // is only for the duration of a copy (both states are locked).
1096
1097 // push a light userdata uniquely representing the function
1098 lua_pushlightuserdata(L2, aspointer); // L2: ... {cache} ... p
1099
1100 // fprintf( stderr, "<< ID: %s >>\n", lua_tostring( L2, -1));
1101
1102 lua_pushvalue(L2, -1); // L2: ... {cache} ... p p
1103 lua_rawget(L2, L2_cache_i); // L2: ... {cache} ... p function|nil|true
1104
1105 if (lua_isnil(L2, -1)) { // function is unknown
1106 lua_pop(L2, 1); // L2: ... {cache} ... p
1107
1108 // Set to 'true' for the duration of creation; need to find self-references
1109 // via upvalues
1110 //
1111 // pushes a copy of the func, stores a reference in the cache
1112 copy_func(); // L2: ... {cache} ... function
1113 } else { // found function in the cache
1114 lua_remove(L2, -2); // L2: ... {cache} ... function
1115 }
1116 STACK_CHECK(L2, 1);
1117 LUA_ASSERT(L1, lua_isfunction(L2, -1));
1118 } else { // function is native/LuaJIT: no need to cache
1119 lookup_native_func(); // L2: ... {cache} ... function
1120 // if the function was in fact a lookup sentinel, we can either get a function or a table here
1121 LUA_ASSERT(L1, lua_isfunction(L2, -1) || lua_istable(L2, -1));
1122 }
1123}
1124
1125// #################################################################################################
1126
1127[[nodiscard]] bool InterCopyContext::push_cached_metatable() const
1128{
1129 STACK_CHECK_START_REL(L1, 0);
1130 if (!lua_getmetatable(L1, L1_i)) { // L1: ... mt
1131 STACK_CHECK(L1, 0);
1132 return false;
1133 }
1134 STACK_CHECK(L1, 1);
1135
1136 lua_Integer const mt_id{ get_mt_id(U, L1, -1) }; // Unique id for the metatable
1137
1138 STACK_CHECK_START_REL(L2, 0);
1139 STACK_GROW(L2, 4);
1140 // do we already know this metatable?
1141 std::ignore = kMtIdRegKey.getSubTable(L2, 0, 0); // L2: _R[kMtIdRegKey]
1142 lua_pushinteger(L2, mt_id); // L2: _R[kMtIdRegKey] id
1143 lua_rawget(L2, -2); // L2: _R[kMtIdRegKey] mt|nil
1144 STACK_CHECK(L2, 2);
1145
1146 if (lua_isnil(L2, -1)) { // L2 did not know the metatable
1147 lua_pop(L2, 1); // L2: _R[kMtIdRegKey]
1148 InterCopyContext const c{ U, L2, L1, L2_cache_i, SourceIndex{ lua_gettop(L1) }, VT::METATABLE, mode, name };
1149 if (!c.inter_copy_one()) { // L2: _R[kMtIdRegKey] mt?
1150 raise_luaL_error(getErrL(), "Error copying a metatable");
1151 }
1152
1153 STACK_CHECK(L2, 2); // L2: _R[kMtIdRegKey] mt
1154 // mt_id -> metatable
1155 lua_pushinteger(L2, mt_id); // L2: _R[kMtIdRegKey] mt id
1156 lua_pushvalue(L2, -2); // L2: _R[kMtIdRegKey] mt id mt
1157 lua_rawset(L2, -4); // L2: _R[kMtIdRegKey] mt
1158
1159 // metatable -> mt_id
1160 lua_pushvalue(L2, -1); // L2: _R[kMtIdRegKey] mt mt
1161 lua_pushinteger(L2, mt_id); // L2: _R[kMtIdRegKey] mt mt id
1162 lua_rawset(L2, -4); // L2: _R[kMtIdRegKey] mt
1163 STACK_CHECK(L2, 2);
1164 }
1165 lua_remove(L2, -2); // L2: mt
1166
1167 lua_pop(L1, 1); // L1: ...
1168 STACK_CHECK(L2, 1);
1169 STACK_CHECK(L1, 0);
1170 return true;
1171}
1172
1173// #################################################################################################
1174
1175void InterCopyContext::inter_copy_keyvaluepair() const
1176{
1177 SourceIndex const val_i{ lua_gettop(L1) };
1178 SourceIndex const key_i{ val_i - 1 };
1179
1180 // For the key, only basic key types are copied over. others ignored
1181 InterCopyContext c{ U, L2, L1, L2_cache_i, key_i, VT::KEY, mode, name };
1182 if (!c.inter_copy_one()) {
1183 return;
1184 // we could raise an error instead of ignoring the table entry, like so:
1185 // raise_luaL_error(L1, "Unable to copy %s key '%s' because of value is of type '%s'", (vt == VT::NORMAL) ? "table" : "metatable", name, luaL_typename(L1, key_i));
1186 // maybe offer this possibility as a global configuration option, or a linda setting, or as a parameter of the call causing the transfer?
1187 }
1188
1189 char* valPath{ nullptr };
1190 if (U->verboseErrors) {
1191 // for debug purposes, let's try to build a useful name
1192 if (lua_type(L1, key_i) == LUA_TSTRING) {
1193 char const* key{ lua_tostring(L1, key_i) };
1194 size_t const keyRawLen = lua_rawlen(L1, key_i);
1195 size_t const bufLen = strlen(name) + keyRawLen + 2;
1196 valPath = (char*) alloca(bufLen);
1197 sprintf(valPath, "%s.%*s", name, (int) keyRawLen, key);
1198 key = nullptr;
1199 }
1200#if defined LUA_LNUM || LUA_VERSION_NUM >= 503
1201 else if (lua_isinteger(L1, key_i)) {
1202 lua_Integer const key{ lua_tointeger(L1, key_i) };
1203 valPath = (char*) alloca(strlen(name) + 32 + 3);
1204 sprintf(valPath, "%s[" LUA_INTEGER_FMT "]", name, key);
1205 }
1206#endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503
1207 else if (lua_type(L1, key_i) == LUA_TNUMBER) {
1208 lua_Number const key{ lua_tonumber(L1, key_i) };
1209 valPath = (char*) alloca(strlen(name) + 32 + 3);
1210 sprintf(valPath, "%s[" LUA_NUMBER_FMT "]", name, key);
1211 } else if (lua_type(L1, key_i) == LUA_TLIGHTUSERDATA) {
1212 void* const key{ lua_touserdata(L1, key_i) };
1213 valPath = (char*) alloca(strlen(name) + 16 + 5);
1214 sprintf(valPath, "%s[U:%p]", name, key);
1215 } else if (lua_type(L1, key_i) == LUA_TBOOLEAN) {
1216 int const key{ lua_toboolean(L1, key_i) };
1217 valPath = (char*) alloca(strlen(name) + 8);
1218 sprintf(valPath, "%s[%s]", name, key ? "true" : "false");
1219 }
1220 }
1221 c.L1_i = SourceIndex{ val_i };
1222 // Contents of metatables are copied with cache checking. important to detect loops.
1223 c.vt = VT::NORMAL;
1224 c.name = valPath ? valPath : name;
1225 if (c.inter_copy_one()) {
1226 LUA_ASSERT(L1, lua_istable(L2, -3));
1227 lua_rawset(L2, -3); // add to table (pops key & val)
1228 } else {
1229 raise_luaL_error(getErrL(), "Unable to copy %s entry '%s' because of value is of type '%s'", (vt == VT::NORMAL) ? "table" : "metatable", valPath, luaL_typename(L1, val_i));
1230 }
1231}
1232
1233// #################################################################################################
1234
1235[[nodiscard]] bool InterCopyContext::tryCopyClonable() const
1236{
1237 SourceIndex const L1i{ lua_absindex(L1, L1_i) };
1238 void* const source{ lua_touserdata(L1, L1i) };
1239
1240 STACK_CHECK_START_REL(L1, 0);
1241 STACK_CHECK_START_REL(L2, 0);
1242
1243 // Check if the source was already cloned during this copy
1244 lua_pushlightuserdata(L2, source); // L2: ... source
1245 lua_rawget(L2, L2_cache_i); // L2: ... clone?
1246 if (!lua_isnil(L2, -1)) {
1247 STACK_CHECK(L2, 1);
1248 return true;
1249 } else {
1250 lua_pop(L2, 1); // L2: ...
1251 }
1252 STACK_CHECK(L2, 0);
1253
1254 // no metatable? -> not clonable
1255 if (!lua_getmetatable(L1, L1i)) { // L1: ... mt?
1256 STACK_CHECK(L1, 0);
1257 return false;
1258 }
1259
1260 // no __lanesclone? -> not clonable
1261 lua_getfield(L1, -1, "__lanesclone"); // L1: ... mt __lanesclone?
1262 if (lua_isnil(L1, -1)) {
1263 lua_pop(L1, 2); // L1: ...
1264 STACK_CHECK(L1, 0);
1265 return false;
1266 }
1267
1268 // we need to copy over the uservalues of the userdata as well
1269 {
1270 int const mt{ lua_absindex(L1, -2) }; // L1: ... mt __lanesclone
1271 size_t const userdata_size{ lua_rawlen(L1, L1i) };
1272 // extract all the uservalues, but don't transfer them yet
1273 int uvi = 0;
1274 while (lua_getiuservalue(L1, L1i, ++uvi) != LUA_TNONE) {} // L1: ... mt __lanesclone [uv]+ nil
1275 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now
1276 lua_pop(L1, 1); // L1: ... mt __lanesclone [uv]+
1277 --uvi;
1278 // create the clone userdata with the required number of uservalue slots
1279 void* const clone{ lua_newuserdatauv(L2, userdata_size, uvi) }; // L2: ... u
1280 // copy the metatable in the target state, and give it to the clone we put there
1281 InterCopyContext c{ U, L2, L1, L2_cache_i, SourceIndex{ mt }, VT::NORMAL, mode, name };
1282 if (c.inter_copy_one()) { // L2: ... u mt|sentinel
1283 if (LookupMode::ToKeeper == mode) { // L2: ... u sentinel
1284 LUA_ASSERT(L1, lua_tocfunction(L2, -1) == table_lookup_sentinel);
1285 // we want to create a new closure with a 'clone sentinel' function, where the upvalues are the userdata and the metatable fqn
1286 lua_getupvalue(L2, -1, 1); // L2: ... u sentinel fqn
1287 lua_remove(L2, -2); // L2: ... u fqn
1288 lua_insert(L2, -2); // L2: ... fqn u
1289 lua_pushcclosure(L2, userdata_clone_sentinel, 2); // L2: ... userdata_clone_sentinel
1290 } else { // from keeper or direct // L2: ... u mt
1291 LUA_ASSERT(L1, lua_istable(L2, -1));
1292 lua_setmetatable(L2, -2); // L2: ... u
1293 }
1294 STACK_CHECK(L2, 1);
1295 } else {
1296 raise_luaL_error(getErrL(), "Error copying a metatable");
1297 }
1298 // first, add the entry in the cache (at this point it is either the actual userdata or the keeper sentinel
1299 lua_pushlightuserdata(L2, source); // L2: ... u source
1300 lua_pushvalue(L2, -2); // L2: ... u source u
1301 lua_rawset(L2, L2_cache_i); // L2: ... u
1302 // make sure we have the userdata now
1303 if (LookupMode::ToKeeper == mode) { // L2: ... userdata_clone_sentinel
1304 lua_getupvalue(L2, -1, 2); // L2: ... userdata_clone_sentinel u
1305 }
1306 // assign uservalues
1307 while (uvi > 0) {
1308 c.L1_i = SourceIndex{ lua_absindex(L1, -1) };
1309 if (!c.inter_copy_one()) { // L2: ... u uv
1310 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1));
1311 }
1312 lua_pop(L1, 1); // L1: ... mt __lanesclone [uv]*
1313 // this pops the value from the stack
1314 lua_setiuservalue(L2, -2, uvi); // L2: ... u
1315 --uvi;
1316 }
1317 // when we are done, all uservalues are popped from the source stack, and we want only the single transferred value in the destination
1318 if (LookupMode::ToKeeper == mode) { // L2: ... userdata_clone_sentinel u
1319 lua_pop(L2, 1); // L2: ... userdata_clone_sentinel
1320 }
1321 STACK_CHECK(L2, 1);
1322 STACK_CHECK(L1, 2);
1323 // call cloning function in source state to perform the actual memory cloning
1324 lua_pushlightuserdata(L1, clone); // L1: ... mt __lanesclone clone
1325 lua_pushlightuserdata(L1, source); // L1: ... mt __lanesclone clone source
1326 lua_pushinteger(L1, static_cast<lua_Integer>(userdata_size)); // L1: ... mt __lanesclone clone source size
1327 lua_call(L1, 3, 0); // L1: ... mt
1328 STACK_CHECK(L1, 1);
1329 }
1330
1331 STACK_CHECK(L2, 1);
1332 lua_pop(L1, 1); // L1: ...
1333 STACK_CHECK(L1, 0);
1334 return true;
1335}
1336
1337// #################################################################################################
1338
1339[[nodiscard]] bool InterCopyContext::inter_copy_userdata() const
1340{
1341 STACK_CHECK_START_REL(L1, 0);
1342 STACK_CHECK_START_REL(L2, 0);
1343 if (vt == VT::KEY) {
1344 return false;
1345 }
1346
1347 // try clonable userdata first
1348 if (tryCopyClonable()) {
1349 STACK_CHECK(L1, 0);
1350 STACK_CHECK(L2, 1);
1351 return true;
1352 }
1353
1354 STACK_CHECK(L1, 0);
1355 STACK_CHECK(L2, 0);
1356
1357 // Allow only deep userdata entities to be copied across
1358 DEBUGSPEW_CODE(fprintf(stderr, "USERDATA\n"));
1359 if (tryCopyDeep()) {
1360 STACK_CHECK(L1, 0);
1361 STACK_CHECK(L2, 1);
1362 return true;
1363 }
1364
1365 STACK_CHECK(L1, 0);
1366 STACK_CHECK(L2, 0);
1367
1368 // Not a deep or clonable full userdata
1369 if (U->demoteFullUserdata) { // attempt demotion to light userdata
1370 void* const lud{ lua_touserdata(L1, L1_i) };
1371 lua_pushlightuserdata(L2, lud);
1372 } else { // raise an error
1373 raise_luaL_error(getErrL(), "can't copy non-deep full userdata across lanes");
1374 }
1375
1376 STACK_CHECK(L2, 1);
1377 STACK_CHECK(L1, 0);
1378 return true;
1379}
1380
1381// #################################################################################################
1382
1383[[nodiscard]] bool InterCopyContext::inter_copy_function() const
1384{
1385 if (vt == VT::KEY) {
1386 return false;
1387 }
1388
1389 STACK_CHECK_START_REL(L1, 0);
1390 STACK_CHECK_START_REL(L2, 0);
1391 DEBUGSPEW_CODE(fprintf(stderr, "FUNCTION %s\n", name));
1392
1393 if (lua_tocfunction(L1, L1_i) == userdata_clone_sentinel) { // we are actually copying a clonable full userdata from a keeper
1394 // clone the full userdata again
1395
1396 // let's see if we already restored this userdata
1397 lua_getupvalue(L1, L1_i, 2); // L1: ... u
1398 void* source = lua_touserdata(L1, -1);
1399 lua_pushlightuserdata(L2, source); // L2: ... source
1400 lua_rawget(L2, L2_cache_i); // L2: ... u?
1401 if (!lua_isnil(L2, -1)) {
1402 lua_pop(L1, 1); // L1: ...
1403 STACK_CHECK(L1, 0);
1404 STACK_CHECK(L2, 1);
1405 return true;
1406 }
1407 lua_pop(L2, 1); // L2: ...
1408
1409 // userdata_clone_sentinel has 2 upvalues: the fqn of its metatable, and the userdata itself
1410 bool const found{ lookup_table() }; // L2: ... mt?
1411 if (!found) {
1412 STACK_CHECK(L2, 0);
1413 return false;
1414 }
1415 // 'L1_i' slot was the proxy closure, but from now on we operate onthe actual userdata we extracted from it
1416 SourceIndex const source_i{ lua_gettop(L1) };
1417 source = lua_touserdata(L1, -1);
1418 void* clone{ nullptr };
1419 // get the number of bytes to allocate for the clone
1420 size_t const userdata_size{ lua_rawlen(L1, -1) };
1421 {
1422 // extract uservalues (don't transfer them yet)
1423 int uvi = 0;
1424 while (lua_getiuservalue(L1, source_i, ++uvi) != LUA_TNONE) {} // L1: ... u uv
1425 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now
1426 lua_pop(L1, 1); // L1: ... u [uv]*
1427 --uvi;
1428 STACK_CHECK(L1, uvi + 1);
1429 // create the clone userdata with the required number of uservalue slots
1430 clone = lua_newuserdatauv(L2, userdata_size, uvi); // L2: ... mt u
1431 // add it in the cache
1432 lua_pushlightuserdata(L2, source); // L2: ... mt u source
1433 lua_pushvalue(L2, -2); // L2: ... mt u source u
1434 lua_rawset(L2, L2_cache_i); // L2: ... mt u
1435 // set metatable
1436 lua_pushvalue(L2, -2); // L2: ... mt u mt
1437 lua_setmetatable(L2, -2); // L2: ... mt u
1438 // transfer and assign uservalues
1439 InterCopyContext c{ *this };
1440 while (uvi > 0) {
1441 c.L1_i = SourceIndex{ lua_absindex(L1, -1) };
1442 if (!c.inter_copy_one()) { // L2: ... mt u uv
1443 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1));
1444 }
1445 lua_pop(L1, 1); // L1: ... u [uv]*
1446 // this pops the value from the stack
1447 lua_setiuservalue(L2, -2, uvi); // L2: ... mt u
1448 --uvi;
1449 }
1450 // when we are done, all uservalues are popped from the stack, we can pop the source as well
1451 lua_pop(L1, 1); // L1: ...
1452 STACK_CHECK(L1, 0);
1453 STACK_CHECK(L2, 2); // L2: ... mt u
1454 }
1455 // perform the custom cloning part
1456 lua_insert(L2, -2); // L2: ... u mt
1457 // __lanesclone should always exist because we wouldn't be restoring data from a userdata_clone_sentinel closure to begin with
1458 lua_getfield(L2, -1, "__lanesclone"); // L2: ... u mt __lanesclone
1459 lua_remove(L2, -2); // L2: ... u __lanesclone
1460 lua_pushlightuserdata(L2, clone); // L2: ... u __lanesclone clone
1461 lua_pushlightuserdata(L2, source); // L2: ... u __lanesclone clone source
1462 lua_pushinteger(L2, userdata_size); // L2: ... u __lanesclone clone source size
1463 // clone:__lanesclone(dest, source, size)
1464 lua_call(L2, 3, 0); // L2: ... u
1465 } else { // regular function
1466 DEBUGSPEW_CODE(fprintf(stderr, "FUNCTION %s\n", name));
1467 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U });
1468 copy_cached_func(); // L2: ... f
1469 }
1470 STACK_CHECK(L2, 1);
1471 STACK_CHECK(L1, 0);
1472 return true;
1473}
1474
1475// #################################################################################################
1476
1477[[nodiscard]] bool InterCopyContext::inter_copy_table() const
1478{
1479 if (vt == VT::KEY) {
1480 return false;
1481 }
1482
1483 STACK_CHECK_START_REL(L1, 0);
1484 STACK_CHECK_START_REL(L2, 0);
1485 DEBUGSPEW_CODE(fprintf(stderr, "TABLE %s\n", name));
1486
1487 /*
1488 * 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?)
1489 * 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
1490 */
1491 if (lookup_table()) {
1492 LUA_ASSERT(L1, lua_istable(L2, -1) || (lua_tocfunction(L2, -1) == table_lookup_sentinel)); // from lookup data. can also be table_lookup_sentinel if this is a table we know
1493 return true;
1494 }
1495
1496 /* Check if we've already copied the same table from 'L1' (during this transmission), and
1497 * reuse the old copy. This allows table upvalues shared by multiple
1498 * local functions to point to the same table, also in the target.
1499 * Also, this takes care of cyclic tables and multiple references
1500 * to the same subtable.
1501 *
1502 * Note: Even metatables need to go through this test; to detect
1503 * loops such as those in required module tables (getmetatable(lanes).lanes == lanes)
1504 */
1505 if (push_cached_table()) {
1506 LUA_ASSERT(L1, lua_istable(L2, -1)); // from cache
1507 return true;
1508 }
1509 LUA_ASSERT(L1, lua_istable(L2, -1));
1510
1511 STACK_GROW(L1, 2);
1512 STACK_GROW(L2, 2);
1513
1514 lua_pushnil(L1); // start iteration
1515 while (lua_next(L1, L1_i)) {
1516 // need a function to prevent overflowing the stack with verboseErrors-induced alloca()
1517 inter_copy_keyvaluepair();
1518 lua_pop(L1, 1); // pop value (next round)
1519 }
1520 STACK_CHECK(L1, 0);
1521 STACK_CHECK(L2, 1);
1522
1523 // Metatables are expected to be immutable, and copied only once.
1524 if (push_cached_metatable()) { // L2: ... t mt?
1525 lua_setmetatable(L2, -2); // L2: ... t
1526 }
1527 STACK_CHECK(L2, 1);
1528 STACK_CHECK(L1, 0);
1529 return true;
1530}
1531
1532// #################################################################################################
1533
1534[[nodiscard]] bool InterCopyContext::inter_copy_boolean() const
1535{
1536 int const v{ lua_toboolean(L1, L1_i) };
1537 DEBUGSPEW_CODE(fprintf(stderr, "%s\n", v ? "true" : "false"));
1538 lua_pushboolean(L2, v);
1539 return true;
1540}
1541
1542// #################################################################################################
1543
1544[[nodiscard]] bool InterCopyContext::inter_copy_lightuserdata() const
1545{
1546 void* const p{ lua_touserdata(L1, L1_i) };
1547 DEBUGSPEW_CODE(fprintf(stderr, "%p\n", p));
1548 lua_pushlightuserdata(L2, p);
1549 return true;
1550}
1551
1552// #################################################################################################
1553
1554[[nodiscard]] bool InterCopyContext::inter_copy_nil() const
1555{
1556 if (vt == VT::KEY) {
1557 return false;
1558 }
1559 lua_pushnil(L2);
1560 return true;
1561}
1562
1563// #################################################################################################
1564
1565[[nodiscard]] bool InterCopyContext::inter_copy_number() const
1566{
1567 // LNUM patch support (keeping integer accuracy)
1568#if defined LUA_LNUM || LUA_VERSION_NUM >= 503
1569 if (lua_isinteger(L1, L1_i)) {
1570 lua_Integer const v{ lua_tointeger(L1, L1_i) };
1571 DEBUGSPEW_CODE(fprintf(stderr, LUA_INTEGER_FMT "\n", v));
1572 lua_pushinteger(L2, v);
1573 } else
1574#endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503
1575 {
1576 lua_Number const v{ lua_tonumber(L1, L1_i) };
1577 DEBUGSPEW_CODE(fprintf(stderr, LUA_NUMBER_FMT "\n", v));
1578 lua_pushnumber(L2, v);
1579 }
1580 return true;
1581}
1582
1583// #################################################################################################
1584
1585[[nodiscard]] bool InterCopyContext::inter_copy_string() const
1586{
1587 size_t len;
1588 char const* const s{ lua_tolstring(L1, L1_i, &len) };
1589 DEBUGSPEW_CODE(fprintf(stderr, "'%s'\n", s));
1590 lua_pushlstring(L2, s, len);
1591 return true;
1592}
1593
1594// #################################################################################################
1595
1596/*
1597 * Copies a value from 'L1' state (at index 'i') to 'L2' state. Does not remove
1598 * the original value.
1599 *
1600 * NOTE: Both the states must be solely in the current OS thread's possession.
1601 *
1602 * 'i' is an absolute index (no -1, ...)
1603 *
1604 * Returns true if value was pushed, false if its type is non-supported.
1605 */
1606[[nodiscard]] bool InterCopyContext::inter_copy_one() const
1607{
1608 static constexpr int kPODmask = (1 << LUA_TNIL) | (1 << LUA_TBOOLEAN) | (1 << LUA_TLIGHTUSERDATA) | (1 << LUA_TNUMBER) | (1 << LUA_TSTRING);
1609 STACK_GROW(L2, 1);
1610 STACK_CHECK_START_REL(L1, 0);
1611 STACK_CHECK_START_REL(L2, 0);
1612
1613 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "inter_copy_one()\n" INDENT_END(U)));
1614 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U });
1615
1616 LuaType val_type{ lua_type_as_enum(L1, L1_i) };
1617 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%s %s: " INDENT_END(U), lua_type_names[static_cast<int>(val_type)], vt_names[static_cast<int>(vt)]));
1618
1619 // Non-POD can be skipped if its metatable contains { __lanesignore = true }
1620 if (((1 << static_cast<int>(val_type)) & kPODmask) == 0) {
1621 if (lua_getmetatable(L1, L1_i)) { // L1: ... mt
1622 lua_getfield(L1, -1, "__lanesignore"); // L1: ... mt ignore?
1623 if (lua_isboolean(L1, -1) && lua_toboolean(L1, -1)) {
1624 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "__lanesignore -> LUA_TNIL\n" INDENT_END(U)));
1625 val_type = LuaType::NIL;
1626 }
1627 lua_pop(L1, 2); // L1: ...
1628 }
1629 }
1630 STACK_CHECK(L1, 0);
1631
1632 // Lets push nil to L2 if the object should be ignored
1633 bool ret{ true };
1634 switch (val_type) {
1635 // Basic types allowed both as values, and as table keys
1636 case LuaType::BOOLEAN:
1637 ret = inter_copy_boolean();
1638 break;
1639 case LuaType::NUMBER:
1640 ret = inter_copy_number();
1641 break;
1642 case LuaType::STRING:
1643 ret = inter_copy_string();
1644 break;
1645 case LuaType::LIGHTUSERDATA:
1646 ret = inter_copy_lightuserdata();
1647 break;
1648
1649 // The following types are not allowed as table keys
1650 case LuaType::USERDATA:
1651 ret = inter_copy_userdata();
1652 break;
1653 case LuaType::NIL:
1654 ret = inter_copy_nil();
1655 break;
1656 case LuaType::FUNCTION:
1657 ret = inter_copy_function();
1658 break;
1659 case LuaType::TABLE:
1660 ret = inter_copy_table();
1661 break;
1662
1663 // The following types cannot be copied
1664 case LuaType::CDATA:
1665 [[fallthrough]];
1666 case LuaType::THREAD:
1667 ret = false;
1668 break;
1669 }
1670
1671 STACK_CHECK(L2, ret ? 1 : 0);
1672 STACK_CHECK(L1, 0);
1673 return ret;
1674}
1675
1676// #################################################################################################
1677
1678// Akin to 'lua_xmove' but copies values between _any_ Lua states.
1679// NOTE: Both the states must be solely in the current OS thread's possession.
1680[[nodiscard]] InterCopyResult InterCopyContext::inter_copy(int n_) const
1681{
1682 LUA_ASSERT(L1, vt == VT::NORMAL);
1683
1684 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "InterCopyContext::inter_copy()\n" INDENT_END(U)));
1685 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U });
1686
1687 int const top_L1{ lua_gettop(L1) };
1688 if (n_ > top_L1) {
1689 // requesting to copy more than is available?
1690 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "nothing to copy()\n" INDENT_END(U)));
1691 return InterCopyResult::NotEnoughValues;
1692 }
1693
1694 STACK_CHECK_START_REL(L2, 0);
1695 STACK_GROW(L2, n_ + 1);
1696
1697 /*
1698 * Make a cache table for the duration of this copy. Collects tables and
1699 * function entries, avoiding the same entries to be passed on as multiple
1700 * copies. ESSENTIAL i.e. for handling upvalue tables in the right manner!
1701 */
1702 int const top_L2{ lua_gettop(L2) }; // L2: ...
1703 lua_newtable(L2); // L2: ... cache
1704
1705 char tmpBuf[16];
1706 char const* const pBuf{ U->verboseErrors ? tmpBuf : "?" };
1707 InterCopyContext c{ U, L2, L1, CacheIndex{ top_L2 + 1 }, {}, VT::NORMAL, mode, pBuf };
1708 bool copyok{ true };
1709 STACK_CHECK_START_REL(L1, 0);
1710 for (int i{ top_L1 - n_ + 1 }, j{ 1 }; i <= top_L1; ++i, ++j) {
1711 if (U->verboseErrors) {
1712 sprintf(tmpBuf, "arg_%d", j);
1713 }
1714 c.L1_i = SourceIndex{ i };
1715 copyok = c.inter_copy_one(); // L2: ... cache {}n
1716 if (!copyok) {
1717 break;
1718 }
1719 }
1720 STACK_CHECK(L1, 0);
1721
1722 if (copyok) {
1723 STACK_CHECK(L2, n_ + 1);
1724 // Remove the cache table. Persistent caching would cause i.e. multiple
1725 // messages passed in the same table to use the same table also in receiving end.
1726 lua_remove(L2, top_L2 + 1);
1727 return InterCopyResult::Success;
1728 }
1729
1730 // error -> pop everything from the target state stack
1731 lua_settop(L2, top_L2);
1732 STACK_CHECK(L2, 0);
1733 return InterCopyResult::Error;
1734}
1735
1736// #################################################################################################
1737
1738[[nodiscard]] InterCopyResult InterCopyContext::inter_move(int n_) const
1739{
1740 InterCopyResult const ret{ inter_copy(n_) };
1741 lua_pop(L1, n_);
1742 return ret;
1743}
1744
1745// #################################################################################################
1746
1747// transfers stuff from L1->_G["package"] to L2->_G["package"]
1748// returns InterCopyResult::Success if everything is fine
1749// returns InterCopyResult::Error if pushed an error message in L1
1750// else raise an error in L1
1751[[nodiscard]] InterCopyResult InterCopyContext::inter_copy_package() const
1752{
1753 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "InterCopyContext::inter_copy_package()\n" INDENT_END(U)));
1754
1755 class OnExit
1756 {
1757 private:
1758 lua_State* const L2;
1759 int const top_L2;
1760 DEBUGSPEW_CODE(DebugSpewIndentScope m_scope);
1761
1762 public:
1763 OnExit(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L2_)
1764 : L2{ L2_ }
1765 , top_L2{ lua_gettop(L2) } DEBUGSPEW_COMMA_PARAM(m_scope{ U_ })
1766 {
1767 }
1768
1769 ~OnExit()
1770 {
1771 lua_settop(L2, top_L2);
1772 }
1773 } onExit{ DEBUGSPEW_PARAM_COMMA(U) L2 };
1774
1775 STACK_CHECK_START_REL(L1, 0);
1776 if (lua_type_as_enum(L1, L1_i) != LuaType::TABLE) {
1777 lua_pushfstring(L1, "expected package as table, got %s", luaL_typename(L1, L1_i));
1778 STACK_CHECK(L1, 1);
1779 // raise the error when copying from lane to lane, else just leave it on the stack to be raised later
1780 if (mode == LookupMode::LaneBody) {
1781 raise_lua_error(getErrL()); // that's ok, getErrL() is L1 in that case
1782 }
1783 return InterCopyResult::Error;
1784 }
1785 if (luaG_getmodule(L2, LUA_LOADLIBNAME) == LuaType::NIL) { // package library not loaded: do nothing
1786 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "'package' not loaded, nothing to do\n" INDENT_END(U)));
1787 STACK_CHECK(L1, 0);
1788 return InterCopyResult::Success;
1789 }
1790
1791 InterCopyResult result{ InterCopyResult::Success };
1792 // package.loaders is renamed package.searchers in Lua 5.2
1793 // but don't copy it anyway, as the function names change depending on the slot index!
1794 // users should provide an on_state_create function to setup custom loaders instead
1795 // don't copy package.preload in keeper states (they don't know how to translate functions)
1796 char const* entries[] = { "path", "cpath", (mode == LookupMode::LaneBody) ? "preload" : nullptr /*, (LUA_VERSION_NUM == 501) ? "loaders" : "searchers"*/, nullptr };
1797 for (char const* const entry : entries) {
1798 if (!entry) {
1799 continue;
1800 }
1801 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "package.%s\n" INDENT_END(U), entry));
1802 lua_getfield(L1, L1_i, entry);
1803 if (lua_isnil(L1, -1)) {
1804 lua_pop(L1, 1);
1805 } else {
1806 {
1807 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U });
1808 result = inter_move(1); // moves the entry to L2
1809 STACK_CHECK(L1, 0);
1810 }
1811 if (result == InterCopyResult::Success) {
1812 lua_setfield(L2, -2, entry); // set package[entry]
1813 } else {
1814 lua_pushfstring(L1, "failed to copy package entry %s", entry);
1815 // raise the error when copying from lane to lane, else just leave it on the stack to be raised later
1816 if (mode == LookupMode::LaneBody) {
1817 raise_lua_error(getErrL());
1818 }
1819 lua_pop(L1, 1);
1820 break;
1821 }
1822 }
1823 }
1824 STACK_CHECK(L1, 0);
1825 return result;
1826}