diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/keeper.c | 78 | ||||
-rw-r--r-- | src/keeper.h | 11 | ||||
-rw-r--r-- | src/lanes.c | 43 | ||||
-rw-r--r-- | src/tools.c | 446 | ||||
-rw-r--r-- | src/tools.h | 13 |
5 files changed, 258 insertions, 333 deletions
diff --git a/src/keeper.c b/src/keeper.c index 4a5c913..8d9f7ec 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
@@ -51,7 +51,6 @@ | |||
51 | #include "tools.h" | 51 | #include "tools.h" |
52 | #include "keeper.h" | 52 | #include "keeper.h" |
53 | 53 | ||
54 | #if KEEPER_MODEL == KEEPER_MODEL_C | ||
55 | //################################################################################### | 54 | //################################################################################### |
56 | // Keeper implementation | 55 | // Keeper implementation |
57 | //################################################################################### | 56 | //################################################################################### |
@@ -207,10 +206,10 @@ int keeper_push_linda_storage( lua_State* L, void* ptr) | |||
207 | { | 206 | { |
208 | keeper_fifo* fifo = prepare_fifo_access( KL, -1); // storage key fifo | 207 | keeper_fifo* fifo = prepare_fifo_access( KL, -1); // storage key fifo |
209 | lua_pushvalue( KL, -2); // storage key fifo key | 208 | lua_pushvalue( KL, -2); // storage key fifo key |
210 | luaG_inter_move( KL, L, 1); // storage key fifo // out key | 209 | luaG_inter_move( KL, L, 1, eLM_FromKeeper); // storage key fifo // out key |
211 | STACK_MID( L, 2); | 210 | STACK_MID( L, 2); |
212 | lua_newtable( L); // out key keyout | 211 | lua_newtable( L); // out key keyout |
213 | luaG_inter_move( KL, L, 1); // storage key // out key keyout fifo | 212 | luaG_inter_move( KL, L, 1, eLM_FromKeeper); // storage key // out key keyout fifo |
214 | lua_pushinteger( L, fifo->first); // out key keyout fifo first | 213 | lua_pushinteger( L, fifo->first); // out key keyout fifo first |
215 | STACK_MID( L, 5); | 214 | STACK_MID( L, 5); |
216 | lua_setfield( L, -3, "first"); // out key keyout fifo | 215 | lua_setfield( L, -3, "first"); // out key keyout fifo |
@@ -512,7 +511,6 @@ int keepercall_count( lua_State* L) | |||
512 | } | 511 | } |
513 | return 1; | 512 | return 1; |
514 | } | 513 | } |
515 | #endif // KEEPER_MODEL == KEEPER_MODEL_C | ||
516 | 514 | ||
517 | //################################################################################### | 515 | //################################################################################### |
518 | // Keeper API, accessed from linda methods | 516 | // Keeper API, accessed from linda methods |
@@ -576,17 +574,11 @@ char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepe | |||
576 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | 574 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
577 | // We need to load all base libraries in the keeper states so that the transfer databases are populated properly | 575 | // We need to load all base libraries in the keeper states so that the transfer databases are populated properly |
578 | // | 576 | // |
579 | // 'io' for debugging messages, 'package' because we need to require modules exporting idfuncs | 577 | // we don't need any libs in the keeper states |
580 | // the others because they export functions that we may store in a keeper for transfer between lanes | 578 | K = luaG_newstate( L, _on_state_create, NULL); |
581 | K = luaG_newstate( L, _on_state_create, "K"); | ||
582 | 579 | ||
583 | STACK_CHECK( K); | 580 | STACK_CHECK( K); |
584 | 581 | ||
585 | // replace default 'package' contents with stuff gotten from the master state | ||
586 | lua_getglobal( L, "package"); | ||
587 | luaG_inter_copy_package( L, K, -1); | ||
588 | lua_pop( L, 1); | ||
589 | |||
590 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "### init_keepers %d END\n" INDENT_END, i)); | 582 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "### init_keepers %d END\n" INDENT_END, i)); |
591 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | 583 | DEBUGSPEW_CODE( -- debugspew_indent_depth); |
592 | 584 | ||
@@ -596,32 +588,11 @@ char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepe | |||
596 | lua_concat( K, 2); | 588 | lua_concat( K, 2); |
597 | lua_setglobal( K, "decoda_name"); | 589 | lua_setglobal( K, "decoda_name"); |
598 | 590 | ||
599 | #if KEEPER_MODEL == KEEPER_MODEL_C | ||
600 | // create the fifos table in the keeper state | 591 | // create the fifos table in the keeper state |
601 | lua_pushlightuserdata( K, fifos_key); | 592 | lua_pushlightuserdata( K, fifos_key); |
602 | lua_newtable( K); | 593 | lua_newtable( K); |
603 | lua_rawset( K, LUA_REGISTRYINDEX); | 594 | lua_rawset( K, LUA_REGISTRYINDEX); |
604 | #endif // KEEPER_MODEL == KEEPER_MODEL_C | 595 | |
605 | |||
606 | #if KEEPER_MODEL == KEEPER_MODEL_LUA | ||
607 | // use package.loaders[2] to find keeper microcode (NOTE: this works only if nobody tampered with the loaders table...) | ||
608 | lua_getglobal( K, "package"); // package | ||
609 | lua_getfield( K, -1, "loaders"); // package package.loaders | ||
610 | lua_rawgeti( K, -1, 2); // package package.loaders package.loaders[2] | ||
611 | lua_pushliteral( K, "lanes-keeper"); // package package.loaders package.loaders[2] "lanes-keeper" | ||
612 | STACK_MID( K, 4); | ||
613 | // first pcall loads lanes-keeper.lua, second one runs the chunk | ||
614 | if( lua_pcall( K, 1 /*args*/, 1 /*results*/, 0 /*errfunc*/) || lua_pcall( K, 0 /*args*/, 0 /*results*/, 0 /*errfunc*/)) | ||
615 | { | ||
616 | // LUA_ERRRUN / LUA_ERRMEM / LUA_ERRERR | ||
617 | // | ||
618 | char const* err = lua_tostring( K, -1); | ||
619 | assert( err); | ||
620 | return err; | ||
621 | } // package package.loaders | ||
622 | STACK_MID( K, 2); | ||
623 | lua_pop( K, 2); | ||
624 | #endif // KEEPER_MODEL == KEEPER_MODEL_LUA | ||
625 | STACK_END( K, 0); | 596 | STACK_END( K, 0); |
626 | MUTEX_INIT( &GKeepers[i].lock_); | 597 | MUTEX_INIT( &GKeepers[i].lock_); |
627 | GKeepers[i].L = K; | 598 | GKeepers[i].L = K; |
@@ -633,41 +604,6 @@ char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepe | |||
633 | return NULL; // ok | 604 | return NULL; // ok |
634 | } | 605 | } |
635 | 606 | ||
636 | // cause each keeper state to populate its database of transferable functions with those from the specified module | ||
637 | // do do this we simply require the module inside the keeper state, then populate the lookup database | ||
638 | void populate_keepers( lua_State* L) | ||
639 | { | ||
640 | size_t name_len; | ||
641 | char const* name = luaL_checklstring( L, -1, &name_len); | ||
642 | int i; | ||
643 | |||
644 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "populate_keepers %s BEGIN\n" INDENT_END, name)); | ||
645 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | ||
646 | |||
647 | for( i = 0; i < GNbKeepers; ++ i) | ||
648 | { | ||
649 | lua_State* K = GKeepers[i].L; | ||
650 | int res; | ||
651 | MUTEX_LOCK( &GKeepers[i].lock_); | ||
652 | STACK_CHECK( K); | ||
653 | STACK_GROW( K, 2); | ||
654 | lua_getglobal( K, "require"); | ||
655 | lua_pushlstring( K, name, name_len); | ||
656 | res = lua_pcall( K, 1, 1, 0); | ||
657 | if( res != LUA_OK) | ||
658 | { | ||
659 | char const* err = luaL_checkstring( K, -1); | ||
660 | luaL_error( L, "error requiring '%s' in keeper state: %s", name, err); | ||
661 | } | ||
662 | // after requiring the module, register the functions it exported in our name<->function database | ||
663 | populate_func_lookup_table( K, -1, name); | ||
664 | lua_pop( K, 1); | ||
665 | STACK_END( K, 0); | ||
666 | MUTEX_UNLOCK( &GKeepers[i].lock_); | ||
667 | } | ||
668 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | ||
669 | } | ||
670 | |||
671 | struct s_Keeper* keeper_acquire( void const* ptr) | 607 | struct s_Keeper* keeper_acquire( void const* ptr) |
672 | { | 608 | { |
673 | // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers) | 609 | // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers) |
@@ -747,12 +683,12 @@ int keeper_call( lua_State *K, keeper_api_t _func, lua_State *L, void *linda, ui | |||
747 | 683 | ||
748 | lua_pushlightuserdata( K, linda); | 684 | lua_pushlightuserdata( K, linda); |
749 | 685 | ||
750 | if( (args == 0) || luaG_inter_copy( L, K, args) == 0) // L->K | 686 | if( (args == 0) || luaG_inter_copy( L, K, args, eLM_ToKeeper) == 0) // L->K |
751 | { | 687 | { |
752 | lua_call( K, 1 + args, LUA_MULTRET); | 688 | lua_call( K, 1 + args, LUA_MULTRET); |
753 | 689 | ||
754 | retvals = lua_gettop( K) - Ktos; | 690 | retvals = lua_gettop( K) - Ktos; |
755 | if( (retvals > 0) && luaG_inter_move( K, L, retvals) != 0) // K->L | 691 | if( (retvals > 0) && luaG_inter_move( K, L, retvals, eLM_FromKeeper) != 0) // K->L |
756 | { | 692 | { |
757 | retvals = -1; | 693 | retvals = -1; |
758 | } | 694 | } |
diff --git a/src/keeper.h b/src/keeper.h index 29a19a9..420eca1 100644 --- a/src/keeper.h +++ b/src/keeper.h | |||
@@ -18,21 +18,11 @@ char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepe | |||
18 | void close_keepers( void); | 18 | void close_keepers( void); |
19 | #endif // HAVE_KEEPER_ATEXIT_DESINIT | 19 | #endif // HAVE_KEEPER_ATEXIT_DESINIT |
20 | 20 | ||
21 | void populate_keepers( lua_State *L); | ||
22 | struct s_Keeper *keeper_acquire( const void *ptr); | 21 | struct s_Keeper *keeper_acquire( const void *ptr); |
23 | void keeper_release( struct s_Keeper *K); | 22 | void keeper_release( struct s_Keeper *K); |
24 | void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel); | 23 | void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel); |
25 | int keeper_push_linda_storage( lua_State* L, void* ptr); | 24 | int keeper_push_linda_storage( lua_State* L, void* ptr); |
26 | 25 | ||
27 | #define KEEPER_MODEL_LUA 1 | ||
28 | #define KEEPER_MODEL_C 2 | ||
29 | #define KEEPER_MODEL KEEPER_MODEL_C | ||
30 | |||
31 | #if KEEPER_MODEL == KEEPER_MODEL_LUA | ||
32 | typedef char const* keeper_api_t; | ||
33 | #define KEEPER_API( _op) #_op | ||
34 | #define PUSH_KEEPER_FUNC( K, _api) lua_getglobal( K, _api) | ||
35 | #elif KEEPER_MODEL == KEEPER_MODEL_C | ||
36 | typedef lua_CFunction keeper_api_t; | 26 | typedef lua_CFunction keeper_api_t; |
37 | #define KEEPER_API( _op) keepercall_ ## _op | 27 | #define KEEPER_API( _op) keepercall_ ## _op |
38 | #define PUSH_KEEPER_FUNC lua_pushcfunction | 28 | #define PUSH_KEEPER_FUNC lua_pushcfunction |
@@ -45,7 +35,6 @@ int keepercall_limit( lua_State* L); | |||
45 | int keepercall_get( lua_State* L); | 35 | int keepercall_get( lua_State* L); |
46 | int keepercall_set( lua_State* L); | 36 | int keepercall_set( lua_State* L); |
47 | int keepercall_count( lua_State* L); | 37 | int keepercall_count( lua_State* L); |
48 | #endif // KEEPER_MODEL | ||
49 | 38 | ||
50 | int keeper_call( lua_State *K, keeper_api_t _func, lua_State *L, void *linda, uint_t starting_index); | 39 | int keeper_call( lua_State *K, keeper_api_t _func, lua_State *L, void *linda, uint_t starting_index); |
51 | 40 | ||
diff --git a/src/lanes.c b/src/lanes.c index 7eef2d0..dc1eeed 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
@@ -52,7 +52,7 @@ | |||
52 | * ... | 52 | * ... |
53 | */ | 53 | */ |
54 | 54 | ||
55 | char const* VERSION = "3.6.4"; | 55 | char const* VERSION = "3.6.5"; |
56 | 56 | ||
57 | /* | 57 | /* |
58 | =============================================================================== | 58 | =============================================================================== |
@@ -1862,23 +1862,23 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | |||
1862 | } | 1862 | } |
1863 | 1863 | ||
1864 | // --- If a client wants to transfer stuff of a given module from the current state to another Lane, the module must be required | 1864 | // --- If a client wants to transfer stuff of a given module from the current state to another Lane, the module must be required |
1865 | // with lanes.require, that will call the regular 'require', then populate lookup databases in source and keeper states | 1865 | // with lanes.require, that will call the regular 'require', then populate the lookup database in the source lane |
1866 | // module = lanes.require( "modname") | 1866 | // module = lanes.require( "modname") |
1867 | // upvalue[1]: _G.require | 1867 | // upvalue[1]: _G.require |
1868 | LUAG_FUNC( require) | 1868 | LUAG_FUNC( require) |
1869 | { | 1869 | { |
1870 | char const* name = lua_tostring( L, 1); | 1870 | char const* name = lua_tostring( L, 1); |
1871 | STACK_CHECK( L); | ||
1871 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s BEGIN\n" INDENT_END, name)); | 1872 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s BEGIN\n" INDENT_END, name)); |
1872 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | 1873 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
1873 | lua_pushvalue( L, lua_upvalueindex(1)); // "name" require | 1874 | lua_pushvalue( L, lua_upvalueindex(1)); // "name" require |
1874 | lua_pushvalue( L, 1); // "name" require "name" | 1875 | lua_pushvalue( L, 1); // "name" require "name" |
1875 | lua_call( L, 1, 1); // "name" module | 1876 | lua_call( L, 1, 1); // "name" module |
1876 | populate_func_lookup_table( L, -1, name); | 1877 | populate_func_lookup_table( L, -1, name); |
1877 | lua_insert( L, -2); // module "name" | 1878 | lua_remove( L, -2); // module |
1878 | populate_keepers( L); | ||
1879 | lua_pop( L, 1); // module | ||
1880 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s END\n" INDENT_END, name)); | 1879 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s END\n" INDENT_END, name)); |
1881 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | 1880 | DEBUGSPEW_CODE( -- debugspew_indent_depth); |
1881 | STACK_END( L, 1); | ||
1882 | return 1; | 1882 | return 1; |
1883 | } | 1883 | } |
1884 | 1884 | ||
@@ -1937,7 +1937,7 @@ LUAG_FUNC( thread_new) | |||
1937 | // package | 1937 | // package |
1938 | if( package) | 1938 | if( package) |
1939 | { | 1939 | { |
1940 | luaG_inter_copy_package( L, L2, package); | 1940 | luaG_inter_copy_package( L, L2, package, eLM_LaneBody); |
1941 | } | 1941 | } |
1942 | 1942 | ||
1943 | // modules to require in the target lane *before* the function is transfered! | 1943 | // modules to require in the target lane *before* the function is transfered! |
@@ -1986,8 +1986,6 @@ LUAG_FUNC( thread_new) | |||
1986 | populate_func_lookup_table( L2, -1, name); | 1986 | populate_func_lookup_table( L2, -1, name); |
1987 | STACK_MID( L2, 1); | 1987 | STACK_MID( L2, 1); |
1988 | lua_pop( L2, 1); | 1988 | lua_pop( L2, 1); |
1989 | // don't require this module in the keeper states as well, use lanes.require() for that! | ||
1990 | //populate_keepers( L); | ||
1991 | } | 1989 | } |
1992 | STACK_END( L2, 0); | 1990 | STACK_END( L2, 0); |
1993 | } | 1991 | } |
@@ -2017,7 +2015,7 @@ LUAG_FUNC( thread_new) | |||
2017 | lua_pushglobaltable( L2); // Lua 5.2 wants us to push the globals table on the stack | 2015 | lua_pushglobaltable( L2); // Lua 5.2 wants us to push the globals table on the stack |
2018 | while( lua_next( L, glob)) | 2016 | while( lua_next( L, glob)) |
2019 | { | 2017 | { |
2020 | luaG_inter_copy( L, L2, 2); // moves the key/value pair to the L2 stack | 2018 | luaG_inter_copy( L, L2, 2, eLM_LaneBody); // moves the key/value pair to the L2 stack |
2021 | // assign it in L2's globals table | 2019 | // assign it in L2's globals table |
2022 | lua_rawset( L2, -3); | 2020 | lua_rawset( L2, -3); |
2023 | lua_pop( L, 1); | 2021 | lua_pop( L, 1); |
@@ -2040,7 +2038,7 @@ LUAG_FUNC( thread_new) | |||
2040 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: transfer lane body\n" INDENT_END)); | 2038 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: transfer lane body\n" INDENT_END)); |
2041 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | 2039 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
2042 | lua_pushvalue( L, 1); | 2040 | lua_pushvalue( L, 1); |
2043 | res = luaG_inter_move( L, L2, 1); // L->L2 | 2041 | res = luaG_inter_move( L, L2, 1, eLM_LaneBody); // L->L2 |
2044 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | 2042 | DEBUGSPEW_CODE( -- debugspew_indent_depth); |
2045 | if( res != 0) | 2043 | if( res != 0) |
2046 | { | 2044 | { |
@@ -2067,7 +2065,7 @@ LUAG_FUNC( thread_new) | |||
2067 | int res; | 2065 | int res; |
2068 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: transfer lane arguments\n" INDENT_END)); | 2066 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: transfer lane arguments\n" INDENT_END)); |
2069 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | 2067 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
2070 | res = luaG_inter_copy( L, L2, args); // L->L2 | 2068 | res = luaG_inter_copy( L, L2, args, eLM_LaneBody); // L->L2 |
2071 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | 2069 | DEBUGSPEW_CODE( -- debugspew_indent_depth); |
2072 | if( res != 0) | 2070 | if( res != 0) |
2073 | return luaL_error( L, "tried to copy unsupported types"); | 2071 | return luaL_error( L, "tried to copy unsupported types"); |
@@ -2317,7 +2315,7 @@ LUAG_FUNC( thread_join) | |||
2317 | case DONE: | 2315 | case DONE: |
2318 | { | 2316 | { |
2319 | uint_t n = lua_gettop( L2); // whole L2 stack | 2317 | uint_t n = lua_gettop( L2); // whole L2 stack |
2320 | if( (n > 0) && (luaG_inter_move( L2, L, n) != 0)) | 2318 | if( (n > 0) && (luaG_inter_move( L2, L, n, eLM_LaneBody) != 0)) |
2321 | { | 2319 | { |
2322 | return luaL_error( L, "tried to copy unsupported types"); | 2320 | return luaL_error( L, "tried to copy unsupported types"); |
2323 | } | 2321 | } |
@@ -2327,7 +2325,7 @@ LUAG_FUNC( thread_join) | |||
2327 | 2325 | ||
2328 | case ERROR_ST: | 2326 | case ERROR_ST: |
2329 | lua_pushnil( L); | 2327 | lua_pushnil( L); |
2330 | if( luaG_inter_move( L2, L, 2) != 0) // error message at [-2], stack trace at [-1] | 2328 | if( luaG_inter_move( L2, L, 2, eLM_LaneBody) != 0) // error message at [-2], stack trace at [-1] |
2331 | { | 2329 | { |
2332 | return luaL_error( L, "tried to copy unsupported types"); | 2330 | return luaL_error( L, "tried to copy unsupported types"); |
2333 | } | 2331 | } |
@@ -2620,25 +2618,6 @@ static const struct luaL_Reg lanes_functions [] = { | |||
2620 | 2618 | ||
2621 | 2619 | ||
2622 | /* | 2620 | /* |
2623 | * minimal function registration for keepers, just so that we can populate the transfer databases with them | ||
2624 | * without recursively deadlocking ourselves during one-time inits | ||
2625 | */ | ||
2626 | void register_core_libfuncs_for_keeper( lua_State* L) | ||
2627 | { | ||
2628 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register_core_libfuncs_for_keeper()\n" INDENT_END)); | ||
2629 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | ||
2630 | STACK_GROW( L, 1); | ||
2631 | STACK_CHECK( L); | ||
2632 | lua_newtable( L); | ||
2633 | luaG_registerlibfuncs( L, lanes_functions); | ||
2634 | STACK_MID( L, 1); | ||
2635 | populate_func_lookup_table( L, -1, "lanes.core"); | ||
2636 | lua_pop( L, 1); | ||
2637 | STACK_END( L, 0); | ||
2638 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | ||
2639 | } | ||
2640 | |||
2641 | /* | ||
2642 | ** One-time initializations | 2621 | ** One-time initializations |
2643 | */ | 2622 | */ |
2644 | static void init_once_LOCKED( lua_State* L, int const _on_state_create, int const nbKeepers, lua_Number _shutdown_timeout, bool_t _track_lanes, bool_t verbose_errors) | 2623 | static void init_once_LOCKED( lua_State* L, int const _on_state_create, int const nbKeepers, lua_Number _shutdown_timeout, bool_t _track_lanes, bool_t verbose_errors) |
diff --git a/src/tools.c b/src/tools.c index a3cc6b7..a957f41 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -515,8 +515,6 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* _name) | |||
515 | * Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL. | 515 | * Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL. |
516 | * | 516 | * |
517 | */ | 517 | */ |
518 | extern void register_core_libfuncs_for_keeper( lua_State* L); | ||
519 | |||
520 | lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs) | 518 | lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs) |
521 | { | 519 | { |
522 | // reuse alloc function from the originating state | 520 | // reuse alloc function from the originating state |
@@ -534,6 +532,7 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con | |||
534 | { | 532 | { |
535 | return L; | 533 | return L; |
536 | } | 534 | } |
535 | // if we are here, no keeper state is involved (because libs == NULL when we init keepers) | ||
537 | 536 | ||
538 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END)); | 537 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END)); |
539 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | 538 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
@@ -549,9 +548,8 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con | |||
549 | if( libs) | 548 | if( libs) |
550 | { | 549 | { |
551 | // special "*" case (mainly to help with LuaJIT compatibility) | 550 | // special "*" case (mainly to help with LuaJIT compatibility) |
552 | // "K" is used when opening keeper states: almost the same as "*", but for the fact we don't open lanes.core | ||
553 | // as we are called from luaopen_lanes_core() already, and that would deadlock | 551 | // as we are called from luaopen_lanes_core() already, and that would deadlock |
554 | if( (libs[0] == '*' || libs[0] == 'K') && libs[1] == 0) | 552 | if( libs[0] == '*' && libs[1] == 0) |
555 | { | 553 | { |
556 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); | 554 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); |
557 | luaL_openlibs( L); | 555 | luaL_openlibs( L); |
@@ -560,12 +558,6 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con | |||
560 | // don't forget lanes.core for regular lane states | 558 | // don't forget lanes.core for regular lane states |
561 | open1lib( L, "lanes.core", 10); | 559 | open1lib( L, "lanes.core", 10); |
562 | } | 560 | } |
563 | else | ||
564 | { | ||
565 | // In keeper states however, we only want to register the lanes.core functions to be able to transfer them through lindas | ||
566 | // (we don't care about a full lanes.core init in the keeper states as we won't call anything in there) | ||
567 | register_core_libfuncs_for_keeper( L); | ||
568 | } | ||
569 | libs = NULL; // done with libs | 561 | libs = NULL; // done with libs |
570 | } | 562 | } |
571 | else | 563 | else |
@@ -622,7 +614,7 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con | |||
622 | STACK_CHECK( _from); | 614 | STACK_CHECK( _from); |
623 | // Lua function: transfer as usual (should work as long as it only uses base libraries) | 615 | // Lua function: transfer as usual (should work as long as it only uses base libraries) |
624 | lua_pushvalue( _from, _on_state_create); | 616 | lua_pushvalue( _from, _on_state_create); |
625 | luaG_inter_move( _from, L, 1); | 617 | luaG_inter_move( _from, L, 1, eLM_LaneBody); |
626 | STACK_END( _from, 0); | 618 | STACK_END( _from, 0); |
627 | } | 619 | } |
628 | // capture error and forward it to main state | 620 | // capture error and forward it to main state |
@@ -1283,59 +1275,6 @@ static bool_t push_cached_table( lua_State *L2, uint_t L2_cache_i, lua_State *L, | |||
1283 | } | 1275 | } |
1284 | 1276 | ||
1285 | 1277 | ||
1286 | /* | ||
1287 | * Check if we've already copied the same function from 'L', and reuse the old | ||
1288 | * copy. | ||
1289 | * | ||
1290 | * Always pushes a function to 'L2'. | ||
1291 | */ | ||
1292 | static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, char const* upName_); | ||
1293 | |||
1294 | static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, char const* upName_) | ||
1295 | { | ||
1296 | void* const aspointer = (void*)lua_topointer( L, i); | ||
1297 | // TBD: Merge this and same code for tables | ||
1298 | ASSERT_L( L2_cache_i != 0); | ||
1299 | |||
1300 | STACK_GROW( L2, 2); | ||
1301 | |||
1302 | // L2_cache[id_str]= function | ||
1303 | // | ||
1304 | STACK_CHECK( L2); | ||
1305 | |||
1306 | // We don't need to use the from state ('L') in ID since the life span | ||
1307 | // is only for the duration of a copy (both states are locked). | ||
1308 | // | ||
1309 | |||
1310 | // push a light userdata uniquely representing the function | ||
1311 | lua_pushlightuserdata( L2, aspointer); // ... {cache} ... p | ||
1312 | |||
1313 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); | ||
1314 | |||
1315 | lua_pushvalue( L2, -1); // ... {cache} ... p p | ||
1316 | lua_rawget( L2, L2_cache_i); // ... {cache} ... p function|nil|true | ||
1317 | |||
1318 | if( lua_isnil(L2,-1)) // function is unknown | ||
1319 | { | ||
1320 | lua_pop( L2, 1); // ... {cache} ... p | ||
1321 | |||
1322 | // Set to 'true' for the duration of creation; need to find self-references | ||
1323 | // via upvalues | ||
1324 | // | ||
1325 | // pushes a copy of the func, stores a reference in the cache | ||
1326 | inter_copy_func( L2, L2_cache_i, L, i, upName_); // ... {cache} ... function | ||
1327 | } | ||
1328 | else // found function in the cache | ||
1329 | { | ||
1330 | lua_remove( L2, -2); // ... {cache} ... function | ||
1331 | } | ||
1332 | STACK_END( L2, 1); | ||
1333 | // | ||
1334 | // L2 [-1]: function | ||
1335 | |||
1336 | ASSERT_L( lua_isfunction( L2, -1)); | ||
1337 | } | ||
1338 | |||
1339 | /* | 1278 | /* |
1340 | * Return some name helping to identify an object | 1279 | * Return some name helping to identify an object |
1341 | */ | 1280 | */ |
@@ -1509,24 +1448,41 @@ int luaG_nameof( lua_State* L) | |||
1509 | return 2; | 1448 | return 2; |
1510 | } | 1449 | } |
1511 | 1450 | ||
1451 | // function sentinel used to transfer native functions from/to keeper states | ||
1452 | static int sentinelfunc( lua_State* L) | ||
1453 | { | ||
1454 | return luaL_error( L, "transfer sentinel function for %s, should never be called", lua_tostring( L, lua_upvalueindex( 1))); | ||
1455 | } | ||
1456 | |||
1512 | /* | 1457 | /* |
1513 | * Push a looked-up native/LuaJIT function. | 1458 | * Push a looked-up native/LuaJIT function. |
1514 | */ | 1459 | */ |
1515 | static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, char const* upName_) | 1460 | static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) |
1516 | { | 1461 | { |
1517 | char const* fqn; // L // L2 | 1462 | char const* fqn; // L // L2 |
1518 | size_t len; | 1463 | size_t len; |
1519 | _ASSERT_L( L, lua_isfunction( L, i)); // ... f ... | 1464 | _ASSERT_L( L, lua_isfunction( L, i)); // ... f ... |
1520 | STACK_CHECK( L); | 1465 | STACK_CHECK( L); |
1521 | // fetch the name from the source state's lookup table | 1466 | if( mode_ == eLM_FromKeeper) |
1522 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // ... f ... {} | 1467 | { |
1523 | _ASSERT_L( L, lua_istable( L, -1)); | 1468 | lua_CFunction f = lua_tocfunction( L, i); // should *always* be sentinelfunc! |
1524 | lua_pushvalue( L, i); // ... f ... {} f | 1469 | _ASSERT_L( L, f == sentinelfunc); |
1525 | lua_rawget( L, -2); // ... f ... {} "f.q.n" | 1470 | lua_getupvalue( L, i, 1); // ... f ... "f.q.n" |
1526 | fqn = lua_tolstring( L, -1, &len); | 1471 | fqn = lua_tolstring( L, -1, &len); |
1472 | } | ||
1473 | else | ||
1474 | { | ||
1475 | // fetch the name from the source state's lookup table | ||
1476 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // ... f ... {} | ||
1477 | _ASSERT_L( L, lua_istable( L, -1)); | ||
1478 | lua_pushvalue( L, i); // ... f ... {} f | ||
1479 | lua_rawget( L, -2); // ... f ... {} "f.q.n" | ||
1480 | fqn = lua_tolstring( L, -1, &len); | ||
1481 | } | ||
1527 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END, fqn)); | 1482 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END, fqn)); |
1528 | // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database | 1483 | // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database |
1529 | lua_pop( L, 2); // ... f ... | 1484 | lua_pop( L, (mode_ == eLM_FromKeeper) ? 1 : 2); // ... f ... |
1485 | STACK_MID( L, 0); | ||
1530 | if( !fqn) | 1486 | if( !fqn) |
1531 | { | 1487 | { |
1532 | char const *from, *typewhat, *what, *gotchaA, *gotchaB; | 1488 | char const *from, *typewhat, *what, *gotchaA, *gotchaB; |
@@ -1556,21 +1512,30 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, char cons | |||
1556 | STACK_END( L, 0); | 1512 | STACK_END( L, 0); |
1557 | // push the equivalent function in the destination's stack, retrieved from the lookup table | 1513 | // push the equivalent function in the destination's stack, retrieved from the lookup table |
1558 | STACK_CHECK( L2); | 1514 | STACK_CHECK( L2); |
1559 | lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_KEY); // {} | 1515 | if( mode_ == eLM_ToKeeper) |
1560 | _ASSERT_L( L2, lua_istable( L2, -1)); | ||
1561 | lua_pushlstring( L2, fqn, len); // {} "f.q.n" | ||
1562 | lua_rawget( L2, -2); // {} f | ||
1563 | if( !lua_isfunction( L2, -1)) | ||
1564 | { | 1516 | { |
1565 | char const* from, * to; | 1517 | // push a sentinel closure that holds the lookup name as upvalue |
1566 | lua_getglobal( L, "decoda_name"); // // ... f ... decoda_name | 1518 | lua_pushlstring( L2, fqn, len); // "f.q.n" |
1567 | from = lua_tostring( L, -1); | 1519 | lua_pushcclosure( L2, sentinelfunc, 1); // f |
1568 | lua_getglobal( L2, "decoda_name"); // {} f decoda_name | 1520 | } |
1569 | to = lua_tostring( L2, -1); | 1521 | else |
1570 | (void) luaL_error( L, "%s: function '%s' not found in %s destination transfer database.", from ? from : "main", fqn, to ? to : "main"); | 1522 | { |
1571 | return; | 1523 | lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_KEY); // {} |
1524 | _ASSERT_L( L2, lua_istable( L2, -1)); | ||
1525 | lua_pushlstring( L2, fqn, len); // {} "f.q.n" | ||
1526 | lua_rawget( L2, -2); // {} f | ||
1527 | if( !lua_isfunction( L2, -1)) | ||
1528 | { | ||
1529 | char const* from, * to; | ||
1530 | lua_getglobal( L, "decoda_name"); // ... f ... decoda_name | ||
1531 | from = lua_tostring( L, -1); | ||
1532 | lua_getglobal( L2, "decoda_name"); // {} f decoda_name | ||
1533 | to = lua_tostring( L2, -1); | ||
1534 | (void) luaL_error( L, "%s: function '%s' not found in %s destination transfer database.", from ? from : "main", fqn, to ? to : "main"); | ||
1535 | return; | ||
1536 | } | ||
1537 | lua_remove( L2, -2); // f | ||
1572 | } | 1538 | } |
1573 | lua_remove( L2, -2); // f | ||
1574 | STACK_END( L2, 1); | 1539 | STACK_END( L2, 1); |
1575 | } | 1540 | } |
1576 | 1541 | ||
@@ -1581,159 +1546,207 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, char cons | |||
1581 | enum e_vt { | 1546 | enum e_vt { |
1582 | VT_NORMAL, VT_KEY, VT_METATABLE | 1547 | VT_NORMAL, VT_KEY, VT_METATABLE |
1583 | }; | 1548 | }; |
1584 | 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, char const* upName_); | 1549 | 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, enum eLookupMode mode_, char const* upName_); |
1585 | 1550 | ||
1586 | static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, char const* upName_) | 1551 | static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) |
1587 | { | 1552 | { |
1588 | FuncSubType funcSubType; | 1553 | int n, needToPush; |
1589 | /*lua_CFunction cfunc =*/ luaG_tocfunction( L, i, &funcSubType); // NULL for LuaJIT-fast && bytecode functions | 1554 | luaL_Buffer b; |
1590 | |||
1591 | ASSERT_L( L2_cache_i != 0); // ... {cache} ... p | 1555 | ASSERT_L( L2_cache_i != 0); // ... {cache} ... p |
1592 | STACK_GROW(L,2); | 1556 | STACK_GROW(L,2); |
1593 | STACK_CHECK( L); | 1557 | STACK_CHECK( L); |
1594 | 1558 | ||
1595 | if( funcSubType == FST_Bytecode) | 1559 | // 'lua_dump()' needs the function at top of stack |
1560 | // if already on top of the stack, no need to push again | ||
1561 | needToPush = (i != (uint_t)lua_gettop( L)); | ||
1562 | if( needToPush) | ||
1596 | { | 1563 | { |
1597 | int n; | 1564 | lua_pushvalue( L, i); // ... f |
1598 | luaL_Buffer b; | 1565 | } |
1599 | // 'lua_dump()' needs the function at top of stack | ||
1600 | // if already on top of the stack, no need to push again | ||
1601 | int needToPush = (i != (uint_t)lua_gettop( L)); | ||
1602 | if( needToPush) | ||
1603 | { | ||
1604 | lua_pushvalue( L, i); // ... f | ||
1605 | } | ||
1606 | 1566 | ||
1607 | luaL_buffinit( L, &b); | 1567 | luaL_buffinit( L, &b); |
1608 | // | 1568 | // |
1609 | // "value returned is the error code returned by the last call | 1569 | // "value returned is the error code returned by the last call |
1610 | // to the writer" (and we only return 0) | 1570 | // to the writer" (and we only return 0) |
1611 | // not sure this could ever fail but for memory shortage reasons | 1571 | // not sure this could ever fail but for memory shortage reasons |
1612 | if( lua_dump( L, buf_writer, &b) != 0) | 1572 | if( lua_dump( L, buf_writer, &b) != 0) |
1613 | { | 1573 | { |
1614 | luaL_error( L, "internal error: function dump failed."); | 1574 | luaL_error( L, "internal error: function dump failed."); |
1615 | } | 1575 | } |
1616 | 1576 | ||
1617 | // pushes dumped string on 'L' | 1577 | // pushes dumped string on 'L' |
1618 | luaL_pushresult( &b); // ... f b | 1578 | luaL_pushresult( &b); // ... f b |
1619 | 1579 | ||
1620 | // if not pushed, no need to pop | 1580 | // if not pushed, no need to pop |
1621 | if( needToPush) | 1581 | if( needToPush) |
1582 | { | ||
1583 | lua_remove( L, -2); // ... b | ||
1584 | } | ||
1585 | |||
1586 | // transfer the bytecode, then the upvalues, to create a similar closure | ||
1587 | { | ||
1588 | char const* name = NULL; | ||
1589 | |||
1590 | #if LOG_FUNC_INFO | ||
1591 | // "To get information about a function you push it onto the | ||
1592 | // stack and start the what string with the character '>'." | ||
1593 | // | ||
1622 | { | 1594 | { |
1623 | lua_remove( L, -2); // ... b | 1595 | lua_Debug ar; |
1596 | lua_pushvalue( L, i); // ... b f | ||
1597 | // fills 'name' 'namewhat' and 'linedefined', pops function | ||
1598 | lua_getinfo(L, ">nS", &ar); // ... b | ||
1599 | name = ar.namewhat; | ||
1600 | fprintf( stderr, INDENT_BEGIN "FNAME: %s @ %d\n", i, s_indent, ar.short_src, ar.linedefined); // just gives NULL | ||
1624 | } | 1601 | } |
1625 | 1602 | #endif // LOG_FUNC_INFO | |
1626 | // transfer the bytecode, then the upvalues, to create a similar closure | ||
1627 | { | 1603 | { |
1628 | char const* name = NULL; | 1604 | size_t sz; |
1629 | 1605 | char const* s = lua_tolstring( L, -1, &sz); // ... b | |
1630 | #if LOG_FUNC_INFO | 1606 | ASSERT_L( s && sz); |
1631 | // "To get information about a function you push it onto the | 1607 | STACK_GROW( L2, 2); |
1632 | // stack and start the what string with the character '>'." | 1608 | // Note: Line numbers seem to be taken precisely from the |
1609 | // original function. 'name' is not used since the chunk | ||
1610 | // is precompiled (it seems...). | ||
1633 | // | 1611 | // |
1612 | // TBD: Can we get the function's original name through, as well? | ||
1613 | // | ||
1614 | if( luaL_loadbuffer( L2, s, sz, name) != 0) // ... {cache} ... p function | ||
1634 | { | 1615 | { |
1635 | lua_Debug ar; | 1616 | // chunk is precompiled so only LUA_ERRMEM can happen |
1636 | lua_pushvalue( L, i); // ... b f | 1617 | // "Otherwise, it pushes an error message" |
1637 | // fills 'name' 'namewhat' and 'linedefined', pops function | ||
1638 | lua_getinfo(L, ">nS", &ar); // ... b | ||
1639 | name = ar.namewhat; | ||
1640 | fprintf( stderr, INDENT_BEGIN "FNAME: %s @ %d\n", i, s_indent, ar.short_src, ar.linedefined); // just gives NULL | ||
1641 | } | ||
1642 | #endif // LOG_FUNC_INFO | ||
1643 | { | ||
1644 | size_t sz; | ||
1645 | char const* s = lua_tolstring( L, -1, &sz); // ... b | ||
1646 | ASSERT_L( s && sz); | ||
1647 | STACK_GROW( L2, 2); | ||
1648 | // Note: Line numbers seem to be taken precisely from the | ||
1649 | // original function. 'name' is not used since the chunk | ||
1650 | // is precompiled (it seems...). | ||
1651 | // | ||
1652 | // TBD: Can we get the function's original name through, as well? | ||
1653 | // | 1618 | // |
1654 | if( luaL_loadbuffer( L2, s, sz, name) != 0) // ... {cache} ... p function | 1619 | STACK_GROW( L, 1); |
1655 | { | 1620 | luaL_error( L, "%s", lua_tostring( L2, -1)); |
1656 | // chunk is precompiled so only LUA_ERRMEM can happen | ||
1657 | // "Otherwise, it pushes an error message" | ||
1658 | // | ||
1659 | STACK_GROW( L, 1); | ||
1660 | luaL_error( L, "%s", lua_tostring( L2, -1)); | ||
1661 | } | ||
1662 | // remove the dumped string | ||
1663 | lua_pop( L, 1); // ... | ||
1664 | // now set the cache as soon as we can. | ||
1665 | // this is necessary if one of the function's upvalues references it indirectly | ||
1666 | // we need to find it in the cache even if it isn't fully transfered yet | ||
1667 | lua_insert( L2, -2); // ... {cache} ... function p | ||
1668 | lua_pushvalue( L2, -2); // ... {cache} ... function p function | ||
1669 | // cache[p] = function | ||
1670 | lua_rawset( L2, L2_cache_i); // ... {cache} ... function | ||
1671 | } | 1621 | } |
1672 | STACK_MID( L, 0); | 1622 | // remove the dumped string |
1623 | lua_pop( L, 1); // ... | ||
1624 | // now set the cache as soon as we can. | ||
1625 | // this is necessary if one of the function's upvalues references it indirectly | ||
1626 | // we need to find it in the cache even if it isn't fully transfered yet | ||
1627 | lua_insert( L2, -2); // ... {cache} ... function p | ||
1628 | lua_pushvalue( L2, -2); // ... {cache} ... function p function | ||
1629 | // cache[p] = function | ||
1630 | lua_rawset( L2, L2_cache_i); // ... {cache} ... function | ||
1631 | } | ||
1632 | STACK_MID( L, 0); | ||
1673 | 1633 | ||
1674 | /* push over any upvalues; references to this function will come from | 1634 | /* push over any upvalues; references to this function will come from |
1675 | * cache so we don't end up in eternal loop. | 1635 | * cache so we don't end up in eternal loop. |
1676 | * Lua5.2: one of the upvalues is _ENV, which we don't want to copy! | 1636 | * Lua5.2: one of the upvalues is _ENV, which we don't want to copy! |
1677 | * instead, the function shall have LUA_RIDX_GLOBALS taken in the destination state! | 1637 | * instead, the function shall have LUA_RIDX_GLOBALS taken in the destination state! |
1678 | */ | 1638 | */ |
1679 | { | 1639 | { |
1680 | char const* upname; | 1640 | char const* upname; |
1681 | #if LUA_VERSION_NUM == 502 | 1641 | #if LUA_VERSION_NUM == 502 |
1682 | // With Lua 5.2, each Lua function gets its environment as one of its upvalues (named LUA_ENV, aka "_ENV" by default) | 1642 | // With Lua 5.2, each Lua function gets its environment as one of its upvalues (named LUA_ENV, aka "_ENV" by default) |
1683 | // Generally this is LUA_RIDX_GLOBALS, which we don't want to copy from the source to the destination state... | 1643 | // Generally this is LUA_RIDX_GLOBALS, which we don't want to copy from the source to the destination state... |
1684 | // -> if we encounter an upvalue equal to the global table in the source, bind it to the destination's global table | 1644 | // -> if we encounter an upvalue equal to the global table in the source, bind it to the destination's global table |
1685 | lua_pushglobaltable( L); // ... _G | 1645 | lua_pushglobaltable( L); // ... _G |
1686 | #endif // LUA_VERSION_NUM | 1646 | #endif // LUA_VERSION_NUM |
1687 | for( n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != NULL; ++ n) | 1647 | for( n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != NULL; ++ n) |
1688 | { // ... _G up[n] | 1648 | { // ... _G up[n] |
1689 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "UPNAME[%d]: %s\n" INDENT_END, n, upname)); | 1649 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "UPNAME[%d]: %s\n" INDENT_END, n, upname)); |
1690 | #if LUA_VERSION_NUM == 502 | 1650 | #if LUA_VERSION_NUM == 502 |
1691 | if( lua_rawequal( L, -1, -2)) // is the upvalue equal to the global table? | 1651 | if( lua_rawequal( L, -1, -2)) // is the upvalue equal to the global table? |
1692 | { | 1652 | { |
1693 | lua_pushglobaltable( L2); // ... {cache} ... function <upvalues> | 1653 | lua_pushglobaltable( L2); // ... {cache} ... function <upvalues> |
1694 | } | 1654 | } |
1695 | else | 1655 | else |
1696 | #endif // LUA_VERSION_NUM | 1656 | #endif // LUA_VERSION_NUM |
1657 | { | ||
1658 | if( !inter_copy_one_( L2, L2_cache_i, L, lua_gettop( L), VT_NORMAL, mode_, upname)) // ... {cache} ... function <upvalues> | ||
1697 | { | 1659 | { |
1698 | if( !inter_copy_one_( L2, L2_cache_i, L, lua_gettop( L), VT_NORMAL, upname)) // ... {cache} ... function <upvalues> | 1660 | luaL_error( L, "Cannot copy upvalue type '%s'", luaL_typename( L, -1)); |
1699 | { | ||
1700 | luaL_error( L, "Cannot copy upvalue type '%s'", luaL_typename( L, -1)); | ||
1701 | } | ||
1702 | } | 1661 | } |
1703 | lua_pop( L, 1); // ... _G | ||
1704 | } | 1662 | } |
1663 | lua_pop( L, 1); // ... _G | ||
1664 | } | ||
1705 | #if LUA_VERSION_NUM == 502 | 1665 | #if LUA_VERSION_NUM == 502 |
1706 | lua_pop( L, 1); // ... | 1666 | lua_pop( L, 1); // ... |
1707 | #endif // LUA_VERSION_NUM | 1667 | #endif // LUA_VERSION_NUM |
1708 | } | 1668 | } |
1709 | // L2: function + 'n' upvalues (>=0) | 1669 | // L2: function + 'n' upvalues (>=0) |
1710 | 1670 | ||
1711 | STACK_MID( L, 0); | 1671 | STACK_MID( L, 0); |
1712 | 1672 | ||
1713 | // Set upvalues (originally set to 'nil' by 'lua_load') | 1673 | // Set upvalues (originally set to 'nil' by 'lua_load') |
1674 | { | ||
1675 | int func_index = lua_gettop( L2) - n; | ||
1676 | for( ; n > 0; -- n) | ||
1714 | { | 1677 | { |
1715 | int func_index = lua_gettop( L2) - n; | 1678 | char const* rc = lua_setupvalue( L2, func_index, n); // ... {cache} ... function |
1716 | for( ; n > 0; -- n) | 1679 | // |
1717 | { | 1680 | // "assigns the value at the top of the stack to the upvalue and returns its name. |
1718 | char const* rc = lua_setupvalue( L2, func_index, n); // ... {cache} ... function | 1681 | // It also pops the value from the stack." |
1719 | // | ||
1720 | // "assigns the value at the top of the stack to the upvalue and returns its name. | ||
1721 | // It also pops the value from the stack." | ||
1722 | 1682 | ||
1723 | ASSERT_L( rc); // not having enough slots? | 1683 | ASSERT_L( rc); // not having enough slots? |
1724 | } | ||
1725 | // once all upvalues have been set we are left | ||
1726 | // with the function at the top of the stack // ... {cache} ... function | ||
1727 | } | 1684 | } |
1685 | // once all upvalues have been set we are left | ||
1686 | // with the function at the top of the stack // ... {cache} ... function | ||
1728 | } | 1687 | } |
1729 | } | 1688 | } |
1730 | else // C function OR LuaJIT fast function!!! | 1689 | STACK_END( L, 0); |
1690 | } | ||
1691 | |||
1692 | /* | ||
1693 | * Check if we've already copied the same function from 'L', and reuse the old | ||
1694 | * copy. | ||
1695 | * | ||
1696 | * Always pushes a function to 'L2'. | ||
1697 | */ | ||
1698 | static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) | ||
1699 | { | ||
1700 | FuncSubType funcSubType; | ||
1701 | /*lua_CFunction cfunc =*/ luaG_tocfunction( L, i, &funcSubType); // NULL for LuaJIT-fast && bytecode functions | ||
1702 | if( funcSubType == FST_Bytecode) | ||
1703 | { | ||
1704 | void* const aspointer = (void*)lua_topointer( L, i); | ||
1705 | // TBD: Merge this and same code for tables | ||
1706 | ASSERT_L( L2_cache_i != 0); | ||
1707 | |||
1708 | STACK_GROW( L2, 2); | ||
1709 | |||
1710 | // L2_cache[id_str]= function | ||
1711 | // | ||
1712 | STACK_CHECK( L2); | ||
1713 | |||
1714 | // We don't need to use the from state ('L') in ID since the life span | ||
1715 | // is only for the duration of a copy (both states are locked). | ||
1716 | // | ||
1717 | |||
1718 | // push a light userdata uniquely representing the function | ||
1719 | lua_pushlightuserdata( L2, aspointer); // ... {cache} ... p | ||
1720 | |||
1721 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); | ||
1722 | |||
1723 | lua_pushvalue( L2, -1); // ... {cache} ... p p | ||
1724 | lua_rawget( L2, L2_cache_i); // ... {cache} ... p function|nil|true | ||
1725 | |||
1726 | if( lua_isnil(L2,-1)) // function is unknown | ||
1727 | { | ||
1728 | lua_pop( L2, 1); // ... {cache} ... p | ||
1729 | |||
1730 | // Set to 'true' for the duration of creation; need to find self-references | ||
1731 | // via upvalues | ||
1732 | // | ||
1733 | // pushes a copy of the func, stores a reference in the cache | ||
1734 | inter_copy_func( L2, L2_cache_i, L, i, mode_, upName_); // ... {cache} ... function | ||
1735 | } | ||
1736 | else // found function in the cache | ||
1737 | { | ||
1738 | lua_remove( L2, -2); // ... {cache} ... function | ||
1739 | } | ||
1740 | STACK_END( L2, 1); | ||
1741 | } | ||
1742 | else // function is native/LuaJIT: no need to cache | ||
1731 | { | 1743 | { |
1732 | lua_pop( L2, 1); // ... {cache} ... | 1744 | lookup_native_func( L2, L, i, mode_, upName_); // ... {cache} ... function |
1733 | // No need to transfer upvalues for C/JIT functions since they weren't actually copied, only looked up | ||
1734 | lookup_native_func( L2, L, i, upName_); // ... {cache} ... function | ||
1735 | } | 1745 | } |
1736 | STACK_END( L, 0); | 1746 | |
1747 | // | ||
1748 | // L2 [-1]: function | ||
1749 | ASSERT_L( lua_isfunction( L2, -1)); | ||
1737 | } | 1750 | } |
1738 | 1751 | ||
1739 | /* | 1752 | /* |
@@ -1746,7 +1759,7 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin | |||
1746 | * | 1759 | * |
1747 | * Returns TRUE if value was pushed, FALSE if its type is non-supported. | 1760 | * Returns TRUE if value was pushed, FALSE if its type is non-supported. |
1748 | */ | 1761 | */ |
1749 | static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt, char const* upName_) | 1762 | static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt, enum eLookupMode mode_, char const* upName_) |
1750 | { | 1763 | { |
1751 | bool_t ret = TRUE; | 1764 | bool_t ret = TRUE; |
1752 | 1765 | ||
@@ -1764,6 +1777,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1764 | 1777 | ||
1765 | case LUA_TNUMBER: | 1778 | case LUA_TNUMBER: |
1766 | /* LNUM patch support (keeping integer accuracy) */ | 1779 | /* LNUM patch support (keeping integer accuracy) */ |
1780 | // TODO: support for integer in Lua 5.3 | ||
1767 | #ifdef LUA_LNUM | 1781 | #ifdef LUA_LNUM |
1768 | if( lua_isinteger(L,i)) | 1782 | if( lua_isinteger(L,i)) |
1769 | { | 1783 | { |
@@ -1831,7 +1845,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1831 | { | 1845 | { |
1832 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "FUNCTION\n" INDENT_END)); | 1846 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "FUNCTION\n" INDENT_END)); |
1833 | STACK_CHECK( L2); | 1847 | STACK_CHECK( L2); |
1834 | push_cached_func( L2, L2_cache_i, L, i, upName_); | 1848 | push_cached_func( L2, L2_cache_i, L, i, mode_, upName_); |
1835 | STACK_END( L2, 1); | 1849 | STACK_END( L2, 1); |
1836 | } | 1850 | } |
1837 | break; | 1851 | break; |
@@ -1873,7 +1887,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1873 | 1887 | ||
1874 | /* Only basic key types are copied over; others ignored | 1888 | /* Only basic key types are copied over; others ignored |
1875 | */ | 1889 | */ |
1876 | if( inter_copy_one_( L2, 0 /*key*/, L, key_i, VT_KEY, upName_)) | 1890 | if( inter_copy_one_( L2, 0 /*key*/, L, key_i, VT_KEY, mode_, upName_)) |
1877 | { | 1891 | { |
1878 | char* valPath = (char*) upName_; | 1892 | char* valPath = (char*) upName_; |
1879 | if( GVerboseErrors) | 1893 | if( GVerboseErrors) |
@@ -1894,7 +1908,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1894 | * Contents of metatables are copied with cache checking; | 1908 | * Contents of metatables are copied with cache checking; |
1895 | * important to detect loops. | 1909 | * important to detect loops. |
1896 | */ | 1910 | */ |
1897 | if( inter_copy_one_( L2, L2_cache_i, L, val_i, VT_NORMAL, valPath)) | 1911 | if( inter_copy_one_( L2, L2_cache_i, L, val_i, VT_NORMAL, mode_, valPath)) |
1898 | { | 1912 | { |
1899 | ASSERT_L( lua_istable(L2,-3)); | 1913 | ASSERT_L( lua_istable(L2,-3)); |
1900 | lua_rawset( L2, -3); // add to table (pops key & val) | 1914 | lua_rawset( L2, -3); // add to table (pops key & val) |
@@ -1936,7 +1950,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1936 | lua_pop( L2, 1); | 1950 | lua_pop( L2, 1); |
1937 | STACK_MID( L2, 2); | 1951 | STACK_MID( L2, 2); |
1938 | ASSERT_L( lua_istable(L,-1)); | 1952 | ASSERT_L( lua_istable(L,-1)); |
1939 | if( inter_copy_one_( L2, L2_cache_i /*for function cacheing*/, L, lua_gettop(L) /*[-1]*/, VT_METATABLE, upName_)) | 1953 | if( inter_copy_one_( L2, L2_cache_i /*for function cacheing*/, L, lua_gettop(L) /*[-1]*/, VT_METATABLE, mode_, upName_)) |
1940 | { | 1954 | { |
1941 | // | 1955 | // |
1942 | // L2 ([-3]: copied table) | 1956 | // L2 ([-3]: copied table) |
@@ -1981,8 +1995,8 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1981 | } | 1995 | } |
1982 | STACK_END( L2, 1); | 1996 | STACK_END( L2, 1); |
1983 | STACK_END( L, 0); | 1997 | STACK_END( L, 0); |
1984 | } | 1998 | } |
1985 | break; | 1999 | break; |
1986 | 2000 | ||
1987 | /* The following types cannot be copied */ | 2001 | /* The following types cannot be copied */ |
1988 | 2002 | ||
@@ -2004,7 +2018,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
2004 | * | 2018 | * |
2005 | * Note: Parameters are in this order ('L' = from first) to be same as 'lua_xmove'. | 2019 | * Note: Parameters are in this order ('L' = from first) to be same as 'lua_xmove'. |
2006 | */ | 2020 | */ |
2007 | int luaG_inter_copy( lua_State* L, lua_State* L2, uint_t n) | 2021 | int luaG_inter_copy( lua_State* L, lua_State* L2, uint_t n, enum eLookupMode mode_) |
2008 | { | 2022 | { |
2009 | uint_t top_L = lua_gettop( L); | 2023 | uint_t top_L = lua_gettop( L); |
2010 | uint_t top_L2 = lua_gettop( L2); | 2024 | uint_t top_L2 = lua_gettop( L2); |
@@ -2034,7 +2048,7 @@ int luaG_inter_copy( lua_State* L, lua_State* L2, uint_t n) | |||
2034 | { | 2048 | { |
2035 | sprintf( tmpBuf, "arg_%d", j); | 2049 | sprintf( tmpBuf, "arg_%d", j); |
2036 | } | 2050 | } |
2037 | copyok = inter_copy_one_( L2, top_L2 + 1, L, i, VT_NORMAL, pBuf); | 2051 | copyok = inter_copy_one_( L2, top_L2 + 1, L, i, VT_NORMAL, mode_, pBuf); |
2038 | if( !copyok) | 2052 | if( !copyok) |
2039 | { | 2053 | { |
2040 | break; | 2054 | break; |
@@ -2062,14 +2076,14 @@ int luaG_inter_copy( lua_State* L, lua_State* L2, uint_t n) | |||
2062 | } | 2076 | } |
2063 | 2077 | ||
2064 | 2078 | ||
2065 | int luaG_inter_move( lua_State* L, lua_State* L2, uint_t n) | 2079 | int luaG_inter_move( lua_State* L, lua_State* L2, uint_t n, enum eLookupMode mode_) |
2066 | { | 2080 | { |
2067 | int ret = luaG_inter_copy( L, L2, n); | 2081 | int ret = luaG_inter_copy( L, L2, n, mode_); |
2068 | lua_pop( L, (int) n); | 2082 | lua_pop( L, (int) n); |
2069 | return ret; | 2083 | return ret; |
2070 | } | 2084 | } |
2071 | 2085 | ||
2072 | void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx) | 2086 | void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx, enum eLookupMode mode_) |
2073 | { | 2087 | { |
2074 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_inter_copy_package()\n" INDENT_END)); | 2088 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_inter_copy_package()\n" INDENT_END)); |
2075 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | 2089 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
@@ -2100,7 +2114,7 @@ void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx) | |||
2100 | else | 2114 | else |
2101 | { | 2115 | { |
2102 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | 2116 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
2103 | luaG_inter_move( L, L2, 1); // moves the entry to L2 | 2117 | luaG_inter_move( L, L2, 1, mode_); // moves the entry to L2 |
2104 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | 2118 | DEBUGSPEW_CODE( -- debugspew_indent_depth); |
2105 | lua_setfield( L2, -2, entries[i]); // set package[entries[i]] | 2119 | lua_setfield( L2, -2, entries[i]); // set package[entries[i]] |
2106 | } | 2120 | } |
diff --git a/src/tools.h b/src/tools.h index 93ed92c..bf48f1f 100644 --- a/src/tools.h +++ b/src/tools.h | |||
@@ -90,10 +90,17 @@ typedef struct { | |||
90 | } DEEP_PRELUDE; | 90 | } DEEP_PRELUDE; |
91 | 91 | ||
92 | void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *deep_userdata); | 92 | void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *deep_userdata); |
93 | void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx); | 93 | void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx, enum eLookupMode mode_); |
94 | 94 | ||
95 | int luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n); | 95 | enum eLookupMode |
96 | int luaG_inter_move( lua_State *L, lua_State *L2, uint_t n); | 96 | { |
97 | eLM_LaneBody, // send the lane body directly from the source to the destination lane | ||
98 | eLM_ToKeeper, // send a function from a lane to a keeper state | ||
99 | eLM_FromKeeper, // send a function from a keeper state to a lane | ||
100 | }; | ||
101 | |||
102 | int luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n, enum eLookupMode mode_); | ||
103 | int luaG_inter_move( lua_State *L, lua_State *L2, uint_t n, enum eLookupMode mode_); | ||
97 | 104 | ||
98 | int luaG_nameof( lua_State* L); | 105 | int luaG_nameof( lua_State* L); |
99 | int luaG_new_require( lua_State* L); | 106 | int luaG_new_require( lua_State* L); |