diff options
| author | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2013-09-26 21:11:24 +0200 |
|---|---|---|
| committer | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2013-09-26 21:11:24 +0200 |
| commit | f823c6887e28c815234f8b4bd355887b4f554857 (patch) | |
| tree | 862b37cc93d6779c3c2577e78ed6ff5389412f90 /src | |
| parent | c97ad8630ea9dcb92b4e9db16c4dbade1de18884 (diff) | |
| download | lanes-f823c6887e28c815234f8b4bd355887b4f554857.tar.gz lanes-f823c6887e28c815234f8b4bd355887b4f554857.tar.bz2 lanes-f823c6887e28c815234f8b4bd355887b4f554857.zip | |
Reduce memory footprint, simplify module order setup in conjuction with Lanes, and send over native functions a bit faster as well
* Lanes no longer has to internally require modules inside the keeper
states because they no longer need a lookup database. the lookup name is
stored as-is and actually converted in the destination state
*
optimisation: bypass cache when sending native functions over
* removed
all the KEEPER_MODEL_LUA code, as it can no longer work anyway
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); |
