diff options
| author | Benoit Germain <bnt period germain arrobase gmail period com> | 2017-06-05 11:25:31 +0200 |
|---|---|---|
| committer | Benoit Germain <bnt period germain arrobase gmail period com> | 2017-06-05 11:25:31 +0200 |
| commit | c2ca1fce531e29f8209660b18ef0a493722813f1 (patch) | |
| tree | 3afa59fb910b2aaee79cbccc9a58fc961b3b8868 /src | |
| parent | 0ede50e2da00f2915ceb50184425c42bda83adfd (diff) | |
| download | lanes-c2ca1fce531e29f8209660b18ef0a493722813f1.tar.gz lanes-c2ca1fce531e29f8209660b18ef0a493722813f1.tar.bz2 lanes-c2ca1fce531e29f8209660b18ef0a493722813f1.zip | |
Table transfer improvements
* new API function lanes.register( "name", module) to manually register
a module table after it was required
* Transfering registered module tables will link the equivalent in the
destination state instead of cloning it
* bumped version to 3.11
Diffstat (limited to 'src')
| -rw-r--r-- | src/lanes.c | 42 | ||||
| -rw-r--r-- | src/lanes.lua | 18 | ||||
| -rw-r--r-- | src/tools.c | 318 |
3 files changed, 269 insertions, 109 deletions
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 affbd7d..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 | ||
| @@ -716,6 +715,7 @@ lanes.configure = function( settings_) | |||
| 716 | 715 | ||
| 717 | -- activate full interface | 716 | -- activate full interface |
| 718 | lanes.require = core.require | 717 | lanes.require = core.require |
| 718 | lanes.register = core.register | ||
| 719 | lanes.gen = gen | 719 | lanes.gen = gen |
| 720 | lanes.linda = core.linda | 720 | lanes.linda = core.linda |
| 721 | lanes.cancel_error = core.cancel_error | 721 | lanes.cancel_error = core.cancel_error |
| @@ -734,20 +734,18 @@ lanes.configure = function( settings_) | |||
| 734 | return lanes | 734 | return lanes |
| 735 | end -- lanes.configure | 735 | end -- lanes.configure |
| 736 | 736 | ||
| 737 | lanesMeta.__index = function(t,k) | 737 | lanesMeta.__index = function( t, k) |
| 738 | -- This is called when some functionality is accessed without calling configure() | 738 | -- This is called when some functionality is accessed without calling configure() |
| 739 | lanes.configure() -- Initialize with default settings | 739 | lanes.configure() -- initialize with default settings |
| 740 | -- Access the required key | 740 | -- Access the required key |
| 741 | return lanes[k] | 741 | return lanes[k] |
| 742 | end | 742 | end |
| 743 | 743 | ||
| 744 | -- 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) |
| 745 | if core.settings then | 745 | if core.settings then |
| 746 | return lanes.configure() | 746 | return lanes.configure() |
| 747 | else | 747 | else |
| 748 | return lanes | 748 | return lanes |
| 749 | end | 749 | end |
| 750 | 750 | ||
| 751 | 751 | --the end | |
| 752 | --the end (Unreachable Code) | ||
| 753 | --return lanes | ||
diff --git a/src/tools.c b/src/tools.c index d97b231..a4d781f 100644 --- a/src/tools.c +++ b/src/tools.c | |||
| @@ -85,7 +85,7 @@ void luaG_dump( lua_State* L) | |||
| 85 | { | 85 | { |
| 86 | int type = lua_type( L, i); | 86 | int type = lua_type( L, i); |
| 87 | 87 | ||
| 88 | fprintf( stderr, "\t[%d]= (%s) ", i, lua_typename(L, type)); | 88 | fprintf( stderr, "\t[%d]= (%s) ", i, lua_typename( L, type)); |
| 89 | 89 | ||
| 90 | // Print item contents here... | 90 | // Print item contents here... |
| 91 | // | 91 | // |
| @@ -99,7 +99,7 @@ void luaG_dump( lua_State* L) | |||
| 99 | // | 99 | // |
| 100 | // [-1]: tostring function, or nil | 100 | // [-1]: tostring function, or nil |
| 101 | 101 | ||
| 102 | if( !lua_isfunction(L, -1)) | 102 | if( !lua_isfunction( L, -1)) |
| 103 | { | 103 | { |
| 104 | fprintf( stderr, "('tostring' not available)"); | 104 | fprintf( stderr, "('tostring' not available)"); |
| 105 | } | 105 | } |
| @@ -110,7 +110,7 @@ void luaG_dump( lua_State* L) | |||
| 110 | 110 | ||
| 111 | // Don't trust the string contents | 111 | // Don't trust the string contents |
| 112 | // | 112 | // |
| 113 | fprintf( stderr, "%s", lua_tostring(L, -1)); | 113 | fprintf( stderr, "%s", lua_tostring( L, -1)); |
| 114 | } | 114 | } |
| 115 | lua_pop( L, 1); | 115 | lua_pop( L, 1); |
| 116 | STACK_END( L, 0); | 116 | STACK_END( L, 0); |
| @@ -258,7 +258,8 @@ static void open1lib( struct s_Universe* U, lua_State* L, char const* name_, siz | |||
| 258 | } | 258 | } |
| 259 | } | 259 | } |
| 260 | 260 | ||
| 261 | 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) | ||
| 262 | { | 263 | { |
| 263 | (void)L; (void)p; (void)sz; (void) ud; // unused | 264 | (void)L; (void)p; (void)sz; (void) ud; // unused |
| 264 | return 666; | 265 | return 666; |
| @@ -326,12 +327,12 @@ static lua_CFunction luaG_tocfunction( lua_State *L, int _i, FuncSubType *_out) | |||
| 326 | 327 | ||
| 327 | 328 | ||
| 328 | // inspired from tconcat() in ltablib.c | 329 | // inspired from tconcat() in ltablib.c |
| 329 | 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) |
| 330 | { | 331 | { |
| 331 | int i = 1; | 332 | int i = 1; |
| 332 | luaL_Buffer b; | 333 | luaL_Buffer b; |
| 333 | STACK_CHECK( L); | 334 | STACK_CHECK( L); |
| 334 | luaL_buffinit(L, &b); | 335 | luaL_buffinit( L, &b); |
| 335 | for( ; i < last; ++ i) | 336 | for( ; i < last; ++ i) |
| 336 | { | 337 | { |
| 337 | lua_rawgeti( L, t, i); | 338 | lua_rawgeti( L, t, i); |
| @@ -349,10 +350,12 @@ static char const* luaG_pushFQN(lua_State *L, int t, int last, size_t* length) | |||
| 349 | } | 350 | } |
| 350 | 351 | ||
| 351 | /* | 352 | /* |
| 353 | * receives 2 arguments: a name k and an object o | ||
| 352 | * add two entries ["fully.qualified.name"] = o | 354 | * add two entries ["fully.qualified.name"] = o |
| 353 | * and [o] = "fully.qualified.name" | 355 | * and [o] = "fully.qualified.name" |
| 354 | * where <o> is either a table or a function | 356 | * where <o> is either a table or a function |
| 355 | * if we already had an entry of type [o] = ..., replace the name if the new one is shorter | 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 | ||
| 356 | */ | 359 | */ |
| 357 | static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth) | 360 | static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth) |
| 358 | { | 361 | { |
| @@ -364,12 +367,16 @@ static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth) | |||
| 364 | size_t prevNameLength, newNameLength; | 367 | size_t prevNameLength, newNameLength; |
| 365 | char const* prevName; | 368 | char const* prevName; |
| 366 | DEBUGSPEW_CODE( char const *newName); | 369 | DEBUGSPEW_CODE( char const *newName); |
| 370 | DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); | ||
| 371 | |||
| 372 | STACK_CHECK( L); | ||
| 367 | // first, raise an error if the function is already known | 373 | // first, raise an error if the function is already known |
| 368 | lua_pushvalue( L, -1); // ... {bfc} k o o | 374 | lua_pushvalue( L, -1); // ... {bfc} k o o |
| 369 | lua_rawget( L, dest); // ... {bfc} k o name? | 375 | lua_rawget( L, dest); // ... {bfc} k o name? |
| 370 | prevName = lua_tolstring( L, -1, &prevNameLength); // NULL if we got nil (first encounter of this object) | 376 | prevName = lua_tolstring( L, -1, &prevNameLength); // NULL if we got nil (first encounter of this object) |
| 371 | // push name in fqn stack (note that concatenation will crash if name is a not string or a number) | 377 | // push name in fqn stack (note that concatenation will crash if name is a not string or a number) |
| 372 | lua_pushvalue( L, -3); // ... {bfc} k o name? k | 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); | ||
| 373 | ++ _depth; | 380 | ++ _depth; |
| 374 | lua_rawseti( L, fqn, _depth); // ... {bfc} k o name? | 381 | lua_rawseti( L, fqn, _depth); // ... {bfc} k o name? |
| 375 | // generate name | 382 | // generate name |
| @@ -385,7 +392,7 @@ static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth) | |||
| 385 | // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded | 392 | // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded |
| 386 | if( prevName != NULL && (prevNameLength < newNameLength || lua_lessthan( L, -2, -1))) | 393 | if( prevName != NULL && (prevNameLength < newNameLength || lua_lessthan( L, -2, -1))) |
| 387 | { | 394 | { |
| 388 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END, lua_typename( L, -3), newName, prevName)); | 395 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -3)), newName, prevName)); |
| 389 | // the previous name is 'smaller' than the one we just generated: keep it! | 396 | // the previous name is 'smaller' than the one we just generated: keep it! |
| 390 | lua_pop( L, 3); // ... {bfc} k | 397 | lua_pop( L, 3); // ... {bfc} k |
| 391 | } | 398 | } |
| @@ -404,7 +411,7 @@ static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth) | |||
| 404 | { | 411 | { |
| 405 | lua_remove( L, -2); // ... {bfc} k o "f.q.n" | 412 | lua_remove( L, -2); // ... {bfc} k o "f.q.n" |
| 406 | } | 413 | } |
| 407 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END, lua_typename( L, -2), newName)); | 414 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -2)), newName)); |
| 408 | // prepare the stack for database feed | 415 | // prepare the stack for database feed |
| 409 | lua_pushvalue( L, -1); // ... {bfc} k o "f.q.n" "f.q.n" | 416 | lua_pushvalue( L, -1); // ... {bfc} k o "f.q.n" "f.q.n" |
| 410 | lua_pushvalue( L, -3); // ... {bfc} k o "f.q.n" "f.q.n" o | 417 | lua_pushvalue( L, -3); // ... {bfc} k o "f.q.n" "f.q.n" o |
| @@ -419,6 +426,7 @@ static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth) | |||
| 419 | lua_rawseti( L, fqn, _depth); // ... {bfc} k | 426 | lua_rawseti( L, fqn, _depth); // ... {bfc} k |
| 420 | } | 427 | } |
| 421 | -- _depth; | 428 | -- _depth; |
| 429 | STACK_END( L, -1); | ||
| 422 | } | 430 | } |
| 423 | 431 | ||
| 424 | 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) |
| @@ -547,7 +555,7 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) | |||
| 547 | { | 555 | { |
| 548 | int const ctx_base = lua_gettop( L) + 1; | 556 | int const ctx_base = lua_gettop( L) + 1; |
| 549 | int const in_base = lua_absindex( L, _i); | 557 | int const in_base = lua_absindex( L, _i); |
| 550 | int const start_depth = name_ ? 1 : 0; | 558 | int start_depth = 0; |
| 551 | DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); | 559 | DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); |
| 552 | 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")); |
| 553 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 561 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
| @@ -571,9 +579,17 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) | |||
| 571 | lua_newtable( L); // {} {fqn} | 579 | lua_newtable( L); // {} {fqn} |
| 572 | if( name_) | 580 | if( name_) |
| 573 | { | 581 | { |
| 582 | STACK_MID( L, 2); | ||
| 574 | 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; | ||
| 575 | lua_rawseti( L, -2, start_depth); // {} {fqn} | 589 | lua_rawseti( L, -2, start_depth); // {} {fqn} |
| 590 | STACK_MID( L, 2); | ||
| 576 | } | 591 | } |
| 592 | // retrieve the cache, create it if we haven't done it yet | ||
| 577 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache}? | 593 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache}? |
| 578 | if( lua_isnil( L, -1)) | 594 | if( lua_isnil( L, -1)) |
| 579 | { | 595 | { |
| @@ -582,6 +598,7 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) | |||
| 582 | lua_pushvalue( L, -1); // {} {fqn} {cache} {cache} | 598 | lua_pushvalue( L, -1); // {} {fqn} {cache} {cache} |
| 583 | lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache} | 599 | lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache} |
| 584 | } | 600 | } |
| 601 | // process everything we find in that table, filling in lookup data for all functions and tables we see there | ||
| 585 | 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} |
| 586 | lua_pop( L, 3); | 603 | lua_pop( L, 3); |
| 587 | } | 604 | } |
| @@ -823,6 +840,158 @@ static int buf_writer( lua_State *L, const void* b, size_t n, void* B ) { | |||
| 823 | } | 840 | } |
| 824 | 841 | ||
| 825 | 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 | |||
| 826 | /* | 995 | /* |
| 827 | * 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 |
| 828 | * reuse the old copy. This allows table upvalues shared by multiple | 997 | * reuse the old copy. This allows table upvalues shared by multiple |
| @@ -847,7 +1016,7 @@ static bool_t push_cached_table( lua_State* L2, uint_t L2_cache_i, lua_State* L, | |||
| 847 | // push a light userdata uniquely representing the table | 1016 | // push a light userdata uniquely representing the table |
| 848 | lua_pushlightuserdata( L2, p); // ... p | 1017 | lua_pushlightuserdata( L2, p); // ... p |
| 849 | 1018 | ||
| 850 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); | 1019 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring( L2, -1)); |
| 851 | 1020 | ||
| 852 | lua_rawget( L2, L2_cache_i); // ... {cached|nil} | 1021 | lua_rawget( L2, L2_cache_i); // ... {cached|nil} |
| 853 | not_found_in_cache = lua_isnil( L2, -1); | 1022 | not_found_in_cache = lua_isnil( L2, -1); |
| @@ -1002,6 +1171,7 @@ static int discover_object_name_recur( lua_State* L, int shortest_, int depth_) | |||
| 1002 | return shortest_; | 1171 | return shortest_; |
| 1003 | } | 1172 | } |
| 1004 | 1173 | ||
| 1174 | |||
| 1005 | /* | 1175 | /* |
| 1006 | * "type", "name" = lanes.nameof( o) | 1176 | * "type", "name" = lanes.nameof( o) |
| 1007 | */ | 1177 | */ |
| @@ -1049,72 +1219,17 @@ int luaG_nameof( lua_State* L) | |||
| 1049 | return 2; | 1219 | return 2; |
| 1050 | } | 1220 | } |
| 1051 | 1221 | ||
| 1052 | // function sentinel used to transfer native functions from/to keeper states | ||
| 1053 | static int sentinelfunc( lua_State* L) | ||
| 1054 | { | ||
| 1055 | return luaL_error( L, "transfer sentinel function for %s, should never be called", lua_tostring( L, lua_upvalueindex( 1))); | ||
| 1056 | } | ||
| 1057 | 1222 | ||
| 1058 | /* | 1223 | /* |
| 1059 | * Push a looked-up native/LuaJIT function. | 1224 | * Push a looked-up native/LuaJIT function. |
| 1060 | */ | 1225 | */ |
| 1061 | 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_) |
| 1062 | { | 1227 | { |
| 1063 | char const* fqn; // L // L2 | 1228 | // get the name of the function we want to send |
| 1064 | size_t len; | 1229 | size_t len; |
| 1065 | ASSERT_L( lua_isfunction( L, i)); // ... f ... | 1230 | char const* fqn = find_lookup_name( L, i, mode_, upName_, &len); |
| 1066 | STACK_CHECK( L); | ||
| 1067 | STACK_GROW( L, 3); // up to 3 slots are necessary on error | ||
| 1068 | if( mode_ == eLM_FromKeeper) | ||
| 1069 | { | ||
| 1070 | lua_CFunction f = lua_tocfunction( L, i); // should *always* be sentinelfunc! | ||
| 1071 | ASSERT_L( f == sentinelfunc); | ||
| 1072 | lua_getupvalue( L, i, 1); // ... f ... "f.q.n" | ||
| 1073 | fqn = lua_tolstring( L, -1, &len); | ||
| 1074 | } | ||
| 1075 | else | ||
| 1076 | { | ||
| 1077 | // fetch the name from the source state's lookup table | ||
| 1078 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // ... f ... {} | ||
| 1079 | ASSERT_L( lua_istable( L, -1)); | ||
| 1080 | lua_pushvalue( L, i); // ... f ... {} f | ||
| 1081 | lua_rawget( L, -2); // ... f ... {} "f.q.n" | ||
| 1082 | fqn = lua_tolstring( L, -1, &len); | ||
| 1083 | } | ||
| 1084 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END, fqn)); | ||
| 1085 | // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database | ||
| 1086 | lua_pop( L, (mode_ == eLM_FromKeeper) ? 1 : 2); // ... f ... | ||
| 1087 | STACK_MID( L, 0); | ||
| 1088 | if( !fqn) | ||
| 1089 | { | ||
| 1090 | char const *from, *typewhat, *what, *gotchaA, *gotchaB; | ||
| 1091 | // try to discover the name of the function we want to send | ||
| 1092 | lua_getglobal( L, "decoda_name"); // ... f ... decoda_name | ||
| 1093 | from = lua_tostring( L, -1); | ||
| 1094 | lua_pushcfunction( L, luaG_nameof); // ... f ... decoda_name luaG_nameof | ||
| 1095 | lua_pushvalue( L, i); // ... f ... decoda_name luaG_nameof f | ||
| 1096 | lua_call( L, 1, 2); // ... f ... decoda_name "type" "name"|nil | ||
| 1097 | typewhat = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : luaL_typename( L, -2); | ||
| 1098 | // second return value can be nil if the function was not found | ||
| 1099 | // probable reason: the function was removed from the source Lua state before Lanes was required. | ||
| 1100 | if( lua_isnil( L, -1)) | ||
| 1101 | { | ||
| 1102 | gotchaA = " referenced by"; | ||
| 1103 | gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)"; | ||
| 1104 | what = upName_; | ||
| 1105 | } | ||
| 1106 | else | ||
| 1107 | { | ||
| 1108 | gotchaA = ""; | ||
| 1109 | gotchaB = ""; | ||
| 1110 | what = (lua_type( L, -1) == LUA_TSTRING) ? lua_tostring( L, -1) : luaL_typename( L, -1); | ||
| 1111 | } | ||
| 1112 | (void) luaL_error( L, "%s%s '%s' not found in %s origin transfer database.%s", typewhat, gotchaA, what, from ? from : "main", gotchaB); | ||
| 1113 | return; | ||
| 1114 | } | ||
| 1115 | STACK_END( L, 0); | ||
| 1116 | // 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 |
| 1117 | STACK_CHECK( L2); | 1232 | STACK_CHECK( L2); // L // L2 |
| 1118 | 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 |
| 1119 | switch( mode_) | 1234 | switch( mode_) |
| 1120 | { | 1235 | { |
| @@ -1125,7 +1240,7 @@ static void lookup_native_func( struct s_Universe* U, lua_State* L2, lua_State* | |||
| 1125 | case eLM_ToKeeper: | 1240 | case eLM_ToKeeper: |
| 1126 | // push a sentinel closure that holds the lookup name as upvalue | 1241 | // push a sentinel closure that holds the lookup name as upvalue |
| 1127 | lua_pushlstring( L2, fqn, len); // "f.q.n" | 1242 | lua_pushlstring( L2, fqn, len); // "f.q.n" |
| 1128 | lua_pushcclosure( L2, sentinelfunc, 1); // f | 1243 | lua_pushcclosure( L2, func_lookup_sentinel, 1); // f |
| 1129 | break; | 1244 | break; |
| 1130 | 1245 | ||
| 1131 | case eLM_LaneBody: | 1246 | case eLM_LaneBody: |
| @@ -1134,15 +1249,26 @@ static void lookup_native_func( struct s_Universe* U, lua_State* L2, lua_State* | |||
| 1134 | ASSERT_L( lua_istable( L2, -1)); | 1249 | ASSERT_L( lua_istable( L2, -1)); |
| 1135 | lua_pushlstring( L2, fqn, len); // {} "f.q.n" | 1250 | lua_pushlstring( L2, fqn, len); // {} "f.q.n" |
| 1136 | lua_rawget( L2, -2); // {} f | 1251 | lua_rawget( L2, -2); // {} f |
| 1137 | 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)) | ||
| 1138 | { | 1255 | { |
| 1139 | char const* from, * to; | 1256 | char const* from, * to; |
| 1140 | lua_getglobal( L, "decoda_name"); // ... f ... decoda_name | 1257 | lua_getglobal( L, "decoda_name"); // ... f ... decoda_name |
| 1141 | from = lua_tostring( L, -1); | 1258 | from = lua_tostring( L, -1); |
| 1259 | lua_pop( L, 1); // ... f ... | ||
| 1142 | lua_getglobal( L2, "decoda_name"); // {} f decoda_name | 1260 | lua_getglobal( L2, "decoda_name"); // {} f decoda_name |
| 1143 | to = lua_tostring( L2, -1); | 1261 | to = lua_tostring( L2, -1); |
| 1262 | lua_pop( L2, 1); // {} f | ||
| 1144 | // 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 |
| 1145 | (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 | ); | ||
| 1146 | return; | 1272 | return; |
| 1147 | } | 1273 | } |
| 1148 | lua_remove( L2, -2); // f | 1274 | lua_remove( L2, -2); // f |
| @@ -1167,6 +1293,7 @@ static void lookup_native_func( struct s_Universe* U, lua_State* L2, lua_State* | |||
| 1167 | STACK_END( L2, 1); | 1293 | STACK_END( L2, 1); |
| 1168 | } | 1294 | } |
| 1169 | 1295 | ||
| 1296 | |||
| 1170 | /* | 1297 | /* |
| 1171 | * 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. |
| 1172 | * 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 |
| @@ -1184,7 +1311,7 @@ static void inter_copy_func( struct s_Universe* U, lua_State* L2, uint_t L2_cach | |||
| 1184 | int n, needToPush; | 1311 | int n, needToPush; |
| 1185 | luaL_Buffer b; | 1312 | luaL_Buffer b; |
| 1186 | ASSERT_L( L2_cache_i != 0); // ... {cache} ... p | 1313 | ASSERT_L( L2_cache_i != 0); // ... {cache} ... p |
| 1187 | STACK_GROW(L,2); | 1314 | STACK_GROW( L, 2); |
| 1188 | STACK_CHECK( L); | 1315 | STACK_CHECK( L); |
| 1189 | 1316 | ||
| 1190 | // 'lua_dump()' needs the function at top of stack | 1317 | // 'lua_dump()' needs the function at top of stack |
| @@ -1226,7 +1353,7 @@ static void inter_copy_func( struct s_Universe* U, lua_State* L2, uint_t L2_cach | |||
| 1226 | lua_Debug ar; | 1353 | lua_Debug ar; |
| 1227 | lua_pushvalue( L, i); // ... b f | 1354 | lua_pushvalue( L, i); // ... b f |
| 1228 | // fills 'name' 'namewhat' and 'linedefined', pops function | 1355 | // fills 'name' 'namewhat' and 'linedefined', pops function |
| 1229 | lua_getinfo(L, ">nS", &ar); // ... b | 1356 | lua_getinfo( L, ">nS", &ar); // ... b |
| 1230 | name = ar.namewhat; | 1357 | name = ar.namewhat; |
| 1231 | 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 |
| 1232 | } | 1359 | } |
| @@ -1351,12 +1478,12 @@ static void push_cached_func( struct s_Universe* U, lua_State* L2, uint_t L2_cac | |||
| 1351 | // push a light userdata uniquely representing the function | 1478 | // push a light userdata uniquely representing the function |
| 1352 | lua_pushlightuserdata( L2, aspointer); // ... {cache} ... p | 1479 | lua_pushlightuserdata( L2, aspointer); // ... {cache} ... p |
| 1353 | 1480 | ||
| 1354 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); | 1481 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring( L2, -1)); |
| 1355 | 1482 | ||
| 1356 | lua_pushvalue( L2, -1); // ... {cache} ... p p | 1483 | lua_pushvalue( L2, -1); // ... {cache} ... p p |
| 1357 | lua_rawget( L2, L2_cache_i); // ... {cache} ... p function|nil|true | 1484 | lua_rawget( L2, L2_cache_i); // ... {cache} ... p function|nil|true |
| 1358 | 1485 | ||
| 1359 | if( lua_isnil(L2,-1)) // function is unknown | 1486 | if( lua_isnil( L2, -1)) // function is unknown |
| 1360 | { | 1487 | { |
| 1361 | lua_pop( L2, 1); // ... {cache} ... p | 1488 | lua_pop( L2, 1); // ... {cache} ... p |
| 1362 | 1489 | ||
| @@ -1371,15 +1498,14 @@ static void push_cached_func( struct s_Universe* U, lua_State* L2, uint_t L2_cac | |||
| 1371 | lua_remove( L2, -2); // ... {cache} ... function | 1498 | lua_remove( L2, -2); // ... {cache} ... function |
| 1372 | } | 1499 | } |
| 1373 | STACK_END( L2, 1); | 1500 | STACK_END( L2, 1); |
| 1501 | ASSERT_L( lua_isfunction( L2, -1)); | ||
| 1374 | } | 1502 | } |
| 1375 | else // function is native/LuaJIT: no need to cache | 1503 | else // function is native/LuaJIT: no need to cache |
| 1376 | { | 1504 | { |
| 1377 | 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)); | ||
| 1378 | } | 1508 | } |
| 1379 | |||
| 1380 | // | ||
| 1381 | // L2 [-1]: function | ||
| 1382 | ASSERT_L( lua_isfunction( L2, -1)); | ||
| 1383 | } | 1509 | } |
| 1384 | 1510 | ||
| 1385 | /* | 1511 | /* |
| @@ -1396,12 +1522,12 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
| 1396 | { | 1522 | { |
| 1397 | bool_t ret = TRUE; | 1523 | bool_t ret = TRUE; |
| 1398 | bool_t ignore = FALSE; | 1524 | bool_t ignore = FALSE; |
| 1399 | int val_type = lua_type(L, i); | 1525 | int val_type = lua_type( L, i); |
| 1400 | STACK_GROW( L2, 1); | 1526 | STACK_GROW( L2, 1); |
| 1401 | STACK_CHECK( L2); | 1527 | STACK_CHECK( L2); |
| 1402 | 1528 | ||
| 1403 | /* Skip the object if it has metatable with { __lanesignore = true } */ | 1529 | /* Skip the object if it has metatable with { __lanesignore = true } */ |
| 1404 | if( lua_getmetatable( L, i)) // ... mt | 1530 | if( lua_getmetatable( L, i)) // ... mt |
| 1405 | { | 1531 | { |
| 1406 | lua_getfield( L, -1, "__lanesignore"); // ... mt ignore? | 1532 | lua_getfield( L, -1, "__lanesignore"); // ... mt ignore? |
| 1407 | if( lua_isboolean( L, -1) && lua_toboolean( L, -1)) | 1533 | if( lua_isboolean( L, -1) && lua_toboolean( L, -1)) |
| @@ -1426,7 +1552,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
| 1426 | if( lua_isinteger( L, i)) | 1552 | if( lua_isinteger( L, i)) |
| 1427 | { | 1553 | { |
| 1428 | lua_Integer v = lua_tointeger( L, i); | 1554 | lua_Integer v = lua_tointeger( L, i); |
| 1429 | 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)); |
| 1430 | lua_pushinteger( L2, v); | 1556 | lua_pushinteger( L2, v); |
| 1431 | break; | 1557 | break; |
| 1432 | } | 1558 | } |
| @@ -1449,7 +1575,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
| 1449 | break; | 1575 | break; |
| 1450 | 1576 | ||
| 1451 | case LUA_TLIGHTUSERDATA: | 1577 | case LUA_TLIGHTUSERDATA: |
| 1452 | lua_pushlightuserdata( L2, lua_touserdata(L, i)); | 1578 | lua_pushlightuserdata( L2, lua_touserdata( L, i)); |
| 1453 | break; | 1579 | break; |
| 1454 | 1580 | ||
| 1455 | /* The following types are not allowed as table keys */ | 1581 | /* The following types are not allowed as table keys */ |
| @@ -1525,6 +1651,16 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
| 1525 | STACK_CHECK( L); | 1651 | STACK_CHECK( L); |
| 1526 | STACK_CHECK( L2); | 1652 | STACK_CHECK( L2); |
| 1527 | 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 | |||
| 1528 | /* 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 |
| 1529 | * reuse the old copy. This allows table upvalues shared by multiple | 1665 | * reuse the old copy. This allows table upvalues shared by multiple |
| 1530 | * 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. |
| @@ -1539,7 +1675,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
| 1539 | ASSERT_L( lua_istable( L2, -1)); // from cache | 1675 | ASSERT_L( lua_istable( L2, -1)); // from cache |
| 1540 | break; | 1676 | break; |
| 1541 | } | 1677 | } |
| 1542 | ASSERT_L( lua_istable( L2,-1)); | 1678 | ASSERT_L( lua_istable( L2, -1)); |
| 1543 | 1679 | ||
| 1544 | STACK_GROW( L, 2); | 1680 | STACK_GROW( L, 2); |
| 1545 | STACK_GROW( L2, 2); | 1681 | STACK_GROW( L2, 2); |
| @@ -1547,7 +1683,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
| 1547 | lua_pushnil( L); // start iteration | 1683 | lua_pushnil( L); // start iteration |
| 1548 | while( lua_next( L, i)) | 1684 | while( lua_next( L, i)) |
| 1549 | { | 1685 | { |
| 1550 | uint_t val_i = lua_gettop(L); | 1686 | uint_t val_i = lua_gettop( L); |
| 1551 | uint_t key_i = val_i - 1; | 1687 | uint_t key_i = val_i - 1; |
| 1552 | 1688 | ||
| 1553 | // Only basic key types are copied over; others ignored | 1689 | // Only basic key types are copied over; others ignored |
| @@ -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) |
