diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2025-07-22 15:36:56 +0200 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2025-07-22 15:36:56 +0200 |
commit | c67c7bb2cde0d418f72c8ac1ef57f15669b8a2bf (patch) | |
tree | 74dfb12958087ddb04a6e856a6c04d6f17bab590 /src | |
parent | 9eb852e50c62f5e67266e0055e5899ef61e611d3 (diff) | |
download | lanes-c67c7bb2cde0d418f72c8ac1ef57f15669b8a2bf.tar.gz lanes-c67c7bb2cde0d418f72c8ac1ef57f15669b8a2bf.tar.bz2 lanes-c67c7bb2cde0d418f72c8ac1ef57f15669b8a2bf.zip |
New helper to push function bytecode (to facilitate Lua 5.5 support)
Diffstat (limited to 'src')
-rw-r--r-- | src/intercopycontext.cpp | 38 | ||||
-rw-r--r-- | src/tools.cpp | 51 | ||||
-rw-r--r-- | src/tools.hpp | 2 |
3 files changed, 53 insertions, 38 deletions
diff --git a/src/intercopycontext.cpp b/src/intercopycontext.cpp index 7be1326..653eeb6 100644 --- a/src/intercopycontext.cpp +++ b/src/intercopycontext.cpp | |||
@@ -36,23 +36,6 @@ THE SOFTWARE. | |||
36 | 36 | ||
37 | // ################################################################################################# | 37 | // ################################################################################################# |
38 | 38 | ||
39 | // Lua 5.4.3 style of dumping (see lstrlib.c) | ||
40 | // we have to do it that way because we can't unbalance the stack between buffer operations | ||
41 | // namely, this means we can't push a function on top of the stack *after* we initialize the buffer! | ||
42 | // luckily, this also works with earlier Lua versions | ||
43 | [[nodiscard]] | ||
44 | static int buf_writer(lua_State* L_, void const* b_, size_t size_, void* ud_) | ||
45 | { | ||
46 | luaL_Buffer* const _B{ static_cast<luaL_Buffer*>(ud_) }; | ||
47 | if (!_B->L) { | ||
48 | luaL_buffinit(L_, _B); | ||
49 | } | ||
50 | luaL_addlstring(_B, static_cast<char const*>(b_), size_); | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | // ################################################################################################# | ||
55 | |||
56 | // function sentinel used to transfer native functions from/to keeper states | 39 | // function sentinel used to transfer native functions from/to keeper states |
57 | [[nodiscard]] | 40 | [[nodiscard]] |
58 | static int func_lookup_sentinel(lua_State* const L_) | 41 | static int func_lookup_sentinel(lua_State* const L_) |
@@ -211,19 +194,18 @@ void InterCopyContext::copyFunction() const | |||
211 | // to the writer" (and we only return 0) | 194 | // to the writer" (and we only return 0) |
212 | // not sure this could ever fail but for memory shortage reasons | 195 | // not sure this could ever fail but for memory shortage reasons |
213 | // last argument is Lua 5.4-specific (no stripping) | 196 | // last argument is Lua 5.4-specific (no stripping) |
214 | luaL_Buffer B{}; | 197 | if (tools::PushFunctionBytecode(L1, U->stripFunctions) != 0) { // L1: ... f "<bytecode>" |
215 | if (luaW_dump(L1, buf_writer, &B, U->stripFunctions) != 0) { | ||
216 | raise_luaL_error(getErrL(), "internal error: function dump failed."); | 198 | raise_luaL_error(getErrL(), "internal error: function dump failed."); |
217 | } | 199 | } |
218 | 200 | ||
219 | // pushes dumped string on 'L1' | 201 | // if pushed, we need to pop |
220 | luaL_pushresult(&B); // L1: ... f b | ||
221 | |||
222 | // if not pushed, no need to pop | ||
223 | if (_needToPush) { | 202 | if (_needToPush) { |
224 | lua_remove(L1, -2); // L1: ... b | 203 | lua_remove(L1, -2); // L1: ... "<bytecode>" |
225 | } | 204 | } |
226 | 205 | ||
206 | // When we are done, the stack should be the original one, with the bytecode string added on top | ||
207 | STACK_CHECK(L1, 1); | ||
208 | |||
227 | // transfer the bytecode, then the upvalues, to create a similar closure | 209 | // transfer the bytecode, then the upvalues, to create a similar closure |
228 | { | 210 | { |
229 | char const* _fname{}; | 211 | char const* _fname{}; |
@@ -231,16 +213,16 @@ void InterCopyContext::copyFunction() const | |||
231 | if constexpr (LOG_FUNC_INFO) | 213 | if constexpr (LOG_FUNC_INFO) |
232 | { | 214 | { |
233 | lua_Debug _ar; | 215 | lua_Debug _ar; |
234 | lua_pushvalue(L1, L1_i); // L1: ... b f | 216 | lua_pushvalue(L1, L1_i); // L1: ... "<bytecode>" f |
235 | // "To get information about a function you push it onto the stack and start the what string with the character '>'." | 217 | // "To get information about a function you push it onto the stack and start the what string with the character '>'." |
236 | // fills 'fname' 'namewhat' and 'linedefined', pops function | 218 | // fills 'fname' 'namewhat' and 'linedefined', pops function |
237 | lua_getinfo(L1, ">nS", &_ar); // L1: ... b | 219 | lua_getinfo(L1, ">nS", &_ar); // L1: ... "<bytecode>" |
238 | _fname = _ar.namewhat; | 220 | _fname = _ar.namewhat; |
239 | DEBUGSPEW_CODE(DebugSpew(U) << "FNAME: " << _ar.short_src << " @ " << _ar.linedefined << std::endl); | 221 | DEBUGSPEW_CODE(DebugSpew(U) << "FNAME: " << _ar.short_src << " @ " << _ar.linedefined << std::endl); |
240 | } | 222 | } |
241 | 223 | ||
242 | { | 224 | { |
243 | std::string_view const _bytecode{ luaW_tostring(L1, kIdxTop) }; // L1: ... b | 225 | std::string_view const _bytecode{ luaW_tostring(L1, kIdxTop) }; // L1: ... "<bytecode>" |
244 | LUA_ASSERT(L1, !_bytecode.empty()); | 226 | LUA_ASSERT(L1, !_bytecode.empty()); |
245 | STACK_GROW(L2, 2); | 227 | STACK_GROW(L2, 2); |
246 | // Note: Line numbers seem to be taken precisely from the | 228 | // Note: Line numbers seem to be taken precisely from the |
@@ -257,7 +239,7 @@ void InterCopyContext::copyFunction() const | |||
257 | raise_luaL_error(getErrL(), "%s: %s", _fname, lua_tostring(L2, -1)); | 239 | raise_luaL_error(getErrL(), "%s: %s", _fname, lua_tostring(L2, -1)); |
258 | } | 240 | } |
259 | // remove the dumped string | 241 | // remove the dumped string |
260 | lua_pop(L1, 1); // ... | 242 | lua_pop(L1, 1); // L1: ... |
261 | // now set the cache as soon as we can. | 243 | // now set the cache as soon as we can. |
262 | // this is necessary if one of the function's upvalues references it indirectly | 244 | // this is necessary if one of the function's upvalues references it indirectly |
263 | // we need to find it in the cache even if it isn't fully transfered yet | 245 | // we need to find it in the cache even if it isn't fully transfered yet |
diff --git a/src/tools.cpp b/src/tools.cpp index 25949e4..aafb9e8 100644 --- a/src/tools.cpp +++ b/src/tools.cpp | |||
@@ -45,13 +45,33 @@ static constexpr RegistryUniqueKey kLookupCacheRegKey{ 0x9BF75F84E54B691Bull }; | |||
45 | 45 | ||
46 | // ################################################################################################# | 46 | // ################################################################################################# |
47 | 47 | ||
48 | static constexpr int kWriterReturnCode{ 666 }; | 48 | namespace { |
49 | [[nodiscard]] | 49 | namespace local { |
50 | static int dummy_writer([[maybe_unused]] lua_State* const L_, [[maybe_unused]] void const* p_, [[maybe_unused]] size_t sz_, [[maybe_unused]] void* ud_) | 50 | static int buf_writer(lua_State* L_, void const* b_, size_t size_, void* ud_) |
51 | { | 51 | { |
52 | // always fail with this code | 52 | auto* const _B{ static_cast<luaL_Buffer*>(ud_) }; |
53 | return kWriterReturnCode; | 53 | if (!_B->L) { |
54 | } | 54 | luaL_buffinit(L_, _B); |
55 | } | ||
56 | // starting with Lua 5.5, the writer is called one last time with nullptr, 0 at the end | ||
57 | if (b_ && size_) { | ||
58 | luaL_addlstring(_B, static_cast<char const*>(b_), size_); | ||
59 | } | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static constexpr int kWriterReturnCode{ 666 }; | ||
64 | [[nodiscard]] | ||
65 | static int dummy_writer([[maybe_unused]] lua_State* const L_, [[maybe_unused]] void const* p_, [[maybe_unused]] size_t sz_, [[maybe_unused]] void* ud_) | ||
66 | { | ||
67 | // always fail with this code | ||
68 | return kWriterReturnCode; | ||
69 | } | ||
70 | |||
71 | } // namespace local | ||
72 | } // namespace | ||
73 | |||
74 | // ################################################################################################# | ||
55 | 75 | ||
56 | /* | 76 | /* |
57 | * differentiation between C, bytecode and JIT-fast functions | 77 | * differentiation between C, bytecode and JIT-fast functions |
@@ -77,11 +97,11 @@ FuncSubType luaW_getfuncsubtype(lua_State* const L_, StackIndex const i_) | |||
77 | // luaW_dump expects the function at the top of the stack | 97 | // luaW_dump expects the function at the top of the stack |
78 | int const _popCount{ (luaW_absindex(L_, i_) == lua_gettop(L_)) ? 0 : (lua_pushvalue(L_, i_), 1) }; | 98 | int const _popCount{ (luaW_absindex(L_, i_) == lua_gettop(L_)) ? 0 : (lua_pushvalue(L_, i_), 1) }; |
79 | // here we either have a Lua bytecode or a LuaJIT-compiled function | 99 | // here we either have a Lua bytecode or a LuaJIT-compiled function |
80 | int const _dumpres{ luaW_dump(L_, dummy_writer, nullptr, 0) }; | 100 | int const _dumpres{ luaW_dump(L_, local::dummy_writer, nullptr, 0) }; |
81 | if (_popCount > 0) { | 101 | if (_popCount > 0) { |
82 | lua_pop(L_, _popCount); | 102 | lua_pop(L_, _popCount); |
83 | } | 103 | } |
84 | if (_dumpres == kWriterReturnCode) { | 104 | if (_dumpres == local::kWriterReturnCode) { |
85 | // anytime we get kWriterReturnCode, this means that luaW_dump() attempted a dump | 105 | // anytime we get kWriterReturnCode, this means that luaW_dump() attempted a dump |
86 | return FuncSubType::Bytecode; | 106 | return FuncSubType::Bytecode; |
87 | } | 107 | } |
@@ -92,7 +112,6 @@ FuncSubType luaW_getfuncsubtype(lua_State* const L_, StackIndex const i_) | |||
92 | // ################################################################################################# | 112 | // ################################################################################################# |
93 | 113 | ||
94 | namespace tools { | 114 | namespace tools { |
95 | |||
96 | // inspired from tconcat() in ltablib.c | 115 | // inspired from tconcat() in ltablib.c |
97 | [[nodiscard]] | 116 | [[nodiscard]] |
98 | std::string_view PushFQN(lua_State* const L_, StackIndex const t_) | 117 | std::string_view PushFQN(lua_State* const L_, StackIndex const t_) |
@@ -118,6 +137,18 @@ namespace tools { | |||
118 | return luaW_tostring(L_, kIdxTop); | 137 | return luaW_tostring(L_, kIdxTop); |
119 | } | 138 | } |
120 | 139 | ||
140 | // ############################################################################################# | ||
141 | |||
142 | [[nodiscard]] | ||
143 | int PushFunctionBytecode(lua_State* const L_, int const strip_) | ||
144 | { | ||
145 | luaL_Buffer B{}; | ||
146 | int const result_{ luaW_dump(L_, local::buf_writer, &B, strip_) }; | ||
147 | if (result_ == 0) { // documentation says it should always be the case (because our writer only ever returns 0), but better safe than sorry | ||
148 | luaL_pushresult(&B); | ||
149 | } | ||
150 | return result_; | ||
151 | } | ||
121 | } // namespace tools | 152 | } // namespace tools |
122 | 153 | ||
123 | // ################################################################################################# | 154 | // ################################################################################################# |
diff --git a/src/tools.hpp b/src/tools.hpp index 14f9855..51cbb9b 100644 --- a/src/tools.hpp +++ b/src/tools.hpp | |||
@@ -37,5 +37,7 @@ namespace tools { | |||
37 | void PopulateFuncLookupTable(lua_State* L_, StackIndex i_, std::string_view const& name_); | 37 | void PopulateFuncLookupTable(lua_State* L_, StackIndex i_, std::string_view const& name_); |
38 | [[nodiscard]] | 38 | [[nodiscard]] |
39 | std::string_view PushFQN(lua_State* L_, StackIndex t_); | 39 | std::string_view PushFQN(lua_State* L_, StackIndex t_); |
40 | [[nodiscard]] | ||
41 | int PushFunctionBytecode(lua_State* L_, int strip_); | ||
40 | void SerializeRequire(lua_State* L_); | 42 | void SerializeRequire(lua_State* L_); |
41 | } // namespace tools | 43 | } // namespace tools |