Skip to content

Commit

Permalink
Use separate instruction for setmetatable
Browse files Browse the repository at this point in the history
  • Loading branch information
y5nw committed Feb 15, 2024
1 parent b0b5ab2 commit 00dce32
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 21 deletions.
51 changes: 34 additions & 17 deletions src/script/common/c_packer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,23 @@ static inline bool suitable_key(lua_State *L, int idx)
}
}

// get core.known_metatables for indexing
// returns true if the tables exists (which is pushed onto the stack),
// false otherwise (nothing is pushed onto the stack)
static inline bool get_known_lua_metatables(lua_State *L)
{
lua_getglobal(L, "core");
if (lua_istable(L, -1)) {
lua_getfield(L, -1, "known_metatables");
lua_insert(L, -2);
}
lua_pop(L, 1); // pop core
if (lua_istable(L, -1))
return true;
lua_pop(L, 2); // pop core.known_metatables as it is not useful here
return false;
}

namespace {
// checks if you left any values on the stack, for debugging
class StackChecker {
Expand Down Expand Up @@ -393,14 +410,14 @@ static VectorRef<PackedInstr> pack_inner(lua_State *L, int idx, int vidx, Packed
}

// try to preserve metatable information
if (lua_getmetatable(L, idx)) {
lua_getglobal(L, "core");
lua_getfield(L, -1, "known_metatables");
lua_pushvalue(L, -3);
if (lua_getmetatable(L, idx) && get_known_lua_metatables(L)) {
lua_insert(L, -2);
lua_gettable(L, -2);
if (lua_isstring(L, -1))
rtable->sdata2 = std::string(lua_tostring(L, -1));
lua_pop(L, 4);
if (lua_isstring(L, -1)) {
auto r = emplace(pv, INSTR_SETMETATABLE);
r->sdata = std::string(lua_tostring(L, -1));
}
lua_pop(L, 2);
}

assert(vidx == vi_table + 1);
Expand Down Expand Up @@ -463,6 +480,16 @@ void script_unpack(lua_State *L, PackedValue *pv)
lua_pushinteger(L, i.ref);
lua_rawget(L, top);
break;
case INSTR_SETMETATABLE:
if (get_known_lua_metatables(L)) {
lua_getfield(L, -1, i.sdata.c_str());
if (lua_istable(L, -1))
lua_setmetatable(L, -3);
else
lua_pop(L, 1);
lua_pop(L, 1);
}
break;

/* Lua types */
case LUA_TNIL:
Expand All @@ -479,16 +506,6 @@ void script_unpack(lua_State *L, PackedValue *pv)
break;
case LUA_TTABLE:
lua_createtable(L, i.uidata1, i.uidata2);
lua_getglobal(L, "core");
lua_getfield(L, -1, "known_metatables");
if (lua_istable(L, -1)) {
lua_getfield(L, -1, i.sdata2.c_str());
if (lua_istable(L, -1))
lua_setmetatable(L, -4);
else
lua_pop(L, 1);
}
lua_pop(L, 2);
break;
case LUA_TFUNCTION:
luaL_loadbuffer(L, i.sdata.data(), i.sdata.size(), nullptr);
Expand Down
9 changes: 5 additions & 4 deletions src/script/common/c_packer.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ extern "C" {
states and cannot be used for persistence or network transfer.
*/

#define INSTR_SETTABLE (-10)
#define INSTR_POP (-11)
#define INSTR_PUSHREF (-12)
#define INSTR_SETTABLE (-10)
#define INSTR_POP (-11)
#define INSTR_PUSHREF (-12)
#define INSTR_SETMETATABLE (-13)

/**
* Represents a single instruction that pushes a new value or works with existing ones.
Expand Down Expand Up @@ -69,9 +70,9 @@ struct PackedInstr
- function: buffer
- w/ set_into: string key (no null bytes!)
- userdata: name in registry
- INSTR_SETMETATABLE: name of the metatable
*/
std::string sdata;
std::string sdata2; // table: name of the metatable

PackedInstr() : type(0), set_into(0), keep_ref(false), pop(false) {}
};
Expand Down

0 comments on commit 00dce32

Please sign in to comment.