diff options
Diffstat (limited to '')
-rw-r--r-- | src/universe.cpp | 79 |
1 files changed, 78 insertions, 1 deletions
diff --git a/src/universe.cpp b/src/universe.cpp index 097c642..b63008a 100644 --- a/src/universe.cpp +++ b/src/universe.cpp | |||
@@ -41,6 +41,10 @@ extern LUAG_FUNC(linda); | |||
41 | 41 | ||
42 | // ################################################################################################# | 42 | // ################################################################################################# |
43 | 43 | ||
44 | static constexpr std::string_view kOnStateCreate{ "on_state_create" }; // update lanes.lua if the name changes! | ||
45 | |||
46 | // ################################################################################################# | ||
47 | |||
44 | // xxh64 of string "kUniverseFullRegKey" generated at https://www.pelock.com/products/hash-calculator | 48 | // xxh64 of string "kUniverseFullRegKey" generated at https://www.pelock.com/products/hash-calculator |
45 | static constexpr RegistryUniqueKey kUniverseFullRegKey{ 0x1C2D76870DD9DD9Full }; | 49 | static constexpr RegistryUniqueKey kUniverseFullRegKey{ 0x1C2D76870DD9DD9Full }; |
46 | 50 | ||
@@ -74,6 +78,48 @@ Universe::Universe() | |||
74 | 78 | ||
75 | // ################################################################################################# | 79 | // ################################################################################################# |
76 | 80 | ||
81 | void Universe::callOnStateCreate(lua_State* const L_, lua_State* const from_, LookupMode const mode_) | ||
82 | { | ||
83 | if (std::holds_alternative<std::nullptr_t>(onStateCreateFunc)) { | ||
84 | return; | ||
85 | } | ||
86 | |||
87 | STACK_CHECK_START_REL(L_, 0); | ||
88 | DEBUGSPEW_CODE(DebugSpew(U_) << "calling on_state_create()" << std::endl); | ||
89 | if (std::holds_alternative<lua_CFunction>(onStateCreateFunc)) { | ||
90 | |||
91 | // C function: recreate a closure in the new state, bypassing the lookup scheme | ||
92 | lua_pushcfunction(L_, std::get<lua_CFunction>(onStateCreateFunc)); // on_state_create() | ||
93 | } else { // Lua function located in the config table, copied when we opened "lanes.core" | ||
94 | LUA_ASSERT(from_, std::holds_alternative<uintptr_t>(onStateCreateFunc)); | ||
95 | if (mode_ != LookupMode::LaneBody) { | ||
96 | // if attempting to call in a keeper state, do nothing because the function doesn't exist there | ||
97 | // this doesn't count as an error though | ||
98 | STACK_CHECK(L_, 0); | ||
99 | return; | ||
100 | } | ||
101 | kConfigRegKey.pushValue(L_); // L_: config | ||
102 | STACK_CHECK(L_, 1); | ||
103 | LuaType const _funcType{ luaG_getfield(L_, -1, kOnStateCreate) }; // L_: config on_state_create() | ||
104 | if (_funcType != LuaType::FUNCTION) { | ||
105 | raise_luaL_error(L_, "INTERNAL ERROR: %s is a %s, not a function", kOnStateCreate.data(), luaG_typename(L_, _funcType).data()); | ||
106 | } | ||
107 | lua_remove(L_, -2); // L_: on_state_create() | ||
108 | } | ||
109 | STACK_CHECK(L_, 1); | ||
110 | // capture error and raise it in caller state | ||
111 | std::string_view const _stateType{ mode_ == LookupMode::LaneBody ? "lane" : "keeper" }; | ||
112 | luaG_pushstring(L_, _stateType); // L_: on_state_create() "<type>" | ||
113 | if (lua_pcall(L_, 1, 0, 0) != LUA_OK) { | ||
114 | raise_luaL_error(from_, "%s failed: \"%s\"", kOnStateCreate.data(), lua_isstring(L_, -1) ? luaG_tostring(L_, -1).data() : luaG_typename(L_, -1).data()); | ||
115 | } | ||
116 | STACK_CHECK(L_, 0); | ||
117 | } | ||
118 | |||
119 | |||
120 | |||
121 | // ################################################################################################# | ||
122 | |||
77 | // only called from the master state | 123 | // only called from the master state |
78 | [[nodiscard]] Universe* Universe::Create(lua_State* const L_) | 124 | [[nodiscard]] Universe* Universe::Create(lua_State* const L_) |
79 | { | 125 | { |
@@ -125,7 +171,7 @@ Universe::Universe() | |||
125 | // Linked chains handling | 171 | // Linked chains handling |
126 | _U->selfdestructFirst = SELFDESTRUCT_END; | 172 | _U->selfdestructFirst = SELFDESTRUCT_END; |
127 | _U->initializeAllocatorFunction(L_); | 173 | _U->initializeAllocatorFunction(L_); |
128 | state::InitializeOnStateCreate(_U, L_); | 174 | _U->initializeOnStateCreate(L_); |
129 | _U->keepers.initialize(*_U, L_, _nbUserKeepers, _keepers_gc_threshold); | 175 | _U->keepers.initialize(*_U, L_, _nbUserKeepers, _keepers_gc_threshold); |
130 | STACK_CHECK(L_, 0); | 176 | STACK_CHECK(L_, 0); |
131 | 177 | ||
@@ -252,6 +298,37 @@ int Universe::InitializeFinalizer(lua_State* const L_) | |||
252 | 298 | ||
253 | // ################################################################################################# | 299 | // ################################################################################################# |
254 | 300 | ||
301 | void Universe::initializeOnStateCreate(lua_State* const L_) | ||
302 | { | ||
303 | STACK_CHECK_START_REL(L_, 1); // L_: settings | ||
304 | if (luaG_getfield(L_, -1, kOnStateCreate) != LuaType::NIL) { // L_: settings on_state_create|nil | ||
305 | LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::FUNCTION); // ensured by lanes.lua parameter validation | ||
306 | // make sure the function doesn't have upvalues | ||
307 | char const* _upname{ lua_getupvalue(L_, -1, 1) }; // L_: settings on_state_create upval? | ||
308 | if (_upname != nullptr) { // should be "" for C functions with upvalues if any | ||
309 | raise_luaL_error(L_, "%s with upvalues are forbidden", kOnStateCreate.data()); | ||
310 | } | ||
311 | // store C function pointer in an internal variable | ||
312 | lua_CFunction const _func{ lua_tocfunction(L_, -1) }; // L_: settings on_state_create | ||
313 | if (_func) { | ||
314 | onStateCreateFunc.emplace<lua_CFunction>(_func); | ||
315 | // remove this C function from the config table so that it doesn't cause problems | ||
316 | // when we transfer the config table in newly created Lua states | ||
317 | lua_pushnil(L_); // L_: settings on_state_create nil | ||
318 | luaG_setfield(L_, -3, kOnStateCreate); // L_: settings on_state_create | ||
319 | } else { | ||
320 | // the function is still in the config table | ||
321 | onStateCreateFunc.emplace<uintptr_t>(std::bit_cast<uintptr_t>(kOnStateCreate.data())); | ||
322 | } | ||
323 | } else { | ||
324 | LUA_ASSERT(L_, std::holds_alternative<std::nullptr_t>(onStateCreateFunc)); | ||
325 | }; | ||
326 | lua_pop(L_, 1); // L_: settings | ||
327 | STACK_CHECK(L_, 1); | ||
328 | } | ||
329 | |||
330 | // ################################################################################################# | ||
331 | |||
255 | lanes::AllocatorDefinition Universe::resolveAllocator(lua_State* const L_, std::string_view const& hint_) const | 332 | lanes::AllocatorDefinition Universe::resolveAllocator(lua_State* const L_, std::string_view const& hint_) const |
256 | { | 333 | { |
257 | lanes::AllocatorDefinition _ret{ protectedAllocator }; | 334 | lanes::AllocatorDefinition _ret{ protectedAllocator }; |