From 8d097de830d8daf1411cc54ba267f21ecfc3204d Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Tue, 27 Nov 2018 17:58:32 +0100 Subject: Lua 5.4 support --- src/compat.c | 33 +++++++++++++++++++++ src/compat.h | 30 ++++++++++++++++--- src/deep.c | 2 +- src/keeper.c | 13 +++++---- src/lanes.c | 11 +++---- src/tools.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++----------- src/universe.c | 2 +- 7 files changed, 149 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/compat.c b/src/compat.c index c5e29f5..9f36090 100644 --- a/src/compat.c +++ b/src/compat.c @@ -4,6 +4,7 @@ * ############################################################################################### */ #include "compat.h" +#include "macros_and_utils.h" /* ** Copied from Lua 5.2 loadlib.c @@ -42,3 +43,35 @@ void luaL_requiref (lua_State *L, const char *modname, lua_CFunction openf, int } #endif // LUA_VERSION_NUM +#if LUA_VERSION_NUM < 504 + +void* lua_newuserdatauv( lua_State* L, size_t sz, int nuvalue) +{ + ASSERT_L( nuvalue <= 1); + return lua_newuserdata( L, sz); +} + +int lua_getiuservalue( lua_State* L, int idx, int n) +{ + if( n > 1) + { + lua_pushnil( L); + return LUA_TNONE; + } + lua_getuservalue( L, idx); + return lua_type( L, -1); +} + +int lua_setiuservalue( lua_State* L, int idx, int n) +{ + if( n > 1) + { + lua_pop( L, 1); + return 0; + } + (void) lua_setuservalue( L, idx); + return 1; // I guess anything non-0 is ok +} + +#endif // LUA_VERSION_NUM + diff --git a/src/compat.h b/src/compat.h index 998edef..eaa9f85 100644 --- a/src/compat.h +++ b/src/compat.h @@ -5,7 +5,8 @@ #include "lualib.h" #include "lauxlib.h" -// code is now preferring Lua 5.3 API +// code is now preferring Lua 5.4 API + // add some Lua 5.3-style API when building for Lua 5.1 #if LUA_VERSION_NUM == 501 #define lua501_equal lua_equal @@ -18,7 +19,8 @@ #define LUA_OK 0 #define LUA_ERRGCMM 666 // doesn't exist in Lua 5.1, we don't care about the actual value void luaL_requiref (lua_State* L, const char* modname, lua_CFunction openf, int glb); // implementation copied from Lua 5.2 sources -#define lua503_dump( L, writer, data, strip) lua_dump( L, writer, data) +#define lua504_dump( L, writer, data, strip) lua_dump( L, writer, data) +#define LUA_LOADED_TABLE "_LOADED" // // doesn't exist in Lua 5.1 #endif // LUA_VERSION_NUM == 501 // wrap Lua 5.2 calls under Lua 5.1 API when it is simpler that way @@ -30,7 +32,8 @@ void luaL_requiref (lua_State* L, const char* modname, lua_CFunction openf, int #define lua_lessthan( L, a, b) lua_compare( L, a, b, LUA_OPLT) #endif // lua_lessthan #define luaG_registerlibfuncs( L, _funcs) luaL_setfuncs( L, _funcs, 0) -#define lua503_dump( L, writer, data, strip) lua_dump( L, writer, data) +#define lua504_dump( L, writer, data, strip) lua_dump( L, writer, data) +#define LUA_LOADED_TABLE "_LOADED" // // doesn't exist in Lua 5.2 #endif // LUA_VERSION_NUM == 502 // wrap Lua 5.3 calls under Lua 5.1 API when it is simpler that way @@ -42,8 +45,27 @@ void luaL_requiref (lua_State* L, const char* modname, lua_CFunction openf, int #define lua_lessthan( L, a, b) lua_compare( L, a, b, LUA_OPLT) #endif // lua_lessthan #define luaG_registerlibfuncs( L, _funcs) luaL_setfuncs( L, _funcs, 0) -#define lua503_dump lua_dump +#define lua504_dump lua_dump #define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) #endif // LUA_VERSION_NUM == 503 +#if LUA_VERSION_NUM < 504 +void *lua_newuserdatauv( lua_State* L, size_t sz, int nuvalue); +int lua_getiuservalue( lua_State* L, int idx, int n); +int lua_setiuservalue( lua_State* L, int idx, int n); +#endif // LUA_VERSION_NUM < 504 + +// wrap Lua 5.4 calls under Lua 5.1 API when it is simpler that way +#if LUA_VERSION_NUM == 504 +#ifndef lua501_equal // already defined when compatibility is active in luaconf.h +#define lua501_equal( L, a, b) lua_compare( L, a, b, LUA_OPEQ) +#endif // lua501_equal +#ifndef lua_lessthan // already defined when compatibility is active in luaconf.h +#define lua_lessthan( L, a, b) lua_compare( L, a, b, LUA_OPLT) +#endif // lua_lessthan +#define luaG_registerlibfuncs( L, _funcs) luaL_setfuncs( L, _funcs, 0) +#define lua504_dump lua_dump +#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) +#endif // LUA_VERSION_NUM == 504 + #endif // __COMPAT_H__ diff --git a/src/deep.c b/src/deep.c index fd92e0c..fadb895 100644 --- a/src/deep.c +++ b/src/deep.c @@ -283,7 +283,7 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, Lo STACK_GROW( L, 7); STACK_CHECK( L, 0); - proxy = lua_newuserdata( L, sizeof(DeepPrelude*)); // DPC proxy + proxy = lua_newuserdatauv( L, sizeof(DeepPrelude*), 0); // DPC proxy ASSERT_L( proxy); *proxy = prelude; diff --git a/src/keeper.c b/src/keeper.c index 7eda598..05e9a02 100644 --- a/src/keeper.c +++ b/src/keeper.c @@ -65,6 +65,8 @@ typedef struct lua_Integer limit; } keeper_fifo; +static int const CONTENTS_TABLE = 1; + // replaces the fifo ud by its uservalue on the stack static keeper_fifo* prepare_fifo_access( lua_State* L, int idx_) { @@ -74,7 +76,7 @@ static keeper_fifo* prepare_fifo_access( lua_State* L, int idx_) idx_ = lua_absindex( L, idx_); STACK_GROW( L, 1); // we can replace the fifo userdata in the stack without fear of it being GCed, there are other references around - lua_getuservalue( L, idx_); + lua_getiuservalue( L, idx_, CONTENTS_TABLE); lua_replace( L, idx_); } return fifo; @@ -86,12 +88,13 @@ static void fifo_new( lua_State* L) { keeper_fifo* fifo; STACK_GROW( L, 2); - fifo = (keeper_fifo*) lua_newuserdata( L, sizeof( keeper_fifo)); + // a fifo full userdata has one uservalue, the table that holds the actual fifo contents + fifo = (keeper_fifo*)lua_newuserdatauv( L, sizeof( keeper_fifo), 1); fifo->first = 1; fifo->count = 0; fifo->limit = -1; lua_newtable( L); - lua_setuservalue( L, -2); + lua_setiuservalue( L, -2, CONTENTS_TABLE); } // in: expect fifo ... on top of the stack @@ -422,7 +425,7 @@ int keepercall_set( lua_State* L) should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit); lua_remove( L, -2); // fifos fifo lua_newtable( L); // fifos fifo {} - lua_setuservalue( L, -2); // fifos fifo + lua_setiuservalue( L, -2, CONTENTS_TABLE); // fifos fifo fifo->first = 1; fifo->count = 0; } @@ -450,7 +453,7 @@ int keepercall_set( lua_State* L) should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit) && (count < fifo->limit); // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! lua_newtable( L); // fifos key [val [, ...]] fifo {} - lua_setuservalue( L, -2); // fifos key [val [, ...]] fifo + lua_setiuservalue( L, -2, CONTENTS_TABLE); // fifos key [val [, ...]] fifo fifo->first = 1; fifo->count = 0; } diff --git a/src/lanes.c b/src/lanes.c index 2ad9bd9..90da9bf 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -114,7 +114,7 @@ static void securize_debug_threadname( lua_State* L, Lane* s) { STACK_CHECK( L, 0); STACK_GROW( L, 3); - lua_getuservalue( L, 1); + lua_getiuservalue( L, 1, 1); lua_newtable( L); // Lua 5.1 can't do 's->debug_name = lua_pushstring( L, s->debug_name);' lua_pushstring( L, s->debug_name); @@ -1376,7 +1376,8 @@ LUAG_FUNC( lane_new) // 's' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread) // - ud = lua_newuserdata( L, sizeof( Lane*)); // func libs cancelstep priority globals package required gc_cb lane + // a Lane full userdata needs a single uservalue + ud = lua_newuserdatauv( L, sizeof( Lane*), 1); // func libs cancelstep priority globals package required gc_cb lane s = *ud = (Lane*) malloc( sizeof( Lane)); if( s == NULL) { @@ -1422,7 +1423,7 @@ LUAG_FUNC( lane_new) lua_rawset( L, -3); // func libs cancelstep priority globals package required gc_cb lane uv } - lua_setuservalue( L, -2); // func libs cancelstep priority globals package required gc_cb lane + lua_setiuservalue( L, -2, 1); // func libs cancelstep priority globals package required gc_cb lane // Store 's' in the lane's registry, for 'cancel_test()' (even if 'cs'==0 we still do cancel tests at pending send/receive). REGISTRY_SET( L2, CANCEL_TEST_KEY, lua_pushlightuserdata( L2, s)); // func [... args ...] @@ -1461,7 +1462,7 @@ LUAG_FUNC( thread_gc) Lane* s = lua_toLane( L, 1); // ud // if there a gc callback? - lua_getuservalue( L, 1); // ud uservalue + lua_getiuservalue( L, 1, 1); // ud uservalue push_unique_key( L, GCCB_KEY); // ud uservalue __gc lua_rawget( L, -2); // ud uservalue gc_cb|nil if( !lua_isnil( L, -1)) @@ -1724,7 +1725,7 @@ LUAG_FUNC( thread_index) // first, check that we don't already have an environment that holds the requested value { // If key is found in the uservalue, return it - lua_getuservalue( L, UD); + lua_getiuservalue( L, UD, 1); lua_pushvalue( L, KEY); lua_rawget( L, USR); if( !lua_isnil( L, -1)) diff --git a/src/tools.c b/src/tools.c index 8885dea..4a0aec6 100644 --- a/src/tools.c +++ b/src/tools.c @@ -120,7 +120,7 @@ static void* protected_lua_Alloc( void *ud, void *ptr, size_t osize, size_t nsiz static int luaG_provide_protected_allocator( lua_State* L) { Universe* U = universe_get( L); - AllocatorDefinition* def = lua_newuserdata( L, sizeof(AllocatorDefinition)); + AllocatorDefinition* def = lua_newuserdatauv( L, sizeof(AllocatorDefinition), 0); def->allocF = protected_lua_Alloc; def->allocUD = &U->protected_allocator; return 1; @@ -356,7 +356,7 @@ FuncSubType luaG_getfuncsubtype( lua_State *L, int _i) // the provided writer fails with code 666 // therefore, anytime we get 666, this means that lua_dump() attempted a dump // all other cases mean this is either a C or LuaJIT-fast function - dumpres = lua503_dump( L, dummy_writer, NULL, 0); + dumpres = lua504_dump( L, dummy_writer, NULL, 0); lua_pop( L, mustpush); if( dumpres == 666) { @@ -1223,19 +1223,27 @@ static int discover_object_name_recur( lua_State* L, int shortest_, int depth_) lua_pop( L, 1); // o "r" {c} {fqn} ... {?} k U } STACK_MID( L, 2); - // search in the object's uservalue if it is a table - lua_getuservalue( L, -1); // o "r" {c} {fqn} ... {?} k U {u} - if( lua_istable( L, -1)) + // search in the object's uservalues { - ++ depth_; - lua_pushliteral( L, "uservalue"); // o "r" {c} {fqn} ... {?} k v {u} "uservalue" - lua_rawseti( L, fqn, depth_); // o "r" {c} {fqn} ... {?} k v {u} - shortest_ = discover_object_name_recur( L, shortest_, depth_); - lua_pushnil( L); // o "r" {c} {fqn} ... {?} k v {u} nil - lua_rawseti( L, fqn, depth_); // o "r" {c} {fqn} ... {?} k v {u} - -- depth_; + int uvi = 1; + while( lua_getiuservalue( L, -1, uvi) != LUA_TNONE) // o "r" {c} {fqn} ... {?} k U {u} + { + if( lua_istable( L, -1)) // if it is a table, look inside + { + ++ depth_; + lua_pushliteral( L, "uservalue"); // o "r" {c} {fqn} ... {?} k v {u} "uservalue" + lua_rawseti( L, fqn, depth_); // o "r" {c} {fqn} ... {?} k v {u} + shortest_ = discover_object_name_recur( L, shortest_, depth_); + lua_pushnil( L); // o "r" {c} {fqn} ... {?} k v {u} nil + lua_rawseti( L, fqn, depth_); // o "r" {c} {fqn} ... {?} k v {u} + -- depth_; + } + lua_pop( L, 1); // o "r" {c} {fqn} ... {?} k U + ++ uvi; + } + // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now + lua_pop( L, 1); // o "r" {c} {fqn} ... {?} k U } - lua_pop( L, 1); // o "r" {c} {fqn} ... {?} k U STACK_MID( L, 2); break; } @@ -1436,7 +1444,7 @@ static void inter_copy_func( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_ // "value returned is the error code returned by the last call // to the writer" (and we only return 0) // not sure this could ever fail but for memory shortage reasons - if( lua503_dump( L, buf_writer, &b, 0) != 0) + if( lua504_dump( L, buf_writer, &b, 0) != 0) { luaL_error( L, "internal error: function dump failed."); } @@ -1846,7 +1854,32 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu 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 + // we need to copy over the uservalues of the userdata as well + lua_pushnil( L2); // ... nil + { + int const clone_i = lua_gettop( L2); + int uvi = 0; + while( lua_getiuservalue( L, i, uvi + 1) != LUA_TNONE) // ... mt __lanesclone uv + { + luaG_inter_move( U, L, L2, 1, mode_); // ... mt __lanesclone // ... nil [uv]+ + ++ uvi; + } + // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now + lua_pop( L, 1); // ... mt __lanesclone + // create the clone userdata with the required number of uservalue slots + clone = lua_newuserdatauv( L2, userdata_size, uvi); // ... nil [uv]+ u + lua_replace( L2, clone_i); // ... u [uv]+ + // assign uservalues + while( uvi > 0) + { + // this pops the value from the stack + lua_setiuservalue( L2, clone_i, uvi); // ... u [uv]+ + -- uvi; + } + // when we are done, all uservalues are popped from the stack + STACK_MID( L2, 1); // ... u + } + STACK_MID( L, 2); // ... mt __lanesclone // 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 @@ -1920,13 +1953,37 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu 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_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_pushnil( L2); // ... mt __lanesclone nil + { + int const clone_i = lua_gettop( L2); + int uvi = 0; + while( lua_getiuservalue( L, i, uvi + 1) != LUA_TNONE) // ... u uv + { + luaG_inter_move( U, L, L2, 1, mode_); // ... u // ... mt __lanesclone nil [uv]+ + ++ uvi; + } + // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now + lua_pop( L, 1); // ... u + // create the clone userdata with the required number of uservalue slots + clone = lua_newuserdatauv( L2, userdata_size, uvi); // ... mt __lanesclone nil [uv]+ u + lua_replace( L2, clone_i); // ... mt __lanesclone u [uv]+ + // assign uservalues + while( uvi > 0) + { + // this pops the value from the stack + lua_setiuservalue( L2, clone_i, uvi); // ... mt __lanesclone u [uv]+ + -- uvi; + } + // when we are done, all uservalues are popped from the stack + STACK_MID( L2, 3); // ... mt __lanesclone u + } + STACK_MID( L, 1); // 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 diff --git a/src/universe.c b/src/universe.c index d531bf2..e1cd38f 100644 --- a/src/universe.c +++ b/src/universe.c @@ -43,7 +43,7 @@ static DECLARE_CONST_UNIQUE_KEY( UNIVERSE_REGKEY, 0x9f877b2cf078f17f); Universe* universe_create( lua_State* L) { - Universe* U = (Universe*) lua_newuserdata( L, sizeof(Universe)); // universe + Universe* U = (Universe*) lua_newuserdatauv( L, sizeof(Universe), 0); // universe memset( U, 0, sizeof( Universe)); STACK_CHECK( L, 1); REGISTRY_SET( L, UNIVERSE_REGKEY, lua_pushvalue(L, -2)); // universe -- cgit v1.2.3-55-g6feb