From a142eb1e1ee81919d10b55bb7fa2e33636098d85 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Wed, 7 Nov 2018 19:16:36 +0100 Subject: __lanesclone mechanism should actually work now --- src/lanes.c | 1 + src/tools.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 74 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/lanes.c b/src/lanes.c index d4b4c73..c3e64fb 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -2289,6 +2289,7 @@ LUAG_FUNC( lane_new) // require the module in the target state, and populate the lookup table there too size_t len; char const* name = lua_tolstring( L, -1, &len); + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: require '%s'\n" INDENT_END, name)); // require the module in the target lane lua_getglobal( L2, "require"); // require()? diff --git a/src/tools.c b/src/tools.c index 2f9de7b..8e886b5 100644 --- a/src/tools.c +++ b/src/tools.c @@ -825,6 +825,12 @@ static int table_lookup_sentinel( lua_State* L) return luaL_error( L, "table lookup sentinel for %s, should never be called", lua_tostring( L, lua_upvalueindex( 1))); } +// function sentinel used to transfer cloned full userdata from/to keeper states +static int userdata_clone_sentinel( lua_State* L) +{ + return luaL_error( L, "userdata clone sentinel for %s, should never be called", lua_tostring( L, lua_upvalueindex( 1))); +} + /* * retrieve the name of a function/table in the lookup database */ @@ -838,7 +844,7 @@ static char const* find_lookup_name( lua_State* L, uint_t i, LookupMode mode_, c if( mode_ == eLM_FromKeeper) { lua_CFunction f = lua_tocfunction( L, i); // should *always* be func_lookup_sentinel or table_lookup_sentinel! - if( f == func_lookup_sentinel || f == table_lookup_sentinel) + if( f == func_lookup_sentinel || f == table_lookup_sentinel || f == userdata_clone_sentinel) { lua_getupvalue( L, i, 1); // ... v ... "f.q.n" } @@ -1594,6 +1600,7 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu bool_t ignore = FALSE; int val_type = lua_type( L, i); STACK_GROW( L2, 1); + STACK_CHECK( L); // L // L2 STACK_CHECK( L2); // L // L2 /* Skip the object if it has metatable with { __lanesignore = true } */ @@ -1662,30 +1669,53 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu { break; } + STACK_MID( L, 0); if( lua_getmetatable( L, i)) // ... mt? { - lua_getfield( L, -1, "__lanesclone"); // ... mt clone? - if( !lua_isnil( L, -1)) + lua_getfield( L, -1, "__lanesclone"); // ... mt __lanesclone? + if( lua_isnil( L, -1)) + { + lua_pop( L, 2); // ... + } + else { + FuncSubType fst; + lua_CFunction cloneFunc = luaG_tocfunction( L, -1, &fst); + size_t userdata_size = 0; void* const source = lua_touserdata( L, i); + void* clone = NULL; + lua_pushvalue( L, -1); // ... mt __lanesclone __lanesclone + // call the cloning function with 0 arguments, should return the number of bytes to allocate for the clone + lua_call( L, 0, 1); // ... mt __lanesclone size + STACK_MID( L, 3); + userdata_size = (size_t) lua_tointeger( L, -1); // ... mt __lanesclone size + lua_pop( L, 1); // ... mt __lanesclone + clone = lua_newuserdata( L2, userdata_size); // ... u + // call cloning function in source state to perform the actual memory cloning + lua_pushlightuserdata( L, clone); // ... mt __lanesclone clone + lua_pushlightuserdata( L, source); // ... mt __lanesclone source + lua_call( L, 2, 0); // ... mt + STACK_MID( L, 1); // copy the metatable in the target state - if( push_cached_metatable( U, L2, L2_cache_i, L, i, mode_, upName_)) // ... mt? + if( inter_copy_one_( U, L2, L2_cache_i, L, lua_absindex( L, -1), VT_NORMAL, mode_, upName_)) // ... u mt? { - // retrieve cloning function - lua_getfield( L2, -1, "__lanesclone"); // ... mt clone - lua_pushlightuserdata( L2, source); // ... mt clone p - // cloning function should create a new full userdata without a metatable - if( lua_pcall( L2, 1, 1, 0) == LUA_OK) // ... mt u + lua_pop( L, 1); // ... + STACK_MID( L, 0); + // when writing to a keeper state, we have here a sentinel function with the metatable's fqn as upvalue + if( eLM_ToKeeper == mode_) // ... u sentinel { - lua_insert( L2, -2); // ... u mt - lua_setmetatable( L2, -2); // ... u + ASSERT_L( lua_tocfunction( L2, -1) == table_lookup_sentinel); + // we want to create a new closure with a 'clone sentinel' function, where the upvalues are the userdata and the metatable fqn + lua_getupvalue( L2, -1, 1); // ... u sentinel fqn + lua_remove( L2, -2); // ... u fqn + lua_insert( L2, -2); // ... fqn u + lua_pushcclosure( L2, userdata_clone_sentinel, 2); // ... userdata_clone_sentinel } - else // ... mt err + else // from keeper or direct, we have the userdata and the metatable { - // propagate any error to the source state - char const* errmsg = lua_tostring( L2, -1); - (void) luaL_error( L, "can't copy non-deep full userdata across lanes: %s", errmsg); + ASSERT_L( lua_istable( L2, -1)); + lua_setmetatable( L2, -2); // ... u } } else @@ -1693,7 +1723,6 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu (void) luaL_error( L, "Error copying a metatable"); } } - lua_pop( L, 2); // ... break; } @@ -1724,6 +1753,33 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu ret = FALSE; break; } + + if( lua_tocfunction( L, i) == userdata_clone_sentinel) // we are actually copying a clonable full userdata + { + // clone the full userdata again + size_t userdata_size = 0; + void* source; + void* clone; + // this function has 2 upvalues: the fqn of its metatable, and the userdata itself + lua_getupvalue( L, i, 2); // ... u + source = lua_touserdata( L, -1); + lookup_table( L2, L, i, mode_, upName_); // ... u // ... mt + // __lanesclone should always exist because we woudln't be restoring data from a userdata_clone_sentinel closure to begin with + lua_getfield( L2, -1, "__lanesclone"); // // ... mt __lanesclone + lua_pushvalue( L2, -1); // ... mt __lanesclone __lanesclone + // call the cloning function with 0 arguments, should return the number of bytes to allocate for the clone + lua_call( L2, 0, 1); // ... mt __lanesclone size + userdata_size = (size_t) lua_tointeger( L2, -1); // ... mt __lanesclone size + lua_pop( L2, 1); // ... mt __lanesclone + clone = lua_newuserdata( L2, userdata_size); // ... mt __lanesclone u + lua_insert( L2, -3); // ... u mt __lanesclone + lua_pushlightuserdata( L2, clone); // ... u mt __lanesclone clone + lua_pushlightuserdata( L2, source); // ... u mt __lanesclone clone source + lua_call( L2, 2, 0); // ... u mt + lua_setmetatable( L2, -2); // ... u + lua_pop( L, 1); // ... + } + else { DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "FUNCTION %s\n" INDENT_END, upName_)); DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); @@ -1802,6 +1858,7 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu } STACK_END( L2, ret ? 1 : 0); + STACK_END( L, 0); return ret; } -- cgit v1.2.3-55-g6feb