aboutsummaryrefslogtreecommitdiff
path: root/src/tools.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools.cpp')
-rw-r--r--src/tools.cpp101
1 files changed, 64 insertions, 37 deletions
diff --git a/src/tools.cpp b/src/tools.cpp
index cbfefb0..cd1c593 100644
--- a/src/tools.cpp
+++ b/src/tools.cpp
@@ -45,13 +45,29 @@ static constexpr RegistryUniqueKey kLookupCacheRegKey{ 0x9BF75F84E54B691Bull };
45 45
46// ################################################################################################# 46// #################################################################################################
47 47
48static constexpr int kWriterReturnCode{ 666 }; 48namespace {
49[[nodiscard]] 49 namespace local {
50static 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([[maybe_unused]] lua_State* const 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_ && size_) {
54} 54 luaL_addlstring(_B, static_cast<char const*>(b_), size_);
55 }
56 return 0;
57 }
58
59 static constexpr int kWriterReturnCode{ 666 };
60 [[nodiscard]]
61 static int dummy_writer([[maybe_unused]] lua_State* const L_, [[maybe_unused]] void const* p_, [[maybe_unused]] size_t sz_, [[maybe_unused]] void* ud_)
62 {
63 // always fail with this code
64 return kWriterReturnCode;
65 }
66
67 } // namespace local
68} // namespace
69
70// #################################################################################################
55 71
56/* 72/*
57 * differentiation between C, bytecode and JIT-fast functions 73 * differentiation between C, bytecode and JIT-fast functions
@@ -59,30 +75,28 @@ static int dummy_writer([[maybe_unused]] lua_State* const L_, [[maybe_unused]] v
59 * +-------------------+------------+----------+ 75 * +-------------------+------------+----------+
60 * | bytecode | C function | JIT-fast | 76 * | bytecode | C function | JIT-fast |
61 * +-----------------+-------------------+------------+----------+ 77 * +-----------------+-------------------+------------+----------+
62 * | lua_topointer | | | | 78 * | lua_tocfunction | nullptr | <some p> | nullptr |
63 * +-----------------+-------------------+------------+----------+ 79 * +-----------------+-------------------+------------+----------+
64 * | lua_tocfunction | nullptr | | nullptr | 80 * | luaW_dump | kWriterReturnCode | 1 | 1 |
65 * +-----------------+-------------------+------------+----------+
66 * | luaG_dump | kWriterReturnCode | 1 | 1 |
67 * +-----------------+-------------------+------------+----------+ 81 * +-----------------+-------------------+------------+----------+
68 */ 82 */
69 83
70[[nodiscard]] 84[[nodiscard]]
71FuncSubType luaG_getfuncsubtype(lua_State* const L_, StackIndex const i_) 85FuncSubType luaW_getfuncsubtype(lua_State* const L_, StackIndex const i_)
72{ 86{
73 if (lua_tocfunction(L_, i_)) { // nullptr for LuaJIT-fast && bytecode functions 87 if (lua_tocfunction(L_, i_)) { // nullptr for LuaJIT-fast && bytecode functions
74 return FuncSubType::Native; 88 return FuncSubType::Native;
75 } 89 }
76 90
77 // luaG_dump expects the function at the top of the stack 91 // luaW_dump expects the function at the top of the stack
78 int const _popCount{ (luaG_absindex(L_, i_) == lua_gettop(L_)) ? 0 : (lua_pushvalue(L_, i_), 1) }; 92 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 93 // here we either have a Lua bytecode or a LuaJIT-compiled function
80 int const _dumpres{ luaG_dump(L_, dummy_writer, nullptr, 0) }; 94 int const _dumpres{ luaW_dump(L_, local::dummy_writer, nullptr, 0) };
81 if (_popCount > 0) { 95 if (_popCount > 0) {
82 lua_pop(L_, _popCount); 96 lua_pop(L_, _popCount);
83 } 97 }
84 if (_dumpres == kWriterReturnCode) { 98 if (_dumpres == local::kWriterReturnCode) {
85 // anytime we get kWriterReturnCode, this means that luaG_dump() attempted a dump 99 // anytime we get kWriterReturnCode, this means that luaW_dump() attempted a dump
86 return FuncSubType::Bytecode; 100 return FuncSubType::Bytecode;
87 } 101 }
88 // we didn't try to dump, therefore this is a LuaJIT-fast function 102 // we didn't try to dump, therefore this is a LuaJIT-fast function
@@ -92,7 +106,6 @@ FuncSubType luaG_getfuncsubtype(lua_State* const L_, StackIndex const i_)
92// ################################################################################################# 106// #################################################################################################
93 107
94namespace tools { 108namespace tools {
95
96 // inspired from tconcat() in ltablib.c 109 // inspired from tconcat() in ltablib.c
97 [[nodiscard]] 110 [[nodiscard]]
98 std::string_view PushFQN(lua_State* const L_, StackIndex const t_) 111 std::string_view PushFQN(lua_State* const L_, StackIndex const t_)
@@ -115,9 +128,23 @@ namespace tools {
115 // &b is popped at that point (-> replaced by the result) 128 // &b is popped at that point (-> replaced by the result)
116 luaL_pushresult(&_b); // L_: ... {} ... "<result>" 129 luaL_pushresult(&_b); // L_: ... {} ... "<result>"
117 STACK_CHECK(L_, 1); 130 STACK_CHECK(L_, 1);
118 return luaG_tostring(L_, kIdxTop); 131 return luaW_tostring(L_, kIdxTop);
119 } 132 }
120 133
134 // #############################################################################################
135
136 void PushFunctionBytecode(SourceState const L1_, DestState const L2_, int const strip_)
137 {
138 luaL_Buffer B{};
139 STACK_CHECK_START_REL(L1_, 0);
140 STACK_CHECK_START_REL(L2_, 0);
141 STACK_GROW(L2_, 2);
142 luaL_buffinit(L2_, &B); // L1_: ... f L2_: ... <B stuff>
143 luaW_dump(L1_, local::buf_writer, &B, strip_);
144 luaL_pushresult(&B); // L2_: ... "<bytecode>"
145 STACK_CHECK(L2_, 1);
146 STACK_CHECK(L1_, 0);
147 }
121} // namespace tools 148} // namespace tools
122 149
123// ################################################################################################# 150// #################################################################################################
@@ -145,10 +172,10 @@ static void update_lookup_entry(lua_State* const L_, StackIndex const ctxBase_,
145 // first, raise an error if the function is already known 172 // first, raise an error if the function is already known
146 lua_pushvalue(L_, -1); // L_: ... {bfc} k o o 173 lua_pushvalue(L_, -1); // L_: ... {bfc} k o o
147 lua_rawget(L_, _dest); // L_: ... {bfc} k o name? 174 lua_rawget(L_, _dest); // L_: ... {bfc} k o name?
148 std::string_view const _prevName{ luaG_tostring(L_, kIdxTop) }; // nullptr if we got nil (first encounter of this object) 175 std::string_view const _prevName{ luaW_tostring(L_, kIdxTop) }; // nullptr if we got nil (first encounter of this object)
149 // push name in fqn stack (note that concatenation will crash if name is a not string or a number) 176 // push name in fqn stack (note that concatenation will crash if name is a not string or a number)
150 lua_pushvalue(L_, -3); // L_: ... {bfc} k o name? k 177 lua_pushvalue(L_, -3); // L_: ... {bfc} k o name? k
151 LUA_ASSERT(L_, luaG_type(L_, kIdxTop) == LuaType::NUMBER || luaG_type(L_, kIdxTop) == LuaType::STRING); 178 LUA_ASSERT(L_, luaW_type(L_, kIdxTop) == LuaType::NUMBER || luaW_type(L_, kIdxTop) == LuaType::STRING);
152 TableIndex const _deeper{ depth_ + 1 }; 179 TableIndex const _deeper{ depth_ + 1 };
153 lua_rawseti(L_, _fqn, _deeper); // L_: ... {bfc} k o name? 180 lua_rawseti(L_, _fqn, _deeper); // L_: ... {bfc} k o name?
154 // generate name 181 // generate name
@@ -161,7 +188,7 @@ static void update_lookup_entry(lua_State* const L_, StackIndex const ctxBase_,
161 // Therefore, when we encounter an object for which a name was previously registered, we need to select a single name 188 // Therefore, when we encounter an object for which a name was previously registered, we need to select a single name
162 // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded 189 // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded
163 if (!_prevName.empty() && ((_prevName.size() < _newName.size()) || (_prevName <= _newName))) { 190 if (!_prevName.empty() && ((_prevName.size() < _newName.size()) || (_prevName <= _newName))) {
164 DEBUGSPEW_CODE(DebugSpew(_U) << luaG_typename(L_, StackIndex{ -3 }) << " '" << _newName << "' remains named '" << _prevName << "'" << std::endl); 191 DEBUGSPEW_CODE(DebugSpew(_U) << luaW_typename(L_, StackIndex{ -3 }) << " '" << _newName << "' remains named '" << _prevName << "'" << std::endl);
165 // the previous name is 'smaller' than the one we just generated: keep it! 192 // the previous name is 'smaller' than the one we just generated: keep it!
166 lua_pop(L_, 3); // L_: ... {bfc} k 193 lua_pop(L_, 3); // L_: ... {bfc} k
167 } else { 194 } else {
@@ -175,7 +202,7 @@ static void update_lookup_entry(lua_State* const L_, StackIndex const ctxBase_,
175 } else { 202 } else {
176 lua_remove(L_, -2); // L_: ... {bfc} k o "f.q.n" 203 lua_remove(L_, -2); // L_: ... {bfc} k o "f.q.n"
177 } 204 }
178 DEBUGSPEW_CODE(DebugSpew(_U) << luaG_typename(L_, StackIndex{ -2 }) << " '" << _newName << "'" << std::endl); 205 DEBUGSPEW_CODE(DebugSpew(_U) << luaW_typename(L_, StackIndex{ -2 }) << " '" << _newName << "'" << std::endl);
179 // prepare the stack for database feed 206 // prepare the stack for database feed
180 lua_pushvalue(L_, -1); // L_: ... {bfc} k o "f.q.n" "f.q.n" 207 lua_pushvalue(L_, -1); // L_: ... {bfc} k o "f.q.n" "f.q.n"
181 lua_pushvalue(L_, -3); // L_: ... {bfc} k o "f.q.n" "f.q.n" o 208 lua_pushvalue(L_, -3); // L_: ... {bfc} k o "f.q.n" "f.q.n" o
@@ -210,7 +237,7 @@ static void populate_lookup_table_recur(lua_State* const L_, StackIndex const db
210 STACK_CHECK_START_REL(L_, 0); // L_: ... {i_} 237 STACK_CHECK_START_REL(L_, 0); // L_: ... {i_}
211 238
212 // if object is a userdata, replace it by its metatable 239 // if object is a userdata, replace it by its metatable
213 if (luaG_type(L_, i_) == LuaType::USERDATA) { 240 if (luaW_type(L_, i_) == LuaType::USERDATA) {
214 lua_getmetatable(L_, i_); // L_: ... {i_} mt 241 lua_getmetatable(L_, i_); // L_: ... {i_} mt
215 lua_replace(L_, i_); // L_: ... {i_} 242 lua_replace(L_, i_); // L_: ... {i_}
216 } 243 }
@@ -239,7 +266,7 @@ static void populate_lookup_table_recur(lua_State* const L_, StackIndex const db
239 lua_pushnil(L_); // L_: ... {i_} {bfc} nil 266 lua_pushnil(L_); // L_: ... {i_} {bfc} nil
240 while (lua_next(L_, i_) != 0) { // L_: ... {i_} {bfc} k v 267 while (lua_next(L_, i_) != 0) { // L_: ... {i_} {bfc} k v
241 // just for debug, not actually needed 268 // just for debug, not actually needed
242 // std::string_view const _key{ (luaG_type(L_, -2) == LuaType::STRING) ? luaG_tostring(L_, -2) : "not a string" }; 269 // std::string_view const _key{ (luaW_type(L_, -2) == LuaType::STRING) ? luaW_tostring(L_, -2) : "not a string" };
243 // subtable: process it recursively 270 // subtable: process it recursively
244 if (lua_istable(L_, kIdxTop)) { // L_: ... {i_} {bfc} k {} 271 if (lua_istable(L_, kIdxTop)) { // L_: ... {i_} {bfc} k {}
245 // increment visit count to make sure we will actually scan it at this recursive level 272 // increment visit count to make sure we will actually scan it at this recursive level
@@ -256,11 +283,11 @@ static void populate_lookup_table_recur(lua_State* const L_, StackIndex const db
256 lua_rawset(L_, _breadthFirstCache); // L_: ... {i_} {bfc} k {} 283 lua_rawset(L_, _breadthFirstCache); // L_: ... {i_} {bfc} k {}
257 // generate a name, and if we already had one name, keep whichever is the shorter 284 // generate a name, and if we already had one name, keep whichever is the shorter
258 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k 285 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k
259 } else if (lua_isfunction(L_, kIdxTop) && (luaG_getfuncsubtype(L_, kIdxTop) != FuncSubType::Bytecode)) { 286 } else if (lua_isfunction(L_, kIdxTop) && (luaW_getfuncsubtype(L_, kIdxTop) != FuncSubType::Bytecode)) {
260 // generate a name, and if we already had one name, keep whichever is the shorter 287 // generate a name, and if we already had one name, keep whichever is the shorter
261 // this pops the function from the stack 288 // this pops the function from the stack
262 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k 289 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k
263 } else if (luaG_type(L_, kIdxTop) == LuaType::USERDATA) { 290 } else if (luaW_type(L_, kIdxTop) == LuaType::USERDATA) {
264 // generate a name, and if we already had one name, keep whichever is the shorter 291 // generate a name, and if we already had one name, keep whichever is the shorter
265 // this pops the userdata from the stack 292 // this pops the userdata from the stack
266 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k 293 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k
@@ -273,13 +300,13 @@ static void populate_lookup_table_recur(lua_State* const L_, StackIndex const db
273 TableIndex const _deeper{ depth_ + 1 }; 300 TableIndex const _deeper{ depth_ + 1 };
274 lua_pushnil(L_); // L_: ... {i_} {bfc} nil 301 lua_pushnil(L_); // L_: ... {i_} {bfc} nil
275 while (lua_next(L_, _breadthFirstCache) != 0) { // L_: ... {i_} {bfc} k {} 302 while (lua_next(L_, _breadthFirstCache) != 0) { // L_: ... {i_} {bfc} k {}
276 DEBUGSPEW_CODE(std::string_view const _key{ (luaG_type(L_, StackIndex{ -2 }) == LuaType::STRING) ? luaG_tostring(L_, StackIndex{ -2 }) : std::string_view{ "<not a string>" } }); 303 DEBUGSPEW_CODE(std::string_view const _key{ (luaW_type(L_, StackIndex{ -2 }) == LuaType::STRING) ? luaW_tostring(L_, StackIndex{ -2 }) : std::string_view{ "<not a string>" } });
277 DEBUGSPEW_CODE(DebugSpew(_U) << "table '"<< _key <<"'" << std::endl); 304 DEBUGSPEW_CODE(DebugSpew(_U) << "table '"<< _key <<"'" << std::endl);
278 DEBUGSPEW_CODE(DebugSpewIndentScope _scope2{ _U }); 305 DEBUGSPEW_CODE(DebugSpewIndentScope _scope2{ _U });
279 // un-visit this table in case we do need to process it 306 // un-visit this table in case we do need to process it
280 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {} 307 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {}
281 lua_rawget(L_, _cache); // L_: ... {i_} {bfc} k {} n 308 lua_rawget(L_, _cache); // L_: ... {i_} {bfc} k {} n
282 LUA_ASSERT(L_, luaG_type(L_, kIdxTop) == LuaType::NUMBER); 309 LUA_ASSERT(L_, luaW_type(L_, kIdxTop) == LuaType::NUMBER);
283 _visit_count = lua_tointeger(L_, -1) - 1; 310 _visit_count = lua_tointeger(L_, -1) - 1;
284 lua_pop(L_, 1); // L_: ... {i_} {bfc} k {} 311 lua_pop(L_, 1); // L_: ... {i_} {bfc} k {}
285 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {} 312 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {}
@@ -312,7 +339,7 @@ namespace tools {
312 // create a "fully.qualified.name" <-> function equivalence database 339 // create a "fully.qualified.name" <-> function equivalence database
313 void PopulateFuncLookupTable(lua_State* const L_, StackIndex const i_, std::string_view const& name_) 340 void PopulateFuncLookupTable(lua_State* const L_, StackIndex const i_, std::string_view const& name_)
314 { 341 {
315 StackIndex const _in_base{ luaG_absindex(L_, i_) }; 342 StackIndex const _in_base{ luaW_absindex(L_, i_) };
316 DEBUGSPEW_CODE(Universe* _U = Universe::Get(L_)); 343 DEBUGSPEW_CODE(Universe* _U = Universe::Get(L_));
317 std::string_view _name{ name_.empty() ? std::string_view{} : name_ }; 344 std::string_view _name{ name_.empty() ? std::string_view{} : name_ };
318 DEBUGSPEW_CODE(DebugSpew(_U) << L_ << ": PopulateFuncLookupTable('" << _name << "')" << std::endl); 345 DEBUGSPEW_CODE(DebugSpew(_U) << L_ << ": PopulateFuncLookupTable('" << _name << "')" << std::endl);
@@ -323,24 +350,24 @@ namespace tools {
323 StackIndex const _dbIdx{ lua_gettop(L_) }; 350 StackIndex const _dbIdx{ lua_gettop(L_) };
324 STACK_CHECK(L_, 1); 351 STACK_CHECK(L_, 1);
325 LUA_ASSERT(L_, lua_istable(L_, -1)); 352 LUA_ASSERT(L_, lua_istable(L_, -1));
326 LuaType const _moduleType{ luaG_type(L_, _in_base) }; 353 LuaType const _moduleType{ luaW_type(L_, _in_base) };
327 if ((_moduleType == LuaType::FUNCTION) || (_moduleType == LuaType::USERDATA)) { // for example when a module is a simple function 354 if ((_moduleType == LuaType::FUNCTION) || (_moduleType == LuaType::USERDATA)) { // for example when a module is a simple function
328 if (_name.empty()) { 355 if (_name.empty()) {
329 _name = "nullptr"; 356 _name = "nullptr";
330 } 357 }
331 lua_pushvalue(L_, _in_base); // L_: {} f 358 lua_pushvalue(L_, _in_base); // L_: {} f
332 luaG_pushstring(L_, _name); // L_: {} f name_ 359 luaW_pushstring(L_, _name); // L_: {} f name_
333 lua_rawset(L_, -3); // L_: {} 360 lua_rawset(L_, -3); // L_: {}
334 luaG_pushstring(L_, _name); // L_: {} name_ 361 luaW_pushstring(L_, _name); // L_: {} name_
335 lua_pushvalue(L_, _in_base); // L_: {} name_ f 362 lua_pushvalue(L_, _in_base); // L_: {} name_ f
336 lua_rawset(L_, -3); // L_: {} 363 lua_rawset(L_, -3); // L_: {}
337 lua_pop(L_, 1); // L_: 364 lua_pop(L_, 1); // L_:
338 } else if (luaG_type(L_, _in_base) == LuaType::TABLE) { 365 } else if (luaW_type(L_, _in_base) == LuaType::TABLE) {
339 lua_newtable(L_); // L_: {} {fqn} 366 lua_newtable(L_); // L_: {} {fqn}
340 TableIndex _startDepth{ 0 }; 367 TableIndex _startDepth{ 0 };
341 if (!_name.empty()) { 368 if (!_name.empty()) {
342 STACK_CHECK(L_, 2); 369 STACK_CHECK(L_, 2);
343 luaG_pushstring(L_, _name); // L_: {} {fqn} "name" 370 luaW_pushstring(L_, _name); // L_: {} {fqn} "name"
344 // generate a name, and if we already had one name, keep whichever is the shorter 371 // generate a name, and if we already had one name, keep whichever is the shorter
345 lua_pushvalue(L_, _in_base); // L_: {} {fqn} "name" t 372 lua_pushvalue(L_, _in_base); // L_: {} {fqn} "name" t
346 update_lookup_entry(L_, _dbIdx, _startDepth); // L_: {} {fqn} "name" 373 update_lookup_entry(L_, _dbIdx, _startDepth); // L_: {} {fqn} "name"
@@ -355,7 +382,7 @@ namespace tools {
355 lua_pop(L_, 3); // L_: 382 lua_pop(L_, 3); // L_:
356 } else { 383 } else {
357 lua_pop(L_, 1); // L_: 384 lua_pop(L_, 1); // L_:
358 raise_luaL_error(L_, "unsupported module type %s", luaG_typename(L_, _in_base).data()); 385 raise_luaL_error(L_, "unsupported module type %s", luaW_typename(L_, _in_base).data());
359 } 386 }
360 STACK_CHECK(L_, 0); 387 STACK_CHECK(L_, 0);
361 } 388 }
@@ -373,7 +400,7 @@ namespace tools {
373 +[](lua_State* L_) 400 +[](lua_State* L_)
374 { 401 {
375 int const _args{ lua_gettop(L_) }; // L_: args... 402 int const _args{ lua_gettop(L_) }; // L_: args...
376 //[[maybe_unused]] std::string_view const _modname{ luaG_checkstring(L_, 1) }; 403 //[[maybe_unused]] std::string_view const _modname{ luaW_checkstring(L_, 1) };
377 404
378 STACK_GROW(L_, 1); 405 STACK_GROW(L_, 1);
379 406