diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/keeper.c | 10 | ||||
-rw-r--r-- | src/lanes.c | 42 | ||||
-rw-r--r-- | src/lanes.lua | 21 | ||||
-rw-r--r-- | src/tools.c | 597 | ||||
-rw-r--r-- | src/tools.h | 4 |
5 files changed, 420 insertions, 254 deletions
diff --git a/src/keeper.c b/src/keeper.c index 056c01e..9a7c804 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
@@ -103,7 +103,7 @@ static void fifo_push( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) | |||
103 | for( i = count_; i >= 1; -- i) | 103 | for( i = count_; i >= 1; -- i) |
104 | { | 104 | { |
105 | // store in the fifo the value at the top of the stack at the specified index, popping it from the stack | 105 | // store in the fifo the value at the top of the stack at the specified index, popping it from the stack |
106 | lua_rawseti( L, idx, start + i); | 106 | lua_rawseti( L, idx, (int)(start + i)); |
107 | } | 107 | } |
108 | fifo_->count += count_; | 108 | fifo_->count += count_; |
109 | } | 109 | } |
@@ -115,11 +115,11 @@ static void fifo_push( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) | |||
115 | // function assumes that there is enough data in the fifo to satisfy the request | 115 | // function assumes that there is enough data in the fifo to satisfy the request |
116 | static void fifo_peek( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) | 116 | static void fifo_peek( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) |
117 | { | 117 | { |
118 | int i; | 118 | lua_Integer i; |
119 | STACK_GROW( L, count_); | 119 | STACK_GROW( L, count_); |
120 | for( i = 0; i < count_; ++ i) | 120 | for( i = 0; i < count_; ++ i) |
121 | { | 121 | { |
122 | lua_rawgeti( L, 1, fifo_->first + i); | 122 | lua_rawgeti( L, 1, (int)( fifo_->first + i)); |
123 | } | 123 | } |
124 | } | 124 | } |
125 | 125 | ||
@@ -134,7 +134,7 @@ static void fifo_pop( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) | |||
134 | // skip first item, we will push it last | 134 | // skip first item, we will push it last |
135 | for( i = 1; i < count_; ++ i) | 135 | for( i = 1; i < count_; ++ i) |
136 | { | 136 | { |
137 | lua_Integer const at = fifo_->first + i; | 137 | int const at = (int)( fifo_->first + i); |
138 | // push item on the stack | 138 | // push item on the stack |
139 | lua_rawgeti( L, fifo_idx, at); // ... fifo val | 139 | lua_rawgeti( L, fifo_idx, at); // ... fifo val |
140 | // remove item from the fifo | 140 | // remove item from the fifo |
@@ -143,7 +143,7 @@ static void fifo_pop( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) | |||
143 | } | 143 | } |
144 | // now process first item | 144 | // now process first item |
145 | { | 145 | { |
146 | lua_Integer const at = fifo_->first; | 146 | int const at = (int)( fifo_->first); |
147 | lua_rawgeti( L, fifo_idx, at); // ... fifo vals val | 147 | lua_rawgeti( L, fifo_idx, at); // ... fifo vals val |
148 | lua_pushnil( L); // ... fifo vals val nil | 148 | lua_pushnil( L); // ... fifo vals val nil |
149 | lua_rawseti( L, fifo_idx, at); // ... fifo vals val | 149 | lua_rawseti( L, fifo_idx, at); // ... fifo vals val |
diff --git a/src/lanes.c b/src/lanes.c index d0ffee1..8410ca2 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * LANES.C Copyright (c) 2007-08, Asko Kauppi | 2 | * LANES.C Copyright (c) 2007-08, Asko Kauppi |
3 | * Copyright (C) 2009-14, Benoit Germain | 3 | * Copyright (C) 2009-17, Benoit Germain |
4 | * | 4 | * |
5 | * Multithreading in Lua. | 5 | * Multithreading in Lua. |
6 | * | 6 | * |
@@ -52,13 +52,13 @@ | |||
52 | * ... | 52 | * ... |
53 | */ | 53 | */ |
54 | 54 | ||
55 | char const* VERSION = "3.10.1"; | 55 | char const* VERSION = "3.11"; |
56 | 56 | ||
57 | /* | 57 | /* |
58 | =============================================================================== | 58 | =============================================================================== |
59 | 59 | ||
60 | Copyright (C) 2007-10 Asko Kauppi <akauppi@gmail.com> | 60 | Copyright (C) 2007-10 Asko Kauppi <akauppi@gmail.com> |
61 | 2011-14 Benoit Germain <bnt.germain@gmail.com> | 61 | 2011-17 Benoit Germain <bnt.germain@gmail.com> |
62 | 62 | ||
63 | Permission is hereby granted, free of charge, to any person obtaining a copy | 63 | Permission is hereby granted, free of charge, to any person obtaining a copy |
64 | of this software and associated documentation files (the "Software"), to deal | 64 | of this software and associated documentation files (the "Software"), to deal |
@@ -162,7 +162,8 @@ struct s_lane | |||
162 | // lane status changes to DONE/ERROR_ST/CANCELLED. | 162 | // lane status changes to DONE/ERROR_ST/CANCELLED. |
163 | #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR | 163 | #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR |
164 | 164 | ||
165 | volatile enum { | 165 | volatile enum |
166 | { | ||
166 | NORMAL, // normal master side state | 167 | NORMAL, // normal master side state |
167 | KILLED // issued an OS kill | 168 | KILLED // issued an OS kill |
168 | } mstatus; | 169 | } mstatus; |
@@ -307,7 +308,7 @@ static bool_t push_registry_table( lua_State* L, void* key, bool_t create) | |||
307 | return FALSE; | 308 | return FALSE; |
308 | } | 309 | } |
309 | 310 | ||
310 | lua_newtable(L); // t | 311 | lua_newtable( L); // t |
311 | lua_pushlightuserdata( L, key); // t key | 312 | lua_pushlightuserdata( L, key); // t key |
312 | lua_pushvalue( L, -2); // t key t | 313 | lua_pushvalue( L, -2); // t key t |
313 | lua_rawset( L, LUA_REGISTRYINDEX); // t | 314 | lua_rawset( L, LUA_REGISTRYINDEX); // t |
@@ -351,7 +352,7 @@ static bool_t tracking_remove( struct s_lane* s) | |||
351 | // still (at process exit they will remove us from chain and then | 352 | // still (at process exit they will remove us from chain and then |
352 | // cancel/kill). | 353 | // cancel/kill). |
353 | // | 354 | // |
354 | if (s->tracking_next != NULL) | 355 | if( s->tracking_next != NULL) |
355 | { | 356 | { |
356 | struct s_lane** ref = (struct s_lane**) &s->U->tracking_first; | 357 | struct s_lane** ref = (struct s_lane**) &s->U->tracking_first; |
357 | 358 | ||
@@ -539,7 +540,7 @@ LUAG_FUNC( linda_send) | |||
539 | break; | 540 | break; |
540 | } | 541 | } |
541 | 542 | ||
542 | // instant timout to bypass the | 543 | // instant timout to bypass the wait syscall |
543 | if( timeout == 0.0) | 544 | if( timeout == 0.0) |
544 | { | 545 | { |
545 | break; /* no wait; instant timeout */ | 546 | break; /* no wait; instant timeout */ |
@@ -2157,6 +2158,30 @@ LUAG_FUNC( require) | |||
2157 | return 1; | 2158 | return 1; |
2158 | } | 2159 | } |
2159 | 2160 | ||
2161 | |||
2162 | // --- If a client wants to transfer stuff of a previously required module from the current state to another Lane, the module must be registered | ||
2163 | // to populate the lookup database in the source lane (and in the destination too, of course) | ||
2164 | // lanes.register( "modname", module) | ||
2165 | LUAG_FUNC( register) | ||
2166 | { | ||
2167 | char const* name = luaL_checkstring( L, 1); | ||
2168 | int const nargs = lua_gettop( L); | ||
2169 | int const mod_type = lua_type( L, 2); | ||
2170 | // ignore extra parameters, just in case | ||
2171 | lua_settop( L, 2); | ||
2172 | luaL_argcheck( L, (mod_type == LUA_TTABLE) || (mod_type == LUA_TFUNCTION), 2, "unexpected module type"); | ||
2173 | DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); | ||
2174 | STACK_CHECK( L); // "name" mod_table | ||
2175 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register %s BEGIN\n" INDENT_END, name)); | ||
2176 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | ||
2177 | populate_func_lookup_table( L, -1, name); | ||
2178 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register %s END\n" INDENT_END, name)); | ||
2179 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); | ||
2180 | STACK_END( L, 0); | ||
2181 | return 0; | ||
2182 | } | ||
2183 | |||
2184 | |||
2160 | LUAG_FUNC( thread_gc); | 2185 | LUAG_FUNC( thread_gc); |
2161 | #define GCCB_KEY (void*)LG_thread_gc | 2186 | #define GCCB_KEY (void*)LG_thread_gc |
2162 | //--- | 2187 | //--- |
@@ -2945,6 +2970,7 @@ static const struct luaL_Reg lanes_functions [] = { | |||
2945 | {"wakeup_conv", LG_wakeup_conv}, | 2970 | {"wakeup_conv", LG_wakeup_conv}, |
2946 | {"set_thread_priority", LG_set_thread_priority}, | 2971 | {"set_thread_priority", LG_set_thread_priority}, |
2947 | {"nameof", luaG_nameof}, | 2972 | {"nameof", luaG_nameof}, |
2973 | {"register", LG_register}, | ||
2948 | {"set_singlethreaded", LG_set_singlethreaded}, | 2974 | {"set_singlethreaded", LG_set_singlethreaded}, |
2949 | {NULL, NULL} | 2975 | {NULL, NULL} |
2950 | }; | 2976 | }; |
@@ -3201,7 +3227,7 @@ LUAG_FUNC( configure) | |||
3201 | { | 3227 | { |
3202 | // don't do this when called during the initialization of a new lane, | 3228 | // don't do this when called during the initialization of a new lane, |
3203 | // because we will do it after on_state_create() is called, | 3229 | // because we will do it after on_state_create() is called, |
3204 | // and we don't want skip _G because of caching in case globals are created then | 3230 | // and we don't want to skip _G because of caching in case globals are created then |
3205 | lua_pushglobaltable( L); // settings M _G | 3231 | lua_pushglobaltable( L); // settings M _G |
3206 | populate_func_lookup_table( L, -1, NULL); | 3232 | populate_func_lookup_table( L, -1, NULL); |
3207 | lua_pop( L, 1); // settings M | 3233 | lua_pop( L, 1); // settings M |
diff --git a/src/lanes.lua b/src/lanes.lua index 6cbbd65..35071ae 100644 --- a/src/lanes.lua +++ b/src/lanes.lua | |||
@@ -40,9 +40,8 @@ local core = require "lanes.core" | |||
40 | -- Lua 5.2: module() is gone | 40 | -- Lua 5.2: module() is gone |
41 | -- almost everything module() does is done by require() anyway | 41 | -- almost everything module() does is done by require() anyway |
42 | -- -> simply create a table, populate it, return it, and be done | 42 | -- -> simply create a table, populate it, return it, and be done |
43 | local lanes = {} | ||
44 | local lanesMeta = {} | 43 | local lanesMeta = {} |
45 | setmetatable(lanes,lanesMeta) | 44 | local lanes = setmetatable( {}, lanesMeta) |
46 | 45 | ||
47 | -- this function is available in the public interface until it is called, after which it disappears | 46 | -- this function is available in the public interface until it is called, after which it disappears |
48 | lanes.configure = function( settings_) | 47 | lanes.configure = function( settings_) |
@@ -55,7 +54,7 @@ lanes.configure = function( settings_) | |||
55 | error( "To use 'lanes', you will also need to have 'string' available.", 2) | 54 | error( "To use 'lanes', you will also need to have 'string' available.", 2) |
56 | end | 55 | end |
57 | -- Configure called so remove metatable from lanes | 56 | -- Configure called so remove metatable from lanes |
58 | setmetatable(lanes,nil) | 57 | setmetatable( lanes, nil) |
59 | -- | 58 | -- |
60 | -- Cache globals for code that might run under sandboxing | 59 | -- Cache globals for code that might run under sandboxing |
61 | -- | 60 | -- |
@@ -139,7 +138,7 @@ lanes.configure = function( settings_) | |||
139 | author= "Asko Kauppi <akauppi@gmail.com>, Benoit Germain <bnt.germain@gmail.com>", | 138 | author= "Asko Kauppi <akauppi@gmail.com>, Benoit Germain <bnt.germain@gmail.com>", |
140 | description= "Running multiple Lua states in parallel", | 139 | description= "Running multiple Lua states in parallel", |
141 | license= "MIT/X11", | 140 | license= "MIT/X11", |
142 | copyright= "Copyright (c) 2007-10, Asko Kauppi; (c) 2011-13, Benoit Germain", | 141 | copyright= "Copyright (c) 2007-10, Asko Kauppi; (c) 2011-17, Benoit Germain", |
143 | version = assert( core.version) | 142 | version = assert( core.version) |
144 | } | 143 | } |
145 | 144 | ||
@@ -220,6 +219,9 @@ lanes.configure = function( settings_) | |||
220 | ["debug"] = true, | 219 | ["debug"] = true, |
221 | ["bit32"] = true, -- Lua 5.2 only, ignored silently under 5.1 | 220 | ["bit32"] = true, -- Lua 5.2 only, ignored silently under 5.1 |
222 | ["utf8"] = true, -- Lua 5.3 only, ignored silently under 5.1 and 5.2 | 221 | ["utf8"] = true, -- Lua 5.3 only, ignored silently under 5.1 and 5.2 |
222 | ["bit"] = true, -- LuaJIT only, ignored silently under PUC-Lua | ||
223 | ["jit"] = true, -- LuaJIT only, ignored silently under PUC-Lua | ||
224 | ["ffi"] = true, -- LuaJIT only, ignored silently under PUC-Lua | ||
223 | -- | 225 | -- |
224 | ["base"] = true, | 226 | ["base"] = true, |
225 | ["coroutine"] = true, -- part of "base" in Lua 5.1 | 227 | ["coroutine"] = true, -- part of "base" in Lua 5.1 |
@@ -713,6 +715,7 @@ lanes.configure = function( settings_) | |||
713 | 715 | ||
714 | -- activate full interface | 716 | -- activate full interface |
715 | lanes.require = core.require | 717 | lanes.require = core.require |
718 | lanes.register = core.register | ||
716 | lanes.gen = gen | 719 | lanes.gen = gen |
717 | lanes.linda = core.linda | 720 | lanes.linda = core.linda |
718 | lanes.cancel_error = core.cancel_error | 721 | lanes.cancel_error = core.cancel_error |
@@ -731,20 +734,18 @@ lanes.configure = function( settings_) | |||
731 | return lanes | 734 | return lanes |
732 | end -- lanes.configure | 735 | end -- lanes.configure |
733 | 736 | ||
734 | lanesMeta.__index = function(t,k) | 737 | lanesMeta.__index = function( t, k) |
735 | -- This is called when some functionality is accessed without calling configure() | 738 | -- This is called when some functionality is accessed without calling configure() |
736 | lanes.configure() -- Initialize with default settings | 739 | lanes.configure() -- initialize with default settings |
737 | -- Access the required key | 740 | -- Access the required key |
738 | return lanes[k] | 741 | return lanes[k] |
739 | end | 742 | end |
740 | 743 | ||
741 | -- no need to force calling configure() excepted the first time | 744 | -- no need to force calling configure() manually excepted the first time (other times will reuse the internally stored settings of the first call) |
742 | if core.settings then | 745 | if core.settings then |
743 | return lanes.configure() | 746 | return lanes.configure() |
744 | else | 747 | else |
745 | return lanes | 748 | return lanes |
746 | end | 749 | end |
747 | 750 | ||
748 | 751 | --the end | |
749 | --the end (Unreachable Code) | ||
750 | --return lanes | ||
diff --git a/src/tools.c b/src/tools.c index f1b0372..c2491ba 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -8,7 +8,7 @@ | |||
8 | =============================================================================== | 8 | =============================================================================== |
9 | 9 | ||
10 | Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com> | 10 | Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com> |
11 | 2011-14 benoit Germain <bnt.germain@gmail.com> | 11 | 2011-17 benoit Germain <bnt.germain@gmail.com> |
12 | 12 | ||
13 | Permission is hereby granted, free of charge, to any person obtaining a copy | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy |
14 | of this software and associated documentation files (the "Software"), to deal | 14 | of this software and associated documentation files (the "Software"), to deal |
@@ -71,48 +71,52 @@ DEBUGSPEW_CODE( char const* debugspew_indent = "----+----!----+----!----+----!-- | |||
71 | 71 | ||
72 | /*---=== luaG_dump ===---*/ | 72 | /*---=== luaG_dump ===---*/ |
73 | 73 | ||
74 | void luaG_dump( lua_State* L ) { | 74 | void luaG_dump( lua_State* L) |
75 | 75 | { | |
76 | int top= lua_gettop(L); | 76 | int top = lua_gettop( L); |
77 | int i; | 77 | int i; |
78 | 78 | ||
79 | fprintf( stderr, "\n\tDEBUG STACK:\n" ); | 79 | fprintf( stderr, "\n\tDEBUG STACK:\n"); |
80 | 80 | ||
81 | if (top==0) | 81 | if( top == 0) |
82 | fprintf( stderr, "\t(none)\n" ); | 82 | fprintf( stderr, "\t(none)\n"); |
83 | 83 | ||
84 | for( i=1; i<=top; i++ ) { | 84 | for( i = 1; i <= top; ++ i) |
85 | int type= lua_type( L, i ); | 85 | { |
86 | int type = lua_type( L, i); | ||
86 | 87 | ||
87 | fprintf( stderr, "\t[%d]= (%s) ", i, lua_typename(L,type) ); | 88 | fprintf( stderr, "\t[%d]= (%s) ", i, lua_typename( L, type)); |
88 | 89 | ||
89 | // Print item contents here... | 90 | // Print item contents here... |
90 | // | 91 | // |
91 | // Note: this requires 'tostring()' to be defined. If it is NOT, | 92 | // Note: this requires 'tostring()' to be defined. If it is NOT, |
92 | // enable it for more debugging. | 93 | // enable it for more debugging. |
93 | // | 94 | // |
94 | STACK_CHECK( L); | 95 | STACK_CHECK( L); |
95 | STACK_GROW( L, 2); | 96 | STACK_GROW( L, 2); |
96 | 97 | ||
97 | lua_getglobal( L, "tostring" ); | 98 | lua_getglobal( L, "tostring"); |
98 | // | 99 | // |
99 | // [-1]: tostring function, or nil | 100 | // [-1]: tostring function, or nil |
100 | 101 | ||
101 | if (!lua_isfunction(L,-1)) { | 102 | if( !lua_isfunction( L, -1)) |
102 | fprintf( stderr, "('tostring' not available)" ); | 103 | { |
103 | } else { | 104 | fprintf( stderr, "('tostring' not available)"); |
104 | lua_pushvalue( L, i ); | ||
105 | lua_call( L, 1 /*args*/, 1 /*retvals*/ ); | ||
106 | |||
107 | // Don't trust the string contents | ||
108 | // | ||
109 | fprintf( stderr, "%s", lua_tostring(L,-1) ); | ||
110 | } | ||
111 | lua_pop(L,1); | ||
112 | STACK_END( L, 0); | ||
113 | fprintf( stderr, "\n" ); | ||
114 | } | 105 | } |
115 | fprintf( stderr, "\n" ); | 106 | else |
107 | { | ||
108 | lua_pushvalue( L, i); | ||
109 | lua_call( L, 1 /*args*/, 1 /*retvals*/); | ||
110 | |||
111 | // Don't trust the string contents | ||
112 | // | ||
113 | fprintf( stderr, "%s", lua_tostring( L, -1)); | ||
114 | } | ||
115 | lua_pop( L, 1); | ||
116 | STACK_END( L, 0); | ||
117 | fprintf( stderr, "\n"); | ||
118 | } | ||
119 | fprintf( stderr, "\n"); | ||
116 | } | 120 | } |
117 | 121 | ||
118 | void initialize_on_state_create( struct s_Universe* U, lua_State* L) | 122 | void initialize_on_state_create( struct s_Universe* U, lua_State* L) |
@@ -206,6 +210,14 @@ static const luaL_Reg libs[] = | |||
206 | { LUA_COLIBNAME, NULL}, // Lua 5.1: part of base package | 210 | { LUA_COLIBNAME, NULL}, // Lua 5.1: part of base package |
207 | #endif // LUA_VERSION_NUM | 211 | #endif // LUA_VERSION_NUM |
208 | { LUA_DBLIBNAME, luaopen_debug}, | 212 | { LUA_DBLIBNAME, luaopen_debug}, |
213 | #if defined LUA_JITLIBNAME // building against LuaJIT headers, add some LuaJIT-specific libs | ||
214 | //#pragma message( "supporting JIT base libs") | ||
215 | { LUA_BITLIBNAME, luaopen_bit}, | ||
216 | { LUA_JITLIBNAME, luaopen_jit}, | ||
217 | { LUA_FFILIBNAME, luaopen_ffi}, | ||
218 | #endif // LUA_JITLIBNAME | ||
219 | |||
220 | { LUA_DBLIBNAME, luaopen_debug}, | ||
209 | { "lanes.core", require_lanes_core}, // So that we can open it like any base library (possible since we have access to the init function) | 221 | { "lanes.core", require_lanes_core}, // So that we can open it like any base library (possible since we have access to the init function) |
210 | // | 222 | // |
211 | { "base", NULL}, // ignore "base" (already acquired it) | 223 | { "base", NULL}, // ignore "base" (already acquired it) |
@@ -246,7 +258,8 @@ static void open1lib( struct s_Universe* U, lua_State* L, char const* name_, siz | |||
246 | } | 258 | } |
247 | } | 259 | } |
248 | 260 | ||
249 | static int dummy_writer(lua_State *L, const void* p, size_t sz, void* ud) | 261 | |
262 | static int dummy_writer( lua_State* L, void const* p, size_t sz, void* ud) | ||
250 | { | 263 | { |
251 | (void)L; (void)p; (void)sz; (void) ud; // unused | 264 | (void)L; (void)p; (void)sz; (void) ud; // unused |
252 | return 666; | 265 | return 666; |
@@ -314,12 +327,12 @@ static lua_CFunction luaG_tocfunction( lua_State *L, int _i, FuncSubType *_out) | |||
314 | 327 | ||
315 | 328 | ||
316 | // inspired from tconcat() in ltablib.c | 329 | // inspired from tconcat() in ltablib.c |
317 | static char const* luaG_pushFQN(lua_State *L, int t, int last, size_t* length) | 330 | static char const* luaG_pushFQN( lua_State* L, int t, int last, size_t* length) |
318 | { | 331 | { |
319 | int i = 1; | 332 | int i = 1; |
320 | luaL_Buffer b; | 333 | luaL_Buffer b; |
321 | STACK_CHECK( L); | 334 | STACK_CHECK( L); |
322 | luaL_buffinit(L, &b); | 335 | luaL_buffinit( L, &b); |
323 | for( ; i < last; ++ i) | 336 | for( ; i < last; ++ i) |
324 | { | 337 | { |
325 | lua_rawgeti( L, t, i); | 338 | lua_rawgeti( L, t, i); |
@@ -336,12 +349,89 @@ static char const* luaG_pushFQN(lua_State *L, int t, int last, size_t* length) | |||
336 | return lua_tolstring( L, -1, length); | 349 | return lua_tolstring( L, -1, length); |
337 | } | 350 | } |
338 | 351 | ||
352 | /* | ||
353 | * receives 2 arguments: a name k and an object o | ||
354 | * add two entries ["fully.qualified.name"] = o | ||
355 | * and [o] = "fully.qualified.name" | ||
356 | * where <o> is either a table or a function | ||
357 | * if we already had an entry of type [o] = ..., replace the name if the new one is shorter | ||
358 | * pops the processed object from the stack | ||
359 | */ | ||
360 | static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth) | ||
361 | { | ||
362 | // slot 1 in the stack contains the table that receives everything we found | ||
363 | int const dest = _ctx_base; | ||
364 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i | ||
365 | int const fqn = _ctx_base + 1; | ||
366 | |||
367 | size_t prevNameLength, newNameLength; | ||
368 | char const* prevName; | ||
369 | DEBUGSPEW_CODE( char const *newName); | ||
370 | DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); | ||
371 | |||
372 | STACK_CHECK( L); | ||
373 | // first, raise an error if the function is already known | ||
374 | lua_pushvalue( L, -1); // ... {bfc} k o o | ||
375 | lua_rawget( L, dest); // ... {bfc} k o name? | ||
376 | prevName = lua_tolstring( L, -1, &prevNameLength); // NULL if we got nil (first encounter of this object) | ||
377 | // push name in fqn stack (note that concatenation will crash if name is a not string or a number) | ||
378 | lua_pushvalue( L, -3); // ... {bfc} k o name? k | ||
379 | ASSERT_L( lua_type( L, -1) == LUA_TNUMBER || lua_type( L, -1) == LUA_TSTRING); | ||
380 | ++ _depth; | ||
381 | lua_rawseti( L, fqn, _depth); // ... {bfc} k o name? | ||
382 | // generate name | ||
383 | DEBUGSPEW_CODE( newName =) luaG_pushFQN( L, fqn, _depth, &newNameLength); // ... {bfc} k o name? "f.q.n" | ||
384 | // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order | ||
385 | // on different VMs even when the tables are populated the exact same way. | ||
386 | // When Lua is built with compatibility options (such as LUA_COMPAT_ALL), | ||
387 | // this causes several base libraries to register functions under multiple names. | ||
388 | // This, with the randomizer, can cause the first generated name of an object to be different on different VMs, | ||
389 | // which breaks function transfer. | ||
390 | // Also, nothing prevents any external module from exposing a given object under several names, so... | ||
391 | // Therefore, when we encounter an object for which a name was previously registered, we need to select the names | ||
392 | // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded | ||
393 | if( prevName != NULL && (prevNameLength < newNameLength || lua_lessthan( L, -2, -1))) | ||
394 | { | ||
395 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -3)), newName, prevName)); | ||
396 | // the previous name is 'smaller' than the one we just generated: keep it! | ||
397 | lua_pop( L, 3); // ... {bfc} k | ||
398 | } | ||
399 | else | ||
400 | { | ||
401 | // the name we generated is either the first one, or a better fit for our purposes | ||
402 | if( prevName) | ||
403 | { | ||
404 | // clear the previous name for the database to avoid clutter | ||
405 | lua_insert( L, -2); // ... {bfc} k o "f.q.n" prevName | ||
406 | // t[prevName] = nil | ||
407 | lua_pushnil( L); // ... {bfc} k o "f.q.n" prevName nil | ||
408 | lua_rawset( L, dest); // ... {bfc} k o "f.q.n" | ||
409 | } | ||
410 | else | ||
411 | { | ||
412 | lua_remove( L, -2); // ... {bfc} k o "f.q.n" | ||
413 | } | ||
414 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -2)), newName)); | ||
415 | // prepare the stack for database feed | ||
416 | lua_pushvalue( L, -1); // ... {bfc} k o "f.q.n" "f.q.n" | ||
417 | lua_pushvalue( L, -3); // ... {bfc} k o "f.q.n" "f.q.n" o | ||
418 | ASSERT_L( lua_rawequal( L, -1, -4)); | ||
419 | ASSERT_L( lua_rawequal( L, -2, -3)); | ||
420 | // t["f.q.n"] = o | ||
421 | lua_rawset( L, dest); // ... {bfc} k o "f.q.n" | ||
422 | // t[o] = "f.q.n" | ||
423 | lua_rawset( L, dest); // ... {bfc} k | ||
424 | // remove table name from fqn stack | ||
425 | lua_pushnil( L); // ... {bfc} k nil | ||
426 | lua_rawseti( L, fqn, _depth); // ... {bfc} k | ||
427 | } | ||
428 | -- _depth; | ||
429 | STACK_END( L, -1); | ||
430 | } | ||
339 | 431 | ||
340 | static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _i, int _depth) | 432 | static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _i, int _depth) |
341 | { | 433 | { |
342 | lua_Integer visit_count; | 434 | lua_Integer visit_count; |
343 | // slot 1 in the stack contains the table that receives everything we found | ||
344 | int const dest = _ctx_base; | ||
345 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i | 435 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i |
346 | int const fqn = _ctx_base + 1; | 436 | int const fqn = _ctx_base + 1; |
347 | // slot 3 contains a cache that stores all already visited tables to avoid infinite recursion loops | 437 | // slot 3 contains a cache that stores all already visited tables to avoid infinite recursion loops |
@@ -400,69 +490,15 @@ static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _ | |||
400 | lua_rawset( L, cache); // ... {_i} {bfc} k {} | 490 | lua_rawset( L, cache); // ... {_i} {bfc} k {} |
401 | // store the table in the breadth-first cache | 491 | // store the table in the breadth-first cache |
402 | lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k | 492 | lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k |
403 | lua_insert( L, -2); // ... {_i} {bfc} k k {} | 493 | lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k {} |
404 | lua_rawset( L, breadth_first_cache); // ... {_i} {bfc} k | 494 | lua_rawset( L, breadth_first_cache); // ... {_i} {bfc} k {} |
495 | // generate a name, and if we already had one name, keep whichever is the shorter | ||
496 | update_lookup_entry( L, _ctx_base, _depth); // ... {_i} {bfc} k | ||
405 | } | 497 | } |
406 | else if( lua_isfunction( L, -1) && (luaG_getfuncsubtype( L, -1) != FST_Bytecode)) // ... {_i} {bfc} k func | 498 | else if( lua_isfunction( L, -1) && (luaG_getfuncsubtype( L, -1) != FST_Bytecode)) // ... {_i} {bfc} k func |
407 | { | 499 | { |
408 | size_t prevNameLength, newNameLength; | 500 | // generate a name, and if we already had one name, keep whichever is the shorter |
409 | char const* prevName; | 501 | update_lookup_entry( L, _ctx_base, _depth); // ... {_i} {bfc} k |
410 | DEBUGSPEW_CODE( char const *newName); | ||
411 | // first, raise an error if the function is already known | ||
412 | lua_pushvalue( L, -1); // ... {_i} {bfc} k func func | ||
413 | lua_rawget( L, dest); // ... {_i} {bfc} k func name? | ||
414 | prevName = lua_tolstring( L, -1, &prevNameLength); // NULL if we got nil (first encounter of this function) | ||
415 | // push function name in fqn stack (note that concatenation will crash if name is a not string or a number) | ||
416 | lua_pushvalue( L, -3); // ... {_i} {bfc} k func name? k | ||
417 | ++ _depth; | ||
418 | lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k func name? | ||
419 | // generate name | ||
420 | DEBUGSPEW_CODE( newName =) luaG_pushFQN( L, fqn, _depth, &newNameLength); // ... {_i} {bfc} k func name? "f.q.n" | ||
421 | // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order | ||
422 | // on different VMs even when the tables are populated the exact same way. | ||
423 | // When Lua is built with compatibility options (such as LUA_COMPAT_ALL), | ||
424 | // this causes several base libraries to register functions under multiple names. | ||
425 | // This, with the randomizer, can cause the first name of a function to be different on different VMs, | ||
426 | // which breaks function transfer. | ||
427 | // Also, nothing prevents any external module from exposing a given function under several names, so... | ||
428 | // Therefore, when we encounter a function for which a name was previously registered, we need to select the names | ||
429 | // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded | ||
430 | if( prevName != NULL && (prevNameLength < newNameLength || lua_lessthan( L, -2, -1))) | ||
431 | { | ||
432 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "function '%s' remained named '%s'\n" INDENT_END, newName, prevName)); | ||
433 | // the previous name is 'smaller' than the one we just generated: keep it! | ||
434 | lua_pop( L, 3); // ... {_i} {bfc} k | ||
435 | } | ||
436 | else | ||
437 | { | ||
438 | // the name we generated is either the first one, or a better fit for our purposes | ||
439 | if( prevName) | ||
440 | { | ||
441 | // clear the previous name for the database to avoid clutter | ||
442 | lua_insert( L, -2); // ... {_i} {bfc} k func "f.q.n" prevName | ||
443 | // t[prevName] = nil | ||
444 | lua_pushnil( L); // ... {_i} {bfc} k func "f.q.n" prevName nil | ||
445 | lua_rawset( L, dest); // ... {_i} {bfc} k func "f.q.n" | ||
446 | } | ||
447 | else | ||
448 | { | ||
449 | lua_remove( L, -2); // ... {_i} {bfc} k func "f.q.n" | ||
450 | } | ||
451 | // prepare the stack for database feed | ||
452 | lua_pushvalue( L, -1); // ... {_i} {bfc} k func "f.q.n" "f.q.n" | ||
453 | lua_pushvalue( L, -3); // ... {_i} {bfc} k func "f.q.n" "f.q.n" func | ||
454 | ASSERT_L( lua_rawequal( L, -1, -4)); | ||
455 | ASSERT_L( lua_rawequal( L, -2, -3)); | ||
456 | // t["f.q.n"] = func | ||
457 | lua_rawset( L, dest); // ... {_i} {bfc} k func "f.q.n" | ||
458 | // t[func] = "f.q.n" | ||
459 | lua_rawset( L, dest); // ... {_i} {bfc} k | ||
460 | // remove table name from fqn stack | ||
461 | lua_pushnil( L); // ... {_i} {bfc} k nil | ||
462 | lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k | ||
463 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "function '%s'\n" INDENT_END, newName)); | ||
464 | } | ||
465 | -- _depth; | ||
466 | } | 502 | } |
467 | else | 503 | else |
468 | { | 504 | { |
@@ -519,7 +555,7 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) | |||
519 | { | 555 | { |
520 | int const ctx_base = lua_gettop( L) + 1; | 556 | int const ctx_base = lua_gettop( L) + 1; |
521 | int const in_base = lua_absindex( L, _i); | 557 | int const in_base = lua_absindex( L, _i); |
522 | int const start_depth = name_ ? 1 : 0; | 558 | int start_depth = 0; |
523 | DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); | 559 | DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); |
524 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "NULL")); | 560 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "NULL")); |
525 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 561 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
@@ -543,9 +579,17 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) | |||
543 | lua_newtable( L); // {} {fqn} | 579 | lua_newtable( L); // {} {fqn} |
544 | if( name_) | 580 | if( name_) |
545 | { | 581 | { |
582 | STACK_MID( L, 2); | ||
546 | lua_pushstring( L, name_); // {} {fqn} "name" | 583 | lua_pushstring( L, name_); // {} {fqn} "name" |
584 | // generate a name, and if we already had one name, keep whichever is the shorter | ||
585 | lua_pushvalue( L, in_base); // {} {fqn} "name" t | ||
586 | update_lookup_entry( L, ctx_base, start_depth); // {} {fqn} "name" | ||
587 | // don't forget to store the name at the bottom of the fqn stack | ||
588 | ++ start_depth; | ||
547 | lua_rawseti( L, -2, start_depth); // {} {fqn} | 589 | lua_rawseti( L, -2, start_depth); // {} {fqn} |
590 | STACK_MID( L, 2); | ||
548 | } | 591 | } |
592 | // retrieve the cache, create it if we haven't done it yet | ||
549 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache}? | 593 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache}? |
550 | if( lua_isnil( L, -1)) | 594 | if( lua_isnil( L, -1)) |
551 | { | 595 | { |
@@ -554,6 +598,7 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) | |||
554 | lua_pushvalue( L, -1); // {} {fqn} {cache} {cache} | 598 | lua_pushvalue( L, -1); // {} {fqn} {cache} {cache} |
555 | lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache} | 599 | lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache} |
556 | } | 600 | } |
601 | // process everything we find in that table, filling in lookup data for all functions and tables we see there | ||
557 | populate_func_lookup_table_recur( L, ctx_base, in_base, start_depth); // {...} {fqn} {cache} | 602 | populate_func_lookup_table_recur( L, ctx_base, in_base, start_depth); // {...} {fqn} {cache} |
558 | lua_pop( L, 3); | 603 | lua_pop( L, 3); |
559 | } | 604 | } |
@@ -795,6 +840,158 @@ static int buf_writer( lua_State *L, const void* b, size_t n, void* B ) { | |||
795 | } | 840 | } |
796 | 841 | ||
797 | 842 | ||
843 | // function sentinel used to transfer native functions from/to keeper states | ||
844 | static int func_lookup_sentinel( lua_State* L) | ||
845 | { | ||
846 | return luaL_error( L, "function lookup sentinel for %s, should never be called", lua_tostring( L, lua_upvalueindex( 1))); | ||
847 | } | ||
848 | |||
849 | |||
850 | // function sentinel used to transfer native table from/to keeper states | ||
851 | static int table_lookup_sentinel( lua_State* L) | ||
852 | { | ||
853 | return luaL_error( L, "table lookup sentinel for %s, should never be called", lua_tostring( L, lua_upvalueindex(1))); | ||
854 | } | ||
855 | |||
856 | /* | ||
857 | * retrieve the name of a function/table in the lookup database | ||
858 | */ | ||
859 | static char const* find_lookup_name( lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_, size_t* len_) | ||
860 | { | ||
861 | DEBUGSPEW_CODE( struct s_Universe* const U = get_universe( L)); | ||
862 | char const* fqn; | ||
863 | ASSERT_L( lua_isfunction( L, i) || lua_istable( L, i)); // ... v ... | ||
864 | STACK_CHECK( L); | ||
865 | STACK_GROW( L, 3); // up to 3 slots are necessary on error | ||
866 | if( mode_ == eLM_FromKeeper) | ||
867 | { | ||
868 | lua_CFunction f = lua_tocfunction( L, i); // should *always* be func_lookup_sentinel or table_lookup_sentinel! | ||
869 | if( f == func_lookup_sentinel || f == table_lookup_sentinel) | ||
870 | { | ||
871 | lua_getupvalue( L, i, 1); // ... v ... "f.q.n" | ||
872 | } | ||
873 | else | ||
874 | { | ||
875 | // if this is not a sentinel, this is some user-created table we wanted to lookup | ||
876 | ASSERT_L( NULL == f && lua_istable( L, i)); | ||
877 | // push anything that will convert to NULL string | ||
878 | lua_pushnil( L); // ... v ... nil | ||
879 | } | ||
880 | } | ||
881 | else | ||
882 | { | ||
883 | // fetch the name from the source state's lookup table | ||
884 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // ... v ... {} | ||
885 | ASSERT_L( lua_istable( L, -1)); | ||
886 | lua_pushvalue( L, i); // ... v ... {} v | ||
887 | lua_rawget( L, -2); // ... v ... {} "f.q.n" | ||
888 | } | ||
889 | fqn = lua_tolstring( L, -1, len_); | ||
890 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END, fqn)); | ||
891 | // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database | ||
892 | lua_pop( L, (mode_ == eLM_FromKeeper) ? 1 : 2); // ... v ... | ||
893 | STACK_MID( L, 0); | ||
894 | if( NULL == fqn && !lua_istable( L, i)) // raise an error if we try to send an unknown function (but not for tables) | ||
895 | { | ||
896 | char const *from, *typewhat, *what, *gotchaA, *gotchaB; | ||
897 | // try to discover the name of the function we want to send | ||
898 | lua_getglobal( L, "decoda_name"); // ... v ... decoda_name | ||
899 | from = lua_tostring( L, -1); | ||
900 | lua_pushcfunction( L, luaG_nameof); // ... v ... decoda_name luaG_nameof | ||
901 | lua_pushvalue( L, i); // ... v ... decoda_name luaG_nameof t | ||
902 | lua_call( L, 1, 2); // ... v ... decoda_name "type" "name"|nil | ||
903 | typewhat = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : luaL_typename( L, -2); | ||
904 | // second return value can be nil if the table was not found | ||
905 | // probable reason: the function was removed from the source Lua state before Lanes was required. | ||
906 | if( lua_isnil( L, -1)) | ||
907 | { | ||
908 | gotchaA = " referenced by"; | ||
909 | gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)"; | ||
910 | what = upName_; | ||
911 | } | ||
912 | else | ||
913 | { | ||
914 | gotchaA = ""; | ||
915 | gotchaB = ""; | ||
916 | what = (lua_type( L, -1) == LUA_TSTRING) ? lua_tostring( L, -1) : luaL_typename( L, -1); | ||
917 | } | ||
918 | (void) luaL_error( L, "%s%s '%s' not found in %s origin transfer database.%s", typewhat, gotchaA, what, from ? from : "main", gotchaB); | ||
919 | *len_ = 0; | ||
920 | return NULL; | ||
921 | } | ||
922 | STACK_END( L, 0); | ||
923 | return fqn; | ||
924 | } | ||
925 | |||
926 | |||
927 | /* | ||
928 | * Push a looked-up table, or nothing if we found nothing | ||
929 | */ | ||
930 | static bool_t lookup_table( lua_State* L2, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) | ||
931 | { | ||
932 | // get the name of the table we want to send | ||
933 | size_t len; | ||
934 | char const* fqn = find_lookup_name( L, i, mode_, upName_, &len); | ||
935 | if( NULL == fqn) // name not found, it is some user-created table | ||
936 | { | ||
937 | return FALSE; | ||
938 | } | ||
939 | // push the equivalent table in the destination's stack, retrieved from the lookup table | ||
940 | STACK_CHECK( L2); // L // L2 | ||
941 | STACK_GROW( L2, 3); // up to 3 slots are necessary on error | ||
942 | switch( mode_) | ||
943 | { | ||
944 | default: // shouldn't happen, in theory... | ||
945 | (void) luaL_error( L, "internal error: unknown lookup mode"); | ||
946 | return FALSE; | ||
947 | |||
948 | case eLM_ToKeeper: | ||
949 | // push a sentinel closure that holds the lookup name as upvalue | ||
950 | lua_pushlstring( L2, fqn, len); // "f.q.n" | ||
951 | lua_pushcclosure( L2, table_lookup_sentinel, 1); // f | ||
952 | break; | ||
953 | |||
954 | case eLM_LaneBody: | ||
955 | case eLM_FromKeeper: | ||
956 | lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // {} | ||
957 | ASSERT_L( lua_istable( L2, -1)); | ||
958 | lua_pushlstring( L2, fqn, len); // {} "f.q.n" | ||
959 | lua_rawget( L2, -2); // {} t | ||
960 | // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead) | ||
961 | // but not when we extract something out of a keeper, as there is nothing to clone! | ||
962 | if( lua_isnil( L2, -1) && mode_ == eLM_LaneBody) | ||
963 | { | ||
964 | lua_pop( L2, 2); // | ||
965 | STACK_MID( L2, 0); | ||
966 | return FALSE; | ||
967 | } | ||
968 | else if( !lua_istable( L2, -1)) | ||
969 | { | ||
970 | char const* from, *to; | ||
971 | lua_getglobal( L, "decoda_name"); // ... t ... decoda_name | ||
972 | from = lua_tostring( L, -1); | ||
973 | lua_pop( L, 1); // ... t ... | ||
974 | lua_getglobal( L2, "decoda_name"); // {} t decoda_name | ||
975 | to = lua_tostring( L2, -1); | ||
976 | lua_pop( L2, 1); // {} t | ||
977 | // 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 | ||
978 | (void) luaL_error( | ||
979 | (mode_ == eLM_FromKeeper) ? L2 : L | ||
980 | , "INTERNAL ERROR IN %s: table '%s' not found in %s destination transfer database." | ||
981 | , from ? from : "main" | ||
982 | , fqn | ||
983 | , to ? to : "main" | ||
984 | ); | ||
985 | return FALSE; | ||
986 | } | ||
987 | lua_remove( L2, -2); // t | ||
988 | break; | ||
989 | } | ||
990 | STACK_END( L2, 1); | ||
991 | return TRUE; | ||
992 | } | ||
993 | |||
994 | |||
798 | /* | 995 | /* |
799 | * Check if we've already copied the same table from 'L', and | 996 | * Check if we've already copied the same table from 'L', and |
800 | * reuse the old copy. This allows table upvalues shared by multiple | 997 | * reuse the old copy. This allows table upvalues shared by multiple |
@@ -805,60 +1002,35 @@ static int buf_writer( lua_State *L, const void* b, size_t n, void* B ) { | |||
805 | * Returns TRUE if the table was cached (no need to fill it!); FALSE if | 1002 | * Returns TRUE if the table was cached (no need to fill it!); FALSE if |
806 | * it's a virgin. | 1003 | * it's a virgin. |
807 | */ | 1004 | */ |
808 | static bool_t push_cached_table( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) | 1005 | static bool_t push_cached_table( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i) |
809 | { | 1006 | { |
810 | bool_t ret; | 1007 | bool_t not_found_in_cache; // L2 |
1008 | void* const p = (void*)lua_topointer( L, i); | ||
811 | 1009 | ||
812 | ASSERT_L( L2_cache_i != 0 ); | 1010 | ASSERT_L( L2_cache_i != 0); |
813 | 1011 | STACK_GROW( L2, 3); | |
814 | STACK_GROW(L2,3); | ||
815 | |||
816 | // L2_cache[id_str]= [{...}] | ||
817 | // | ||
818 | STACK_CHECK( L2); | 1012 | STACK_CHECK( L2); |
819 | 1013 | ||
820 | // We don't need to use the from state ('L') in ID since the life span | 1014 | // We don't need to use the from state ('L') in ID since the life span |
821 | // is only for the duration of a copy (both states are locked). | 1015 | // is only for the duration of a copy (both states are locked). |
822 | // | 1016 | // push a light userdata uniquely representing the table |
823 | lua_pushlightuserdata( L2, (void*)lua_topointer( L, i )); // push a light userdata uniquely representing the table | 1017 | lua_pushlightuserdata( L2, p); // ... p |
824 | |||
825 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); | ||
826 | 1018 | ||
827 | lua_pushvalue( L2, -1 ); | 1019 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring( L2, -1)); |
828 | lua_rawget( L2, L2_cache_i ); | ||
829 | // | ||
830 | // [-2]: identity table pointer lightuserdata | ||
831 | // [-1]: table|nil | ||
832 | 1020 | ||
833 | if (lua_isnil(L2,-1)) | 1021 | lua_rawget( L2, L2_cache_i); // ... {cached|nil} |
1022 | not_found_in_cache = lua_isnil( L2, -1); | ||
1023 | if( not_found_in_cache) | ||
834 | { | 1024 | { |
835 | lua_pop(L2,1); | 1025 | lua_pop( L2, 1); // ... |
836 | lua_newtable(L2); | 1026 | lua_newtable( L2); // ... {} |
837 | lua_pushvalue(L2,-1); | 1027 | lua_pushlightuserdata( L2, p); // ... {} p |
838 | lua_insert(L2,-3); | 1028 | lua_pushvalue( L2, -2); // ... {} p {} |
839 | // | 1029 | lua_rawset( L2, L2_cache_i); // ... {} |
840 | // [-3]: new table (2nd ref) | ||
841 | // [-2]: identity table pointer lightuserdata | ||
842 | // [-1]: new table | ||
843 | |||
844 | lua_rawset(L2, L2_cache_i); | ||
845 | // | ||
846 | // [-1]: new table (tied to 'L2_cache' table') | ||
847 | |||
848 | ret= FALSE; // brand new | ||
849 | |||
850 | } | ||
851 | else | ||
852 | { | ||
853 | lua_remove(L2,-2); | ||
854 | ret= TRUE; // from cache | ||
855 | } | 1030 | } |
856 | STACK_END( L2, 1); | 1031 | STACK_END( L2, 1); |
857 | // | 1032 | ASSERT_L( lua_istable( L2, -1)); |
858 | // L2 [-1]: table to use as destination | 1033 | return !not_found_in_cache; |
859 | |||
860 | ASSERT_L( lua_istable(L2,-1) ); | ||
861 | return ret; | ||
862 | } | 1034 | } |
863 | 1035 | ||
864 | 1036 | ||
@@ -999,6 +1171,7 @@ static int discover_object_name_recur( lua_State* L, int shortest_, int depth_) | |||
999 | return shortest_; | 1171 | return shortest_; |
1000 | } | 1172 | } |
1001 | 1173 | ||
1174 | |||
1002 | /* | 1175 | /* |
1003 | * "type", "name" = lanes.nameof( o) | 1176 | * "type", "name" = lanes.nameof( o) |
1004 | */ | 1177 | */ |
@@ -1046,72 +1219,17 @@ int luaG_nameof( lua_State* L) | |||
1046 | return 2; | 1219 | return 2; |
1047 | } | 1220 | } |
1048 | 1221 | ||
1049 | // function sentinel used to transfer native functions from/to keeper states | ||
1050 | static int sentinelfunc( lua_State* L) | ||
1051 | { | ||
1052 | return luaL_error( L, "transfer sentinel function for %s, should never be called", lua_tostring( L, lua_upvalueindex( 1))); | ||
1053 | } | ||
1054 | 1222 | ||
1055 | /* | 1223 | /* |
1056 | * Push a looked-up native/LuaJIT function. | 1224 | * Push a looked-up native/LuaJIT function. |
1057 | */ | 1225 | */ |
1058 | static void lookup_native_func( struct s_Universe* U, lua_State* L2, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) | 1226 | static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) |
1059 | { | 1227 | { |
1060 | char const* fqn; // L // L2 | 1228 | // get the name of the function we want to send |
1061 | size_t len; | 1229 | size_t len; |
1062 | ASSERT_L( lua_isfunction( L, i)); // ... f ... | 1230 | char const* fqn = find_lookup_name( L, i, mode_, upName_, &len); |
1063 | STACK_CHECK( L); | ||
1064 | STACK_GROW( L, 3); // up to 3 slots are necessary on error | ||
1065 | if( mode_ == eLM_FromKeeper) | ||
1066 | { | ||
1067 | lua_CFunction f = lua_tocfunction( L, i); // should *always* be sentinelfunc! | ||
1068 | ASSERT_L( f == sentinelfunc); | ||
1069 | lua_getupvalue( L, i, 1); // ... f ... "f.q.n" | ||
1070 | fqn = lua_tolstring( L, -1, &len); | ||
1071 | } | ||
1072 | else | ||
1073 | { | ||
1074 | // fetch the name from the source state's lookup table | ||
1075 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // ... f ... {} | ||
1076 | ASSERT_L( lua_istable( L, -1)); | ||
1077 | lua_pushvalue( L, i); // ... f ... {} f | ||
1078 | lua_rawget( L, -2); // ... f ... {} "f.q.n" | ||
1079 | fqn = lua_tolstring( L, -1, &len); | ||
1080 | } | ||
1081 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END, fqn)); | ||
1082 | // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database | ||
1083 | lua_pop( L, (mode_ == eLM_FromKeeper) ? 1 : 2); // ... f ... | ||
1084 | STACK_MID( L, 0); | ||
1085 | if( !fqn) | ||
1086 | { | ||
1087 | char const *from, *typewhat, *what, *gotchaA, *gotchaB; | ||
1088 | // try to discover the name of the function we want to send | ||
1089 | lua_getglobal( L, "decoda_name"); // ... f ... decoda_name | ||
1090 | from = lua_tostring( L, -1); | ||
1091 | lua_pushcfunction( L, luaG_nameof); // ... f ... decoda_name luaG_nameof | ||
1092 | lua_pushvalue( L, i); // ... f ... decoda_name luaG_nameof f | ||
1093 | lua_call( L, 1, 2); // ... f ... decoda_name "type" "name"|nil | ||
1094 | typewhat = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : luaL_typename( L, -2); | ||
1095 | // second return value can be nil if the function was not found | ||
1096 | // probable reason: the function was removed from the source Lua state before Lanes was required. | ||
1097 | if( lua_isnil( L, -1)) | ||
1098 | { | ||
1099 | gotchaA = " referenced by"; | ||
1100 | gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)"; | ||
1101 | what = upName_; | ||
1102 | } | ||
1103 | else | ||
1104 | { | ||
1105 | gotchaA = ""; | ||
1106 | gotchaB = ""; | ||
1107 | what = (lua_type( L, -1) == LUA_TSTRING) ? lua_tostring( L, -1) : luaL_typename( L, -1); | ||
1108 | } | ||
1109 | (void) luaL_error( L, "%s%s '%s' not found in %s origin transfer database.%s", typewhat, gotchaA, what, from ? from : "main", gotchaB); | ||
1110 | return; | ||
1111 | } | ||
1112 | STACK_END( L, 0); | ||
1113 | // push the equivalent function in the destination's stack, retrieved from the lookup table | 1231 | // push the equivalent function in the destination's stack, retrieved from the lookup table |
1114 | STACK_CHECK( L2); | 1232 | STACK_CHECK( L2); // L // L2 |
1115 | STACK_GROW( L2, 3); // up to 3 slots are necessary on error | 1233 | STACK_GROW( L2, 3); // up to 3 slots are necessary on error |
1116 | switch( mode_) | 1234 | switch( mode_) |
1117 | { | 1235 | { |
@@ -1122,7 +1240,7 @@ static void lookup_native_func( struct s_Universe* U, lua_State* L2, lua_State* | |||
1122 | case eLM_ToKeeper: | 1240 | case eLM_ToKeeper: |
1123 | // push a sentinel closure that holds the lookup name as upvalue | 1241 | // push a sentinel closure that holds the lookup name as upvalue |
1124 | lua_pushlstring( L2, fqn, len); // "f.q.n" | 1242 | lua_pushlstring( L2, fqn, len); // "f.q.n" |
1125 | lua_pushcclosure( L2, sentinelfunc, 1); // f | 1243 | lua_pushcclosure( L2, func_lookup_sentinel, 1); // f |
1126 | break; | 1244 | break; |
1127 | 1245 | ||
1128 | case eLM_LaneBody: | 1246 | case eLM_LaneBody: |
@@ -1131,15 +1249,26 @@ static void lookup_native_func( struct s_Universe* U, lua_State* L2, lua_State* | |||
1131 | ASSERT_L( lua_istable( L2, -1)); | 1249 | ASSERT_L( lua_istable( L2, -1)); |
1132 | lua_pushlstring( L2, fqn, len); // {} "f.q.n" | 1250 | lua_pushlstring( L2, fqn, len); // {} "f.q.n" |
1133 | lua_rawget( L2, -2); // {} f | 1251 | lua_rawget( L2, -2); // {} f |
1134 | if( !lua_isfunction( L2, -1)) | 1252 | // nil means we don't know how to transfer stuff: user should do something |
1253 | // anything other than function or table should not happen! | ||
1254 | if( !lua_isfunction( L2, -1) && !lua_istable( L2, -1)) | ||
1135 | { | 1255 | { |
1136 | char const* from, * to; | 1256 | char const* from, * to; |
1137 | lua_getglobal( L, "decoda_name"); // ... f ... decoda_name | 1257 | lua_getglobal( L, "decoda_name"); // ... f ... decoda_name |
1138 | from = lua_tostring( L, -1); | 1258 | from = lua_tostring( L, -1); |
1259 | lua_pop( L, 1); // ... f ... | ||
1139 | lua_getglobal( L2, "decoda_name"); // {} f decoda_name | 1260 | lua_getglobal( L2, "decoda_name"); // {} f decoda_name |
1140 | to = lua_tostring( L2, -1); | 1261 | to = lua_tostring( L2, -1); |
1262 | lua_pop( L2, 1); // {} f | ||
1141 | // 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 | 1263 | // 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 |
1142 | (void) luaL_error( (mode_ == eLM_FromKeeper) ? L2 : L, "%s: function '%s' not found in %s destination transfer database.", from ? from : "main", fqn, to ? to : "main"); | 1264 | (void) luaL_error( |
1265 | (mode_ == eLM_FromKeeper) ? L2 : L | ||
1266 | , "%s%s: function '%s' not found in %s destination transfer database." | ||
1267 | , lua_isnil( L2, -1) ? "" : "INTERNAL ERROR IN " | ||
1268 | , from ? from : "main" | ||
1269 | , fqn | ||
1270 | , to ? to : "main" | ||
1271 | ); | ||
1143 | return; | 1272 | return; |
1144 | } | 1273 | } |
1145 | lua_remove( L2, -2); // f | 1274 | lua_remove( L2, -2); // f |
@@ -1164,6 +1293,7 @@ static void lookup_native_func( struct s_Universe* U, lua_State* L2, lua_State* | |||
1164 | STACK_END( L2, 1); | 1293 | STACK_END( L2, 1); |
1165 | } | 1294 | } |
1166 | 1295 | ||
1296 | |||
1167 | /* | 1297 | /* |
1168 | * Copy a function over, which has not been found in the cache. | 1298 | * Copy a function over, which has not been found in the cache. |
1169 | * L2 has the cache key for this function at the top of the stack | 1299 | * L2 has the cache key for this function at the top of the stack |
@@ -1181,7 +1311,7 @@ static void inter_copy_func( struct s_Universe* U, lua_State* L2, uint_t L2_cach | |||
1181 | int n, needToPush; | 1311 | int n, needToPush; |
1182 | luaL_Buffer b; | 1312 | luaL_Buffer b; |
1183 | ASSERT_L( L2_cache_i != 0); // ... {cache} ... p | 1313 | ASSERT_L( L2_cache_i != 0); // ... {cache} ... p |
1184 | STACK_GROW(L,2); | 1314 | STACK_GROW( L, 2); |
1185 | STACK_CHECK( L); | 1315 | STACK_CHECK( L); |
1186 | 1316 | ||
1187 | // 'lua_dump()' needs the function at top of stack | 1317 | // 'lua_dump()' needs the function at top of stack |
@@ -1223,7 +1353,7 @@ static void inter_copy_func( struct s_Universe* U, lua_State* L2, uint_t L2_cach | |||
1223 | lua_Debug ar; | 1353 | lua_Debug ar; |
1224 | lua_pushvalue( L, i); // ... b f | 1354 | lua_pushvalue( L, i); // ... b f |
1225 | // fills 'name' 'namewhat' and 'linedefined', pops function | 1355 | // fills 'name' 'namewhat' and 'linedefined', pops function |
1226 | lua_getinfo(L, ">nS", &ar); // ... b | 1356 | lua_getinfo( L, ">nS", &ar); // ... b |
1227 | name = ar.namewhat; | 1357 | name = ar.namewhat; |
1228 | fprintf( stderr, INDENT_BEGIN "FNAME: %s @ %d\n", i, s_indent, ar.short_src, ar.linedefined); // just gives NULL | 1358 | fprintf( stderr, INDENT_BEGIN "FNAME: %s @ %d\n", i, s_indent, ar.short_src, ar.linedefined); // just gives NULL |
1229 | } | 1359 | } |
@@ -1348,12 +1478,12 @@ static void push_cached_func( struct s_Universe* U, lua_State* L2, uint_t L2_cac | |||
1348 | // push a light userdata uniquely representing the function | 1478 | // push a light userdata uniquely representing the function |
1349 | lua_pushlightuserdata( L2, aspointer); // ... {cache} ... p | 1479 | lua_pushlightuserdata( L2, aspointer); // ... {cache} ... p |
1350 | 1480 | ||
1351 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); | 1481 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring( L2, -1)); |
1352 | 1482 | ||
1353 | lua_pushvalue( L2, -1); // ... {cache} ... p p | 1483 | lua_pushvalue( L2, -1); // ... {cache} ... p p |
1354 | lua_rawget( L2, L2_cache_i); // ... {cache} ... p function|nil|true | 1484 | lua_rawget( L2, L2_cache_i); // ... {cache} ... p function|nil|true |
1355 | 1485 | ||
1356 | if( lua_isnil(L2,-1)) // function is unknown | 1486 | if( lua_isnil( L2, -1)) // function is unknown |
1357 | { | 1487 | { |
1358 | lua_pop( L2, 1); // ... {cache} ... p | 1488 | lua_pop( L2, 1); // ... {cache} ... p |
1359 | 1489 | ||
@@ -1368,15 +1498,14 @@ static void push_cached_func( struct s_Universe* U, lua_State* L2, uint_t L2_cac | |||
1368 | lua_remove( L2, -2); // ... {cache} ... function | 1498 | lua_remove( L2, -2); // ... {cache} ... function |
1369 | } | 1499 | } |
1370 | STACK_END( L2, 1); | 1500 | STACK_END( L2, 1); |
1501 | ASSERT_L( lua_isfunction( L2, -1)); | ||
1371 | } | 1502 | } |
1372 | else // function is native/LuaJIT: no need to cache | 1503 | else // function is native/LuaJIT: no need to cache |
1373 | { | 1504 | { |
1374 | lookup_native_func( U, L2, L, i, mode_, upName_); // ... {cache} ... function | 1505 | lookup_native_func( L2, L, i, mode_, upName_); // ... {cache} ... function |
1506 | // if the function was in fact a lookup sentinel, we can either get a function or a table here | ||
1507 | ASSERT_L( lua_isfunction( L2, -1) || lua_istable( L2, -1)); | ||
1375 | } | 1508 | } |
1376 | |||
1377 | // | ||
1378 | // L2 [-1]: function | ||
1379 | ASSERT_L( lua_isfunction( L2, -1)); | ||
1380 | } | 1509 | } |
1381 | 1510 | ||
1382 | /* | 1511 | /* |
@@ -1393,25 +1522,23 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
1393 | { | 1522 | { |
1394 | bool_t ret = TRUE; | 1523 | bool_t ret = TRUE; |
1395 | bool_t ignore = FALSE; | 1524 | bool_t ignore = FALSE; |
1525 | int val_type = lua_type( L, i); | ||
1396 | STACK_GROW( L2, 1); | 1526 | STACK_GROW( L2, 1); |
1397 | STACK_CHECK( L2); | 1527 | STACK_CHECK( L2); |
1398 | 1528 | ||
1399 | /* Skip the object if it has metatable with { __lanesignore = true } */ | 1529 | /* Skip the object if it has metatable with { __lanesignore = true } */ |
1400 | if( lua_getmetatable( L, i)) // ... mt | 1530 | if( lua_getmetatable( L, i)) // ... mt |
1401 | { | 1531 | { |
1402 | lua_pushstring( L, "__lanesignore"); // ... mt "__lanesignore" | 1532 | lua_getfield( L, -1, "__lanesignore"); // ... mt ignore? |
1403 | lua_gettable( L, -2); // ... mt ignore? | ||
1404 | |||
1405 | if( lua_isboolean( L, -1) && lua_toboolean( L, -1)) | 1533 | if( lua_isboolean( L, -1) && lua_toboolean( L, -1)) |
1406 | { | 1534 | { |
1407 | ignore = TRUE; | 1535 | val_type = LUA_TNIL; |
1408 | } | 1536 | } |
1409 | |||
1410 | lua_pop( L, 2); // ... | 1537 | lua_pop( L, 2); // ... |
1411 | } | 1538 | } |
1412 | 1539 | ||
1413 | /* Lets push nil to L2 if the object should be ignored */ | 1540 | /* Lets push nil to L2 if the object should be ignored */ |
1414 | switch( ignore ? LUA_TNIL : lua_type( L, i)) | 1541 | switch( val_type) |
1415 | { | 1542 | { |
1416 | /* Basic types allowed both as values, and as table keys */ | 1543 | /* Basic types allowed both as values, and as table keys */ |
1417 | 1544 | ||
@@ -1425,7 +1552,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
1425 | if( lua_isinteger( L, i)) | 1552 | if( lua_isinteger( L, i)) |
1426 | { | 1553 | { |
1427 | lua_Integer v = lua_tointeger( L, i); | 1554 | lua_Integer v = lua_tointeger( L, i); |
1428 | DEBUGSPEW_CODE( if( vt == VT_KEY) fprintf( stderr, INDENT_BEGIN "KEY: %d\n" INDENT_END, v)); | 1555 | DEBUGSPEW_CODE( if( vt == VT_KEY) fprintf( stderr, INDENT_BEGIN "KEY: " LUA_INTEGER_FMT "\n" INDENT_END, v)); |
1429 | lua_pushinteger( L2, v); | 1556 | lua_pushinteger( L2, v); |
1430 | break; | 1557 | break; |
1431 | } | 1558 | } |
@@ -1448,7 +1575,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
1448 | break; | 1575 | break; |
1449 | 1576 | ||
1450 | case LUA_TLIGHTUSERDATA: | 1577 | case LUA_TLIGHTUSERDATA: |
1451 | lua_pushlightuserdata( L2, lua_touserdata(L, i)); | 1578 | lua_pushlightuserdata( L2, lua_touserdata( L, i)); |
1452 | break; | 1579 | break; |
1453 | 1580 | ||
1454 | /* The following types are not allowed as table keys */ | 1581 | /* The following types are not allowed as table keys */ |
@@ -1524,6 +1651,16 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
1524 | STACK_CHECK( L); | 1651 | STACK_CHECK( L); |
1525 | STACK_CHECK( L2); | 1652 | STACK_CHECK( L2); |
1526 | 1653 | ||
1654 | /* | ||
1655 | * 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?) | ||
1656 | * 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 | ||
1657 | */ | ||
1658 | if( lookup_table( L2, L, i, mode_, upName_)) | ||
1659 | { | ||
1660 | 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 | ||
1661 | break; | ||
1662 | } | ||
1663 | |||
1527 | /* Check if we've already copied the same table from 'L' (during this transmission), and | 1664 | /* Check if we've already copied the same table from 'L' (during this transmission), and |
1528 | * reuse the old copy. This allows table upvalues shared by multiple | 1665 | * reuse the old copy. This allows table upvalues shared by multiple |
1529 | * local functions to point to the same table, also in the target. | 1666 | * local functions to point to the same table, also in the target. |
@@ -1531,14 +1668,14 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
1531 | * to the same subtable. | 1668 | * to the same subtable. |
1532 | * | 1669 | * |
1533 | * Note: Even metatables need to go through this test; to detect | 1670 | * Note: Even metatables need to go through this test; to detect |
1534 | * loops s.a. those in required module tables (getmetatable(lanes).lanes == lanes) | 1671 | * loops such as those in required module tables (getmetatable(lanes).lanes == lanes) |
1535 | */ | 1672 | */ |
1536 | if( push_cached_table( L2, L2_cache_i, L, i)) | 1673 | if( push_cached_table( L2, L2_cache_i, L, i)) |
1537 | { | 1674 | { |
1538 | ASSERT_L( lua_istable( L2, -1)); // from cache | 1675 | ASSERT_L( lua_istable( L2, -1)); // from cache |
1539 | break; | 1676 | break; |
1540 | } | 1677 | } |
1541 | ASSERT_L( lua_istable( L2,-1)); | 1678 | ASSERT_L( lua_istable( L2, -1)); |
1542 | 1679 | ||
1543 | STACK_GROW( L, 2); | 1680 | STACK_GROW( L, 2); |
1544 | STACK_GROW( L2, 2); | 1681 | STACK_GROW( L2, 2); |
@@ -1546,11 +1683,10 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
1546 | lua_pushnil( L); // start iteration | 1683 | lua_pushnil( L); // start iteration |
1547 | while( lua_next( L, i)) | 1684 | while( lua_next( L, i)) |
1548 | { | 1685 | { |
1549 | uint_t val_i = lua_gettop(L); | 1686 | uint_t val_i = lua_gettop( L); |
1550 | uint_t key_i = val_i - 1; | 1687 | uint_t key_i = val_i - 1; |
1551 | 1688 | ||
1552 | /* Only basic key types are copied over; others ignored | 1689 | // Only basic key types are copied over; others ignored |
1553 | */ | ||
1554 | if( inter_copy_one_( U, L2, 0 /*key*/, L, key_i, VT_KEY, mode_, upName_)) | 1690 | if( inter_copy_one_( U, L2, 0 /*key*/, L, key_i, VT_KEY, mode_, upName_)) |
1555 | { | 1691 | { |
1556 | char* valPath = (char*) upName_; | 1692 | char* valPath = (char*) upName_; |
@@ -1613,8 +1749,8 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
1613 | { /* L2 did not know the metatable */ | 1749 | { /* L2 did not know the metatable */ |
1614 | lua_pop( L2, 1); | 1750 | lua_pop( L2, 1); |
1615 | STACK_MID( L2, 2); | 1751 | STACK_MID( L2, 2); |
1616 | ASSERT_L( lua_istable(L,-1)); | 1752 | ASSERT_L( lua_istable( L,-1)); |
1617 | if( inter_copy_one_( U, L2, L2_cache_i /*for function cacheing*/, L, lua_gettop(L) /*[-1]*/, VT_METATABLE, mode_, upName_)) | 1753 | if( inter_copy_one_( U, L2, L2_cache_i /*for function cacheing*/, L, lua_gettop( L) /*[-1]*/, VT_METATABLE, mode_, upName_)) |
1618 | { | 1754 | { |
1619 | // | 1755 | // |
1620 | // L2 ([-3]: copied table) | 1756 | // L2 ([-3]: copied table) |
@@ -1664,6 +1800,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
1664 | 1800 | ||
1665 | /* The following types cannot be copied */ | 1801 | /* The following types cannot be copied */ |
1666 | 1802 | ||
1803 | case 10: // LuaJIT CDATA | ||
1667 | case LUA_TTHREAD: | 1804 | case LUA_TTHREAD: |
1668 | ret = FALSE; | 1805 | ret = FALSE; |
1669 | break; | 1806 | break; |
diff --git a/src/tools.h b/src/tools.h index a4bcf43..b869a16 100644 --- a/src/tools.h +++ b/src/tools.h | |||
@@ -17,9 +17,11 @@ | |||
17 | #endif | 17 | #endif |
18 | 18 | ||
19 | // For some reason, LuaJIT 64bits doesn't support lua_newstate() | 19 | // For some reason, LuaJIT 64bits doesn't support lua_newstate() |
20 | #if defined(LUA_LJDIR) && (defined(__x86_64__) || defined(_M_X64)) | 20 | #if defined(LUA_JITLIBNAME) && (defined(__x86_64__) || defined(_M_X64)) |
21 | //#pragma message( "LuaJIT 64 bits detected: don't propagate allocf") | ||
21 | #define PROPAGATE_ALLOCF 0 | 22 | #define PROPAGATE_ALLOCF 0 |
22 | #else // LuaJIT x64 | 23 | #else // LuaJIT x64 |
24 | //#pragma message( "PUC-Lua detected: propagate allocf") | ||
23 | #define PROPAGATE_ALLOCF 1 | 25 | #define PROPAGATE_ALLOCF 1 |
24 | #endif // LuaJIT x64 | 26 | #endif // LuaJIT x64 |
25 | #if PROPAGATE_ALLOCF | 27 | #if PROPAGATE_ALLOCF |