diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2011-11-05 17:31:02 +0100 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2011-11-05 17:31:02 +0100 |
commit | 053f7cff3c95acb915e6babfd306971f11bb7986 (patch) | |
tree | ee38c60b1119d34eb96aea1105ef033e851d266e /src/tools.c | |
parent | 717eadee9c3644fabb32c7ee59949f2846143690 (diff) | |
download | lanes-053f7cff3c95acb915e6babfd306971f11bb7986.tar.gz lanes-053f7cff3c95acb915e6babfd306971f11bb7986.tar.bz2 lanes-053f7cff3c95acb915e6babfd306971f11bb7986.zip |
* process exit change: close everything at GC when main state closes, not when atexit() handlers are processed
* Lua 5.2-style module:
* module() is no longer used to implement lanes.lua
* a global "lanes" variable is no longer created when the module is required
* the Lanes module table is returned instead
* Lanes must be initialized before used:
* the first occurence of 'require "lanes"' produces a minimal interface that only contains a configure() function
* the remainder of the interface is made available once this function is called
* subsequent calls to configure() do nothing
* configure() controls the number of keeper states and the startup of timers
* LuaJIT 2 compatibility
* non-Lua functions are no longer copied by creating a C closure from a C pointer, but through 2-way lookup tables
* this means that if a lane function body pulls non-Lua functions, the lane generator description must contain the list of libraries and modules that exports them
* introduces a change in configuration .globals management: contents are copied *after* std libs are loaded
* new .required configuration entry to list modules that must be require()'ed before lane body is transferred
* lane:cancel() wakes up waiting lindas like what is done at lane shutdown
Diffstat (limited to 'src/tools.c')
-rw-r--r-- | src/tools.c | 649 |
1 files changed, 498 insertions, 151 deletions
diff --git a/src/tools.c b/src/tools.c index f9854db..b412e84 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -31,6 +31,7 @@ THE SOFTWARE. | |||
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include "tools.h" | 33 | #include "tools.h" |
34 | #include "keeper.h" | ||
34 | 35 | ||
35 | #include "lualib.h" | 36 | #include "lualib.h" |
36 | #include "lauxlib.h" | 37 | #include "lauxlib.h" |
@@ -66,7 +67,7 @@ void luaG_dump( lua_State* L ) { | |||
66 | // enable it for more debugging. | 67 | // enable it for more debugging. |
67 | // | 68 | // |
68 | STACK_CHECK(L) | 69 | STACK_CHECK(L) |
69 | STACK_GROW( L, 2 ) | 70 | STACK_GROW( L, 2); |
70 | 71 | ||
71 | lua_getglobal( L, "tostring" ); | 72 | lua_getglobal( L, "tostring" ); |
72 | // | 73 | // |
@@ -108,21 +109,302 @@ static const luaL_Reg libs[] = { | |||
108 | 109 | ||
109 | static bool_t openlib( lua_State *L, const char *name, size_t len ) { | 110 | static bool_t openlib( lua_State *L, const char *name, size_t len ) { |
110 | 111 | ||
111 | unsigned i; | 112 | unsigned i; |
112 | bool_t all= strncmp( name, "*", len ) == 0; | 113 | bool_t all= strncmp( name, "*", len ) == 0; |
113 | 114 | ||
114 | for( i=0; libs[i].name; i++ ) { | 115 | for( i=0; libs[i].name; i++ ) |
115 | if (all || (strncmp(name, libs[i].name, len) ==0)) { | 116 | { |
116 | if (libs[i].func) { | 117 | if (all || (strncmp(name, libs[i].name, len) ==0)) |
117 | STACK_GROW(L,2); | 118 | { |
118 | lua_pushcfunction( L, libs[i].func ); | 119 | if (libs[i].func) |
119 | lua_pushstring( L, libs[i].name ); | 120 | { |
120 | lua_call( L, 1, 0 ); | 121 | STACK_GROW(L,1); |
121 | } | 122 | STACK_CHECK(L) |
122 | if (!all) return TRUE; | 123 | lua_pushcfunction( L, libs[i].func); |
123 | } | 124 | // pushes the module table on the stack |
124 | } | 125 | lua_call( L, 0, 1); |
125 | return all; | 126 | populate_func_lookup_table( L, -1, libs[i].name); |
127 | // remove the module when we are done | ||
128 | lua_pop( L, 1); | ||
129 | STACK_END(L, 0) | ||
130 | } | ||
131 | if (!all) return TRUE; | ||
132 | } | ||
133 | } | ||
134 | return all; | ||
135 | } | ||
136 | |||
137 | static int dummy_writer(lua_State *L, const void* p, size_t sz, void* ud) | ||
138 | { | ||
139 | return 666; | ||
140 | } | ||
141 | |||
142 | |||
143 | /* | ||
144 | * differentiation between C, bytecode and JIT-fast functions | ||
145 | * | ||
146 | * | ||
147 | * +----------+------------+----------+ | ||
148 | * | bytecode | C function | JIT-fast | | ||
149 | * +-----------------+----------+------------+----------+ | ||
150 | * | lua_topointer | | | | | ||
151 | * +-----------------+----------+------------+----------+ | ||
152 | * | lua_tocfunction | NULL | | NULL | | ||
153 | * +-----------------+----------+------------+----------+ | ||
154 | * | lua_dump | 666 | 1 | 1 | | ||
155 | * +-----------------+----------+------------+----------+ | ||
156 | */ | ||
157 | |||
158 | typedef enum | ||
159 | { | ||
160 | FST_Bytecode, | ||
161 | FST_Native, | ||
162 | FST_FastJIT | ||
163 | } FuncSubType; | ||
164 | |||
165 | FuncSubType luaG_getfuncsubtype( lua_State *L, int _i) | ||
166 | { | ||
167 | if( lua_tocfunction( L, _i)) | ||
168 | { | ||
169 | return FST_Native; | ||
170 | } | ||
171 | { | ||
172 | int mustpush = 0, dumpres; | ||
173 | if( STACK_ABS( L, _i) != lua_gettop( L)) | ||
174 | { | ||
175 | lua_pushvalue( L, _i); | ||
176 | mustpush = 1; | ||
177 | } | ||
178 | // the provided writer fails with code 666 | ||
179 | // therefore, anytime we get 666, this means that lua_dump() attempted a dump | ||
180 | // all other cases mean this is either a C or LuaJIT-fast function | ||
181 | dumpres = lua_dump( L, dummy_writer, NULL); | ||
182 | lua_pop( L, mustpush); | ||
183 | if( dumpres == 666) | ||
184 | { | ||
185 | return FST_Bytecode; | ||
186 | } | ||
187 | } | ||
188 | return FST_FastJIT; | ||
189 | } | ||
190 | |||
191 | static lua_CFunction luaG_tocfunction( lua_State *L, int _i, FuncSubType *_out) | ||
192 | { | ||
193 | lua_CFunction p = lua_tocfunction( L, _i); | ||
194 | *_out = luaG_getfuncsubtype( L, _i); | ||
195 | return p; | ||
196 | } | ||
197 | |||
198 | |||
199 | #define LOOKUP_KEY "ddea37aa-50c7-4d3f-8e0b-fb7a9d62bac5" | ||
200 | #define LOOKUP_KEY_CACHE "d1059270-4976-4193-a55b-c952db5ab7cd" | ||
201 | |||
202 | |||
203 | // inspired from tconcat() in ltablib.c | ||
204 | static char const * luaG_pushFQN(lua_State *L, int t, int last) | ||
205 | { | ||
206 | int i = 1; | ||
207 | luaL_Buffer b; | ||
208 | STACK_CHECK( L) | ||
209 | luaL_buffinit(L, &b); | ||
210 | for( ; i < last; i++) | ||
211 | { | ||
212 | lua_rawgeti( L, t, i); | ||
213 | luaL_addvalue( &b); | ||
214 | luaL_addlstring(&b, ".", 1); | ||
215 | } | ||
216 | if (i == last) /* add last value (if interval was not empty) */ | ||
217 | { | ||
218 | lua_rawgeti( L, t, i); | ||
219 | luaL_addvalue( &b); | ||
220 | } | ||
221 | luaL_pushresult( &b); | ||
222 | STACK_END( L, 1) | ||
223 | return lua_tostring( L, -1); | ||
224 | } | ||
225 | |||
226 | |||
227 | static void populate_func_lookup_table_recur( lua_State *L, int _ctx_base, int _i, int _depth) | ||
228 | { | ||
229 | lua_Integer visit_count; | ||
230 | // slot 1 in the stack contains the table that receives everything we found | ||
231 | int const dest = _ctx_base; | ||
232 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i | ||
233 | int const fqn = _ctx_base + 1; | ||
234 | // slot 3 contains a cache that stores all already visited tables to avoid infinite recursion loops | ||
235 | int const cache = _ctx_base + 2; | ||
236 | // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search) | ||
237 | int const breadth_first_cache = lua_gettop( L) + 1; | ||
238 | |||
239 | STACK_GROW( L, 6); | ||
240 | // slot _i contains a table where we search for functions | ||
241 | STACK_CHECK( L) // ... {_i} | ||
242 | |||
243 | // if table is already visited, we are done | ||
244 | lua_pushvalue( L, _i); // ... {_i} {} | ||
245 | lua_rawget( L, cache); // ... {_i} nil|n | ||
246 | visit_count = lua_tointeger( L, -1); // 0 if nil, else n | ||
247 | lua_pop( L, 1); // ... {_i} | ||
248 | STACK_MID( L, 0) | ||
249 | if( visit_count > 0) | ||
250 | { | ||
251 | return; | ||
252 | } | ||
253 | |||
254 | // remember we visited this table (1-visit count) | ||
255 | lua_pushvalue( L, _i); // ... {_i} {} | ||
256 | lua_pushinteger( L, visit_count + 1); // ... {_i} {} 1 | ||
257 | lua_rawset( L, cache); // ... {_i} | ||
258 | STACK_MID( L, 0) | ||
259 | |||
260 | // this table is at breadth_first_cache index | ||
261 | lua_newtable( L); // ... {_i} {bfc} | ||
262 | ASSERT_L( lua_gettop( L) == breadth_first_cache); | ||
263 | // iterate over all entries in the processed table | ||
264 | lua_pushnil( L); // ... {_i} {bfc} nil | ||
265 | while( lua_next( L, _i) != 0) // ... {_i} {bfc} k v | ||
266 | { | ||
267 | // just for debug, not actually needed | ||
268 | //char const * key = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : "not a string"; | ||
269 | // subtable: process it recursively | ||
270 | if( lua_istable( L, -1)) // ... {_i} {bfc} k {} | ||
271 | { | ||
272 | // increment visit count to make sure we will actually scan it at this recursive level | ||
273 | lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} | ||
274 | lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} {} | ||
275 | lua_rawget( L, cache); // ... {_i} {bfc} k {} {} n? | ||
276 | visit_count = lua_tointeger( L, -1) + 1; // 1 if we got nil, else n+1 | ||
277 | lua_pop( L, 1); // ... {_i} {bfc} k {} {} | ||
278 | lua_pushinteger( L, visit_count); // ... {_i} {bfc} k {} {} n | ||
279 | lua_rawset( L, cache); // ... {_i} {bfc} k {} | ||
280 | // store the table in the breadth-first cache | ||
281 | lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k | ||
282 | lua_insert( L, -2); // ... {_i} {bfc} k k {} | ||
283 | lua_rawset( L, breadth_first_cache); // ... {_i} {bfc} k | ||
284 | STACK_MID( L, 2) | ||
285 | } | ||
286 | else if( lua_isfunction( L, -1)) // ... {_i} {bfc} k func | ||
287 | { | ||
288 | if( luaG_getfuncsubtype( L, -1) != FST_Bytecode) | ||
289 | { | ||
290 | char const *fqnString; | ||
291 | bool_t not_registered; | ||
292 | // first, skip everything if the function is already known | ||
293 | lua_pushvalue( L, -1); // ... {_i} {bfc} k func func | ||
294 | lua_rawget( L, dest); // ... {_i} {bfc} k func name? | ||
295 | not_registered = lua_isnil( L, -1); | ||
296 | lua_pop( L, 1); // ... {_i} {bfc} k func | ||
297 | if( not_registered) | ||
298 | { | ||
299 | ++ _depth; | ||
300 | // push function name in fqn stack (note that concatenation will crash if name is a not string!) | ||
301 | lua_pushvalue( L, -2); // ... {_i} {bfc} k func k | ||
302 | lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k func | ||
303 | // generate name | ||
304 | fqnString = luaG_pushFQN( L, fqn, _depth); // ... {_i} {bfc} k func "f.q.n" | ||
305 | //puts( fqnString); | ||
306 | // prepare the stack for database feed | ||
307 | lua_pushvalue( L, -1); // ... {_i} {bfc} k func "f.q.n" "f.q.n" | ||
308 | lua_pushvalue( L, -3); // ... {_i} {bfc} k func "f.q.n" "f.q.n" func | ||
309 | // t["f.q.n"] = func | ||
310 | lua_rawset( L, dest); // ... {_i} {bfc} k func "f.q.n" | ||
311 | // t[func] = "f.q.n" | ||
312 | lua_rawset( L, dest); // ... {_i} {bfc} k | ||
313 | // remove table name from fqn stack | ||
314 | lua_pushnil( L); // ... {_i} {bfc} k nil | ||
315 | lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k | ||
316 | -- _depth; | ||
317 | } | ||
318 | else | ||
319 | { | ||
320 | lua_pop( L, 1); // ... {_i} {bfc} k | ||
321 | } | ||
322 | } | ||
323 | else | ||
324 | { | ||
325 | lua_pop( L, 1); // ... {_i} {bfc} k | ||
326 | } | ||
327 | } | ||
328 | else | ||
329 | { | ||
330 | lua_pop( L, 1); // ... {_i} {bfc} k | ||
331 | } | ||
332 | STACK_MID( L, 2) | ||
333 | } | ||
334 | // now process the tables we encountered at that depth | ||
335 | ++ _depth; | ||
336 | lua_pushnil( L); // ... {_i} {bfc} nil | ||
337 | while( lua_next( L, breadth_first_cache) != 0) // ... {_i} {bfc} k {} | ||
338 | { | ||
339 | // un-visit this table in case we do need to process it | ||
340 | lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} | ||
341 | lua_rawget( L, cache); // ... {_i} {bfc} k {} n | ||
342 | ASSERT_L( lua_type( L, -1) == LUA_TNUMBER); | ||
343 | visit_count = lua_tointeger( L, -1) - 1; | ||
344 | lua_pop( L, 1); // ... {_i} {bfc} k {} | ||
345 | lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} | ||
346 | if( visit_count > 0) | ||
347 | { | ||
348 | lua_pushinteger( L, visit_count); // ... {_i} {bfc} k {} {} n | ||
349 | } | ||
350 | else | ||
351 | { | ||
352 | lua_pushnil( L); // ... {_i} {bfc} k {} {} nil | ||
353 | } | ||
354 | lua_rawset( L, cache); // ... {_i} {bfc} k {} | ||
355 | // push table name in fqn stack (note that concatenation will crash if name is a not string!) | ||
356 | lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k | ||
357 | lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k {} | ||
358 | populate_func_lookup_table_recur( L, _ctx_base, lua_gettop( L), _depth); // ... {_i} {bfc} k {} | ||
359 | lua_pop( L, 1); // ... {_i} {bfc} k | ||
360 | STACK_MID( L, 2) | ||
361 | } | ||
362 | // remove table name from fqn stack | ||
363 | lua_pushnil( L); // ... {_i} {bfc} nil | ||
364 | lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} | ||
365 | -- _depth; | ||
366 | // we are done with our cache | ||
367 | lua_pop( L, 1); // ... {_i} | ||
368 | STACK_END( L, 0) | ||
369 | // we are done // ... {_i} {bfc} | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * create a "fully.qualified.name" <-> function equivalence dabase | ||
374 | */ | ||
375 | void populate_func_lookup_table( lua_State *L, int _i, char const *_name) | ||
376 | { | ||
377 | int const ctx_base = lua_gettop( L) + 1; | ||
378 | int const in_base = STACK_ABS( L, _i); | ||
379 | int const start_depth = _name ? 1 : 0; | ||
380 | //printf( "%p: populate_func_lookup_table('%s')\n", L, _name ? _name : "NULL"); | ||
381 | STACK_GROW( L, 3); | ||
382 | STACK_CHECK( L) | ||
383 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // {}? | ||
384 | if( lua_isnil( L, -1)) // nil | ||
385 | { | ||
386 | lua_pop( L, 1); // | ||
387 | lua_newtable( L); // {} | ||
388 | lua_pushvalue( L, -1); // {} {} | ||
389 | lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // {} | ||
390 | } | ||
391 | lua_newtable( L); // {} {fqn} | ||
392 | if( _name) | ||
393 | { | ||
394 | lua_pushstring( L, _name); // {} {fqn} "name" | ||
395 | lua_rawseti( L, -2, start_depth); // {} {fqn} | ||
396 | } | ||
397 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache}? | ||
398 | if( lua_isnil( L, -1)) | ||
399 | { | ||
400 | lua_pop( L, 1); // {} {fqn} | ||
401 | lua_newtable( L); // {} {fqn} {cache} | ||
402 | lua_pushvalue( L, -1); // {} {fqn} {cache} {cache} | ||
403 | lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache} | ||
404 | } | ||
405 | populate_func_lookup_table_recur( L, ctx_base, in_base, start_depth); // {...} {fqn} {cache} | ||
406 | lua_pop( L, 3); | ||
407 | STACK_END( L, 0) | ||
126 | } | 408 | } |
127 | 409 | ||
128 | /* | 410 | /* |
@@ -139,33 +421,39 @@ static bool_t openlib( lua_State *L, const char *name, size_t len ) { | |||
139 | */ | 421 | */ |
140 | #define is_name_char(c) (isalpha(c) || (c)=='*') | 422 | #define is_name_char(c) (isalpha(c) || (c)=='*') |
141 | 423 | ||
142 | const char *luaG_openlibs( lua_State *L, const char *libs ) { | 424 | const char *luaG_openlibs( lua_State *L, const char *libs) |
143 | const char *p; | 425 | { |
144 | unsigned len; | 426 | const char *p; |
427 | unsigned len; | ||
145 | 428 | ||
146 | if (!libs) return NULL; // no libs, not even 'base' | 429 | if (!libs) return NULL; // no libs, not even 'base' |
147 | 430 | ||
148 | // 'lua.c' stops GC during initialization so perhaps its a good idea. :) | 431 | // 'lua.c' stops GC during initialization so perhaps its a good idea. :) |
149 | // | 432 | // |
150 | lua_gc(L, LUA_GCSTOP, 0); | 433 | lua_gc( L, LUA_GCSTOP, 0); |
151 | 434 | ||
152 | // Anything causes 'base' to be taken in | 435 | // Anything causes 'base' to be taken in |
153 | // | 436 | // |
154 | STACK_GROW(L,2); | 437 | STACK_GROW(L,2); |
155 | lua_pushcfunction( L, luaopen_base ); | 438 | STACK_CHECK(L) |
156 | lua_pushliteral( L, "" ); | 439 | lua_pushcfunction( L, luaopen_base); |
157 | lua_call( L, 1, 0 ); | 440 | lua_call( L, 0, 1); |
158 | 441 | // after opening base, register the functions they exported in our name<->function database | |
159 | for( p= libs; *p; p+=len ) { | 442 | populate_func_lookup_table( L, LUA_GLOBALSINDEX, NULL); |
160 | len=0; | 443 | lua_pop( L, 1); |
161 | while (*p && !is_name_char(*p)) p++; // bypass delimiters | 444 | STACK_MID( L, 0); |
162 | while (is_name_char(p[len])) len++; // bypass name | 445 | for( p= libs; *p; p+=len ) |
163 | if (len && (!openlib( L, p, len ))) | 446 | { |
164 | break; | 447 | len=0; |
165 | } | 448 | while (*p && !is_name_char(*p)) p++; // bypass delimiters |
166 | lua_gc(L, LUA_GCRESTART, 0); | 449 | while (is_name_char(p[len])) len++; // bypass name |
450 | if (len && (!openlib( L, p, len ))) | ||
451 | break; | ||
452 | } | ||
453 | STACK_END(L,0) | ||
454 | lua_gc(L, LUA_GCRESTART, 0); | ||
167 | 455 | ||
168 | return *p ? p : NULL; | 456 | return *p ? p : NULL; |
169 | } | 457 | } |
170 | 458 | ||
171 | 459 | ||
@@ -284,7 +572,7 @@ luaG_IdFunction get_idfunc( lua_State *L, int index ) | |||
284 | { | 572 | { |
285 | luaG_IdFunction ret; | 573 | luaG_IdFunction ret; |
286 | 574 | ||
287 | index= STACK_ABS(L,index); | 575 | index = STACK_ABS( L, index); |
288 | 576 | ||
289 | STACK_GROW(L,1); | 577 | STACK_GROW(L,1); |
290 | 578 | ||
@@ -696,7 +984,7 @@ uint_t get_mt_id( lua_State *L, int i ) { | |||
696 | static uint_t last_id= 0; | 984 | static uint_t last_id= 0; |
697 | uint_t id; | 985 | uint_t id; |
698 | 986 | ||
699 | i= STACK_ABS(L,i); | 987 | i = STACK_ABS( L, i); |
700 | 988 | ||
701 | STACK_GROW(L,3); | 989 | STACK_GROW(L,3); |
702 | 990 | ||
@@ -819,8 +1107,8 @@ static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uin | |||
819 | 1107 | ||
820 | static void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) | 1108 | static void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) |
821 | { | 1109 | { |
1110 | void * const aspointer = (void*)lua_topointer( L, i ); | ||
822 | // TBD: Merge this and same code for tables | 1111 | // TBD: Merge this and same code for tables |
823 | |||
824 | ASSERT_L( L2_cache_i != 0 ); | 1112 | ASSERT_L( L2_cache_i != 0 ); |
825 | 1113 | ||
826 | STACK_GROW(L2,3); | 1114 | STACK_GROW(L2,3); |
@@ -832,7 +1120,7 @@ static void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, ui | |||
832 | // We don't need to use the from state ('L') in ID since the life span | 1120 | // We don't need to use the from state ('L') in ID since the life span |
833 | // is only for the duration of a copy (both states are locked). | 1121 | // is only for the duration of a copy (both states are locked). |
834 | // | 1122 | // |
835 | lua_pushlightuserdata( L2, (void*)lua_topointer( L, i )); // push a light userdata uniquely representing the function | 1123 | lua_pushlightuserdata( L2, aspointer); // push a light userdata uniquely representing the function |
836 | 1124 | ||
837 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); | 1125 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); |
838 | 1126 | ||
@@ -886,9 +1174,46 @@ static void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, ui | |||
886 | // | 1174 | // |
887 | // L2 [-1]: function | 1175 | // L2 [-1]: function |
888 | 1176 | ||
889 | ASSERT_L( lua_isfunction(L2,-1) ); | 1177 | ASSERT_L( lua_isfunction(L2,-1)); |
890 | } | 1178 | } |
891 | 1179 | ||
1180 | /* | ||
1181 | * Push a looked-up native/LuaJIT function. | ||
1182 | */ | ||
1183 | static void lookup_native_func( lua_State *L2, lua_State *L, uint_t i) | ||
1184 | { | ||
1185 | char const *fqn; | ||
1186 | size_t len; | ||
1187 | _ASSERT_L( L, lua_isfunction( L, i)); | ||
1188 | STACK_CHECK( L) | ||
1189 | STACK_CHECK( L2) | ||
1190 | // fetch the name from the source state's lookup table | ||
1191 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // {} | ||
1192 | _ASSERT_L( L, lua_istable( L, -1)); | ||
1193 | lua_pushvalue( L, i); // {} f | ||
1194 | lua_rawget( L, -2); // {} "f.q.n" | ||
1195 | fqn = lua_tolstring( L, -1, &len); | ||
1196 | if( !fqn) | ||
1197 | { | ||
1198 | luaL_error( L, "function not found in origin transfer database."); | ||
1199 | } | ||
1200 | // push the equivalent function in the destination's stack, retrieved from the lookup table | ||
1201 | lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_KEY); // {} | ||
1202 | _ASSERT_L( L2, lua_istable( L2, -1)); | ||
1203 | lua_pushlstring( L2, fqn, len); // {} "f.q.n" | ||
1204 | lua_pop( L, 2); // | ||
1205 | lua_rawget( L2, -2); // {} f | ||
1206 | if( !lua_isfunction( L2, -1)) | ||
1207 | { | ||
1208 | // yarglah: luaL_error formatting doesn't support string width modifier! | ||
1209 | char message[256]; | ||
1210 | sprintf( message, "function %*s not found in destination transfer database.", len, fqn); | ||
1211 | luaL_error( L, message); | ||
1212 | } | ||
1213 | lua_remove( L2, -2); // f | ||
1214 | STACK_END( L2, 1) | ||
1215 | STACK_END( L, 0) | ||
1216 | } | ||
892 | 1217 | ||
893 | #define LOG_FUNC_INFO 0 | 1218 | #define LOG_FUNC_INFO 0 |
894 | 1219 | ||
@@ -900,114 +1225,132 @@ enum e_vt { | |||
900 | }; | 1225 | }; |
901 | static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i, enum e_vt value_type ); | 1226 | static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i, enum e_vt value_type ); |
902 | 1227 | ||
903 | static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) { | 1228 | static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) |
904 | 1229 | { | |
905 | lua_CFunction cfunc= lua_tocfunction( L,i ); | 1230 | FuncSubType funcSubType; |
906 | unsigned n; | 1231 | lua_CFunction cfunc = luaG_tocfunction( L, i, &funcSubType); // NULL for LuaJIT-fast && bytecode functions |
907 | 1232 | i = STACK_ABS( L, i); | |
908 | ASSERT_L( L2_cache_i != 0 ); | ||
909 | |||
910 | STACK_GROW(L,2); | ||
911 | |||
912 | STACK_CHECK(L) | ||
913 | if (!cfunc) { // Lua function | ||
914 | luaL_Buffer b; | ||
915 | const char *s; | ||
916 | size_t sz; | ||
917 | int tmp; | ||
918 | const char *name= NULL; | ||
919 | int linedefined = 0; | ||
920 | 1233 | ||
921 | #if LOG_FUNC_INFO | 1234 | ASSERT_L( L2_cache_i != 0 ); |
922 | // "To get information about a function you push it onto the | 1235 | STACK_GROW(L,2); |
923 | // stack and start the what string with the character '>'." | 1236 | STACK_CHECK(L) |
924 | // | ||
925 | { lua_Debug ar; | ||
926 | lua_pushvalue( L, i ); | ||
927 | lua_getinfo(L, ">nS", &ar); // fills 'name' 'namewhat' and 'linedefined', pops function | ||
928 | name= ar.namewhat; | ||
929 | linedefined = ar.linedefined; | ||
930 | fprintf( stderr, "NAME: %s @ %d\n", ar.short_src, linedefined); // just gives NULL | ||
931 | } | ||
932 | #endif // LOG_FUNC_INFO | ||
933 | // 'lua_dump()' needs the function at top of stack | ||
934 | // | ||
935 | if (i!=-1) lua_pushvalue( L, i ); | ||
936 | 1237 | ||
937 | luaL_buffinit(L,&b); | 1238 | if( funcSubType == FST_Bytecode) |
938 | tmp= lua_dump(L, buf_writer, &b); | 1239 | { |
939 | ASSERT_L(tmp==0); | 1240 | unsigned n; |
940 | // | 1241 | luaL_Buffer b; |
941 | // "value returned is the error code returned by the last call | 1242 | // 'lua_dump()' needs the function at top of stack |
942 | // to the writer" (and we only return 0) | 1243 | // if already on top of the stack, no need to push again |
1244 | int needToPush = (i != lua_gettop( L)); | ||
1245 | if( needToPush) | ||
1246 | lua_pushvalue( L, i); | ||
1247 | |||
1248 | luaL_buffinit( L, &b); | ||
1249 | // | ||
1250 | // "value returned is the error code returned by the last call | ||
1251 | // to the writer" (and we only return 0) | ||
1252 | // not sure this could ever fail but for memory shortage reasons | ||
1253 | if( lua_dump( L, buf_writer, &b) != 0) | ||
1254 | { | ||
1255 | luaL_error( L, "internal error: function dump failed."); | ||
1256 | } | ||
943 | 1257 | ||
944 | luaL_pushresult(&b); // pushes dumped string on 'L' | 1258 | luaL_pushresult( &b); // pushes dumped string on 'L' |
945 | s= lua_tolstring(L,-1,&sz); | ||
946 | ASSERT_L( s && sz ); | ||
947 | 1259 | ||
948 | if (i!=-1) lua_remove( L, -2 ); | 1260 | // if not pushed, no need to pop |
1261 | if( needToPush) | ||
1262 | { | ||
1263 | lua_remove( L, -2); | ||
1264 | } | ||
949 | 1265 | ||
950 | // Note: Line numbers seem to be taken precisely from the | 1266 | // transfer the bytecode, then the upvalues, to create a similar closure |
951 | // original function. 'name' is not used since the chunk | 1267 | { |
952 | // is precompiled (it seems...). | 1268 | const char *name= NULL; |
953 | // | 1269 | |
954 | // TBD: Can we get the function's original name through, as well? | 1270 | #if LOG_FUNC_INFO |
955 | // | 1271 | // "To get information about a function you push it onto the |
956 | if (luaL_loadbuffer(L2, s, sz, name) != 0) { | 1272 | // stack and start the what string with the character '>'." |
957 | // chunk is precompiled so only LUA_ERRMEM can happen | 1273 | // |
958 | // "Otherwise, it pushes an error message" | 1274 | { |
959 | // | 1275 | lua_Debug ar; |
960 | STACK_GROW( L,1 ); | 1276 | lua_pushvalue( L, i ); |
961 | luaL_error( L, "%s", lua_tostring(L2,-1) ); | 1277 | lua_getinfo(L, ">nS", &ar); // fills 'name' 'namewhat' and 'linedefined', pops function |
962 | } | 1278 | name= ar.namewhat; |
963 | lua_pop(L,1); // remove the dumped string | 1279 | fprintf( stderr, "NAME: %s @ %d\n", ar.short_src, ar.linedefined); // just gives NULL |
964 | STACK_MID(L,0) | 1280 | } |
965 | } | 1281 | #endif // LOG_FUNC_INFO |
1282 | { | ||
1283 | const char *s; | ||
1284 | size_t sz; | ||
1285 | s = lua_tolstring( L, -1, &sz); | ||
1286 | ASSERT_L( s && sz); | ||
1287 | |||
1288 | // Note: Line numbers seem to be taken precisely from the | ||
1289 | // original function. 'name' is not used since the chunk | ||
1290 | // is precompiled (it seems...). | ||
1291 | // | ||
1292 | // TBD: Can we get the function's original name through, as well? | ||
1293 | // | ||
1294 | if (luaL_loadbuffer(L2, s, sz, name) != 0) | ||
1295 | { | ||
1296 | // chunk is precompiled so only LUA_ERRMEM can happen | ||
1297 | // "Otherwise, it pushes an error message" | ||
1298 | // | ||
1299 | STACK_GROW( L,1); | ||
1300 | luaL_error( L, "%s", lua_tostring(L2,-1)); | ||
1301 | } | ||
1302 | lua_pop( L, 1); // remove the dumped string | ||
1303 | } | ||
1304 | STACK_MID( L, 0) | ||
1305 | |||
1306 | /* push over any upvalues; references to this function will come from | ||
1307 | * cache so we don't end up in eternal loop. | ||
1308 | */ | ||
1309 | for( n=0; lua_getupvalue( L, i, 1+n ) != NULL; n++ ) | ||
1310 | { | ||
1311 | if ((!cfunc) && lua_equal(L,i,-1)) | ||
1312 | { | ||
1313 | /* Lua closure that has a (recursive) upvalue to itself | ||
1314 | */ | ||
1315 | lua_pushvalue( L2, -((int)n)-1 ); | ||
1316 | } | ||
1317 | else | ||
1318 | { | ||
1319 | if( !inter_copy_one_( L2, L2_cache_i, L, lua_gettop(L), VT_NORMAL)) | ||
1320 | luaL_error( L, "Cannot copy upvalue type '%s'", luaG_typename( L, -1)); | ||
1321 | } | ||
1322 | lua_pop( L, 1); | ||
1323 | } | ||
1324 | // L2: function + 'n' upvalues (>=0) | ||
1325 | |||
1326 | STACK_MID(L,0) | ||
1327 | |||
1328 | // Set upvalues (originally set to 'nil' by 'lua_load') | ||
1329 | { | ||
1330 | int func_index = lua_gettop( L2) - n; | ||
1331 | for( ; n > 0; -- n) | ||
1332 | { | ||
1333 | char const *rc = lua_setupvalue( L2, func_index, n); | ||
1334 | // | ||
1335 | // "assigns the value at the top of the stack to the upvalue and returns its name. | ||
1336 | // It also pops the value from the stack." | ||
1337 | |||
1338 | ASSERT_L(rc); // not having enough slots? | ||
1339 | } | ||
1340 | } | ||
1341 | } | ||
1342 | } | ||
1343 | else // C function OR LuaJIT fast function!!! | ||
1344 | { | ||
966 | #if LOG_FUNC_INFO | 1345 | #if LOG_FUNC_INFO |
967 | else | 1346 | fprintf( stderr, "NAME: [C] function %p \n", cfunc); |
968 | { | ||
969 | fprintf( stderr, "NAME: [C] function %p \n", cfunc); | ||
970 | } | ||
971 | #endif // LOG_FUNC_INFO | 1347 | #endif // LOG_FUNC_INFO |
972 | 1348 | // No need to transfer upvalues for C/JIT functions since they weren't actually copied, only looked up | |
973 | /* push over any upvalues; references to this function will come from | 1349 | lookup_native_func( L2, L, i); |
974 | * cache so we don't end up in eternal loop. | 1350 | } |
975 | */ | 1351 | STACK_END(L,0) |
976 | for( n=0; lua_getupvalue( L, i, 1+n ) != NULL; n++ ) { | ||
977 | if ((!cfunc) && lua_equal(L,i,-1)) { | ||
978 | /* Lua closure that has a (recursive) upvalue to itself | ||
979 | */ | ||
980 | lua_pushvalue( L2, -((int)n)-1 ); | ||
981 | } else { | ||
982 | if (!inter_copy_one_( L2, L2_cache_i, L, lua_gettop(L), VT_NORMAL )) | ||
983 | luaL_error( L, "Cannot copy upvalue type '%s'", luaG_typename(L,-1) ); | ||
984 | } | ||
985 | lua_pop(L,1); | ||
986 | } | ||
987 | // L2: function + 'n' upvalues (>=0) | ||
988 | |||
989 | STACK_MID(L,0) | ||
990 | |||
991 | if (cfunc) { | ||
992 | lua_pushcclosure( L2, cfunc, n ); // eats up upvalues | ||
993 | } else { | ||
994 | // Set upvalues (originally set to 'nil' by 'lua_load') | ||
995 | // | ||
996 | int func_index= lua_gettop(L2)-n; | ||
997 | |||
998 | for( ; n>0; n-- ) { | ||
999 | const char *rc= lua_setupvalue( L2, func_index, n ); | ||
1000 | // | ||
1001 | // "assigns the value at the top of the stack to the upvalue and returns its name. | ||
1002 | // It also pops the value from the stack." | ||
1003 | |||
1004 | ASSERT_L(rc); // not having enough slots? | ||
1005 | } | ||
1006 | } | ||
1007 | STACK_END(L,0) | ||
1008 | } | 1352 | } |
1009 | 1353 | ||
1010 | |||
1011 | /* | 1354 | /* |
1012 | * Copies a value from 'L' state (at index 'i') to 'L2' state. Does not remove | 1355 | * Copies a value from 'L' state (at index 'i') to 'L2' state. Does not remove |
1013 | * the original value. | 1356 | * the original value. |
@@ -1300,32 +1643,36 @@ MUTEX_T require_cs; | |||
1300 | // | 1643 | // |
1301 | // Upvalues: [1]: original 'require' function | 1644 | // Upvalues: [1]: original 'require' function |
1302 | // | 1645 | // |
1303 | static int new_require( lua_State *L ) | 1646 | static int new_require( lua_State *L) |
1304 | { | 1647 | { |
1305 | int rc; | 1648 | int rc, i; |
1306 | int args= lua_gettop(L); | 1649 | int args = lua_gettop( L); |
1650 | //char const *modname = luaL_checkstring( L, 1); | ||
1307 | 1651 | ||
1308 | STACK_GROW(L,1); | 1652 | STACK_GROW( L, args + 1); |
1309 | STACK_CHECK(L) | 1653 | STACK_CHECK( L) |
1654 | |||
1655 | lua_pushvalue( L, lua_upvalueindex(1)); | ||
1656 | for( i = 1; i <= args; ++ i) | ||
1657 | lua_pushvalue( L, i); | ||
1310 | 1658 | ||
1311 | // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would | 1659 | // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would |
1312 | // leave us locked, blocking any future 'require' calls from other lanes. | 1660 | // leave us locked, blocking any future 'require' calls from other lanes. |
1313 | // | 1661 | // |
1314 | MUTEX_LOCK( &require_cs); | 1662 | MUTEX_LOCK( &require_cs); |
1315 | { | 1663 | { |
1316 | lua_pushvalue( L, lua_upvalueindex(1) ); | 1664 | rc = lua_pcall( L, args, 1 /*retvals*/, 0 /*errfunc*/ ); |
1317 | lua_insert( L, 1 ); | ||
1318 | |||
1319 | rc= lua_pcall( L, args, 1 /*retvals*/, 0 /*errfunc*/ ); | ||
1320 | // | 1665 | // |
1321 | // LUA_ERRRUN / LUA_ERRMEM | 1666 | // LUA_ERRRUN / LUA_ERRMEM |
1322 | } | 1667 | } |
1323 | MUTEX_UNLOCK( &require_cs); | 1668 | MUTEX_UNLOCK( &require_cs); |
1324 | 1669 | ||
1670 | // the required module (or an error message) is left on the stack as returned value by original require function | ||
1671 | STACK_END( L, 1) | ||
1672 | |||
1325 | if (rc) | 1673 | if (rc) |
1326 | lua_error(L); // error message already at [-1] | 1674 | lua_error(L); // error message already at [-1] |
1327 | 1675 | ||
1328 | STACK_END(L,0) | ||
1329 | return 1; | 1676 | return 1; |
1330 | } | 1677 | } |
1331 | 1678 | ||