From c4aeac390daf21510575b6cad3163e9e6d34fd55 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Fri, 7 Jun 2024 14:26:18 +0200 Subject: Factorize uservalue extraction in luaG_getalluservalues --- deep_test/deep_test.args.json | 8 ++++++++ deep_test/deep_test.vcxproj.user | 4 ++-- src/compat.cpp | 28 ++++++++++++++++++++-------- src/compat.h | 4 ++++ src/intercopycontext.cpp | 36 +++++++++++++----------------------- 5 files changed, 47 insertions(+), 33 deletions(-) diff --git a/deep_test/deep_test.args.json b/deep_test/deep_test.args.json index fbef41c..a1654a6 100644 --- a/deep_test/deep_test.args.json +++ b/deep_test/deep_test.args.json @@ -6,6 +6,14 @@ "Id": "d9d87866-8c63-44a8-b88a-1d42097985d4", "Command": "DeepTest", "Items": [ + { + "Id": "d762af99-3873-4084-a9a1-ae42f57802a0", + "Command": "deeptest.lua" + }, + { + "Id": "a8d142a9-be5f-459d-8b80-61c7f3a263a1", + "Command": "-e \"REPEAT=1000, SIZE=1000\" -i deeptest.lua" + }, { "Id": "10e30bb2-dc23-4882-b918-b5939c14e588", "Command": "-e \"REPEAT=1000, SIZE=1000 DEEP='stack_abuser'\" -i deeptest.lua" diff --git a/deep_test/deep_test.vcxproj.user b/deep_test/deep_test.vcxproj.user index ed75184..257d4e9 100644 --- a/deep_test/deep_test.vcxproj.user +++ b/deep_test/deep_test.vcxproj.user @@ -36,9 +36,9 @@ $(SolutionDir)..\framework\lua54.exe WindowsLocalDebugger - -e "REPEAT=1000, SIZE=1000" -i deeptest.lua + deeptest.lua $(SolutionDir)Lanes\lanes\deep_test\ - -e "REPEAT=1000, SIZE=1000" -i deeptest.lua + deeptest.lua $(SolutionDir)..\MoonJIT\bin\$(Platform)\moonjit.exe diff --git a/src/compat.cpp b/src/compat.cpp index f0a3685..e1e7488 100644 --- a/src/compat.cpp +++ b/src/compat.cpp @@ -3,25 +3,37 @@ #include "macros_and_utils.h" - -// ################################################################################################# -// ###################################### Lua 5.1 / 5.2 / 5.3 ###################################### // ################################################################################################# +int luaG_getalluservalues(lua_State* const L_, int const idx_) +{ + STACK_CHECK_START_REL(L_, 0); + int const _idx{ luaG_absindex(L_, idx_) }; + int _nuv{ 0 }; + do { + // we don't know how many uservalues we are going to extract, there might be a lot... + STACK_GROW(L_, 1); + } while (lua_getiuservalue(L_, _idx, ++_nuv) != LUA_TNONE); // L_: ... [uv]* nil + // last call returned TNONE and pushed nil, that we don't need + lua_pop(L_, 1); // L_: ... [uv]* + --_nuv; + STACK_CHECK(L_, _nuv); + return _nuv; +} // ################################################################################################# // a small helper to obtain a module's table from the registry instead of relying on the presence of _G[""] -LuaType luaG_getmodule(lua_State* L_, std::string_view const& name_) +LuaType luaG_getmodule(lua_State* const L_, std::string_view const& name_) { STACK_CHECK_START_REL(L_, 0); - LuaType _type{ luaG_getfield(L_, LUA_REGISTRYINDEX, LUA_LOADED_TABLE) }; // L_: _R._LOADED|nil - if (_type != LuaType::TABLE) { // L_: _R._LOADED|nil + LuaType _type{ luaG_getfield(L_, LUA_REGISTRYINDEX, LUA_LOADED_TABLE) }; // L_: _R._LOADED|nil + if (_type != LuaType::TABLE) { // L_: _R._LOADED|nil STACK_CHECK(L_, 1); return _type; } - _type = luaG_getfield(L_, -1, name_); // L_: _R._LOADED {module}|nil - lua_remove(L_, -2); // L_: {module}|nil + _type = luaG_getfield(L_, -1, name_); // L_: _R._LOADED {module}|nil + lua_remove(L_, -2); // L_: {module}|nil STACK_CHECK(L_, 1); return _type; } diff --git a/src/compat.h b/src/compat.h index 8963ef7..d84447b 100644 --- a/src/compat.h +++ b/src/compat.h @@ -292,6 +292,10 @@ inline int luaG_dump(lua_State* L_, lua_Writer writer_, void* data_, int strip_) // ------------------------------------------------------------------------------------------------- +int luaG_getalluservalues(lua_State* L_, int idx_); + +// ------------------------------------------------------------------------------------------------- + LuaType luaG_getmodule(lua_State* L_, std::string_view const& name_); // ------------------------------------------------------------------------------------------------- diff --git a/src/intercopycontext.cpp b/src/intercopycontext.cpp index 8142b6a..b2eda83 100644 --- a/src/intercopycontext.cpp +++ b/src/intercopycontext.cpp @@ -653,13 +653,9 @@ void InterCopyContext::inter_copy_keyvaluepair() const int const _mt{ luaG_absindex(L1, -2) }; // L1: ... mt __lanesclone size_t const userdata_size{ lua_rawlen(L1, _L1_i) }; // extract all the uservalues, but don't transfer them yet - int _uvi{ 0 }; - while (lua_getiuservalue(L1, _L1_i, ++_uvi) != LUA_TNONE) {} // L1: ... mt __lanesclone [uv]+ nil - // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now - lua_pop(L1, 1); // L1: ... mt __lanesclone [uv]+ - --_uvi; + int const _nuv{ luaG_getalluservalues(L1, _L1_i) }; // L1: ... mt __lanesclone [uv]* // create the clone userdata with the required number of uservalue slots - void* const _clone{ lua_newuserdatauv(L2, userdata_size, _uvi) }; // L2: ... u + void* const _clone{ lua_newuserdatauv(L2, userdata_size, _nuv) }; // L2: ... u // copy the metatable in the target state, and give it to the clone we put there InterCopyContext _c{ U, L2, L1, L2_cache_i, SourceIndex{ _mt }, VT::NORMAL, mode, name }; if (_c.inter_copy_one()) { // L2: ... u mt|sentinel @@ -687,6 +683,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const lua_getupvalue(L2, -1, 2); // L2: ... userdata_clone_sentinel u } // assign uservalues + int _uvi{ _nuv }; while (_uvi > 0) { _c.L1_i = SourceIndex{ luaG_absindex(L1, -1) }; if (!_c.inter_copy_one()) { // L2: ... u uv @@ -732,12 +729,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const STACK_CHECK_START_REL(L2, 0); // extract all uservalues of the source. unfortunately, the only way to know their count is to iterate until we fail - int _nuv{ 0 }; - while (lua_getiuservalue(L1, L1_i, _nuv + 1) != LUA_TNONE) { // L1: ... deep ... [uv]* nil - ++_nuv; - } - // last call returned TNONE and pushed nil, that we don't need - lua_pop(L1, 1); // L1: ... deep ... [uv]* + int const _nuv{ luaG_getalluservalues(L1, L1_i) }; // L1: ... deep ... [uv]* STACK_CHECK(L1, _nuv); DeepPrelude* const _deep{ *luaG_tofulluserdata(L1, L1_i) }; @@ -747,16 +739,17 @@ void InterCopyContext::inter_copy_keyvaluepair() const { InterCopyContext _c{ U, L2, L1, L2_cache_i, {}, VT::NORMAL, mode, name }; int const _clone_i{ lua_gettop(L2) }; - // TODO: STACK_GROW(L2, _nuv), and same for L1 above and everywhere we use lua_getiuservalue - while (_nuv) { + STACK_GROW(L2, _nuv); + int _uvi{ _nuv }; + while (_uvi) { _c.L1_i = SourceIndex{ luaG_absindex(L1, -1) }; if (!_c.inter_copy_one()) { // L1: ... deep ... [uv]* L2: deep uv raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); } lua_pop(L1, 1); // L1: ... deep ... [uv]* // this pops the value from the stack - lua_setiuservalue(L2, _clone_i, _nuv); // L2: deep - --_nuv; + lua_setiuservalue(L2, _clone_i, _uvi); // L2: deep + --_uvi; } // loop done: no uv remains on L1 stack // L1: ... deep ... } @@ -818,14 +811,10 @@ void InterCopyContext::inter_copy_keyvaluepair() const size_t const userdata_size{ lua_rawlen(L1, -1) }; { // extract uservalues (don't transfer them yet) - int _uvi = 0; - while (lua_getiuservalue(L1, source_i, ++_uvi) != LUA_TNONE) {} // L1: ... u uv - // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now - lua_pop(L1, 1); // L1: ... u [uv]* - --_uvi; - STACK_CHECK(L1, _uvi + 1); + int const _nuv{ luaG_getalluservalues(L1, source_i) }; // L1: ... u [uv]* + STACK_CHECK(L1, _nuv + 1); // create the clone userdata with the required number of uservalue slots - _clone = lua_newuserdatauv(L2, userdata_size, _uvi); // L2: ... mt u + _clone = lua_newuserdatauv(L2, userdata_size, _nuv); // L2: ... mt u // add it in the cache lua_pushlightuserdata(L2, _source); // L2: ... mt u source lua_pushvalue(L2, -2); // L2: ... mt u source u @@ -835,6 +824,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const lua_setmetatable(L2, -2); // L2: ... mt u // transfer and assign uservalues InterCopyContext c{ *this }; + int _uvi{ _nuv }; while (_uvi > 0) { c.L1_i = SourceIndex{ luaG_absindex(L1, -1) }; if (!c.inter_copy_one()) { // L2: ... mt u uv -- cgit v1.2.3-55-g6feb