diff options
Diffstat (limited to 'src/deep.cpp')
-rw-r--r-- | src/deep.cpp | 330 |
1 files changed, 145 insertions, 185 deletions
diff --git a/src/deep.cpp b/src/deep.cpp index 13932a4..11e1ea7 100644 --- a/src/deep.cpp +++ b/src/deep.cpp | |||
@@ -46,95 +46,90 @@ THE SOFTWARE. | |||
46 | 46 | ||
47 | /*---=== Deep userdata ===---*/ | 47 | /*---=== Deep userdata ===---*/ |
48 | 48 | ||
49 | /* | 49 | /* |
50 | * 'registry[REGKEY]' is a two-way lookup table for 'factory's and those type's | 50 | * 'registry[REGKEY]' is a two-way lookup table for 'factory's and those type's |
51 | * metatables: | 51 | * metatables: |
52 | * | 52 | * |
53 | * metatable -> factory | 53 | * metatable -> factory |
54 | * factory -> metatable | 54 | * factory -> metatable |
55 | */ | 55 | */ |
56 | // xxh64 of string "kDeepLookupRegKey" generated at https://www.pelock.com/products/hash-calculator | 56 | // xxh64 of string "kDeepLookupRegKey" generated at https://www.pelock.com/products/hash-calculator |
57 | static constexpr RegistryUniqueKey kDeepLookupRegKey{ 0xC6788345703C6059ull }; | 57 | static constexpr RegistryUniqueKey kDeepLookupRegKey{ 0xC6788345703C6059ull }; |
58 | 58 | ||
59 | /* | 59 | /* |
60 | * The deep proxy cache is a weak valued table listing all deep UD proxies indexed by the deep UD that they are proxying | 60 | * The deep proxy cache is a weak valued table listing all deep UD proxies indexed by the deep UD that they are proxying |
61 | * xxh64 of string "kDeepProxyCacheRegKey" generated at https://www.pelock.com/products/hash-calculator | 61 | * xxh64 of string "kDeepProxyCacheRegKey" generated at https://www.pelock.com/products/hash-calculator |
62 | */ | 62 | */ |
63 | static constexpr RegistryUniqueKey kDeepProxyCacheRegKey{ 0xEBCD49AE1A3DD35Eull }; | 63 | static constexpr RegistryUniqueKey kDeepProxyCacheRegKey{ 0xEBCD49AE1A3DD35Eull }; |
64 | 64 | ||
65 | /* | 65 | /* |
66 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. | 66 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. |
67 | * Pops the both values off the stack. | 67 | * Pops the both values off the stack. |
68 | */ | 68 | */ |
69 | static void set_deep_lookup(lua_State* L_) | 69 | static void set_deep_lookup(lua_State* L_) |
70 | { | 70 | { |
71 | STACK_GROW( L_, 3); | 71 | STACK_GROW(L_, 3); |
72 | STACK_CHECK_START_REL(L_, 2); // a b | 72 | STACK_CHECK_START_REL(L_, 2); // L_: a b |
73 | push_registry_subtable( L_, kDeepLookupRegKey); // a b {} | 73 | push_registry_subtable(L_, kDeepLookupRegKey); // L_: a b {} |
74 | STACK_CHECK( L_, 3); | 74 | STACK_CHECK(L_, 3); |
75 | lua_insert( L_, -3); // {} a b | 75 | lua_insert(L_, -3); // L_: {} a b |
76 | lua_pushvalue( L_, -1); // {} a b b | 76 | lua_pushvalue(L_, -1); // L_: {} a b b |
77 | lua_pushvalue( L_,-3); // {} a b b a | 77 | lua_pushvalue(L_, -3); // L_: {} a b b a |
78 | lua_rawset( L_, -5); // {} a b | 78 | lua_rawset(L_, -5); // L_: {} a b |
79 | lua_rawset( L_, -3); // {} | 79 | lua_rawset(L_, -3); // L_: {} |
80 | lua_pop( L_, 1); // | 80 | lua_pop(L_, 1); // L_: |
81 | STACK_CHECK( L_, 0); | 81 | STACK_CHECK(L_, 0); |
82 | } | 82 | } |
83 | 83 | ||
84 | // ################################################################################################# | 84 | // ################################################################################################# |
85 | 85 | ||
86 | /* | 86 | /* |
87 | * Pops the key (metatable or factory) off the stack, and replaces with the | 87 | * Pops the key (metatable or factory) off the stack, and replaces with the |
88 | * deep lookup value (factory/metatable/nil). | 88 | * deep lookup value (factory/metatable/nil). |
89 | */ | 89 | */ |
90 | static void get_deep_lookup(lua_State* L_) | 90 | static void get_deep_lookup(lua_State* L_) |
91 | { | 91 | { |
92 | STACK_GROW( L_, 1); | 92 | STACK_GROW(L_, 1); |
93 | STACK_CHECK_START_REL(L_, 1); // a | 93 | STACK_CHECK_START_REL(L_, 1); // L_: a |
94 | kDeepLookupRegKey.pushValue(L_); // a {} | 94 | kDeepLookupRegKey.pushValue(L_); // L_: a {} |
95 | if (!lua_isnil( L_, -1)) | 95 | if (!lua_isnil(L_, -1)) { |
96 | { | 96 | lua_insert(L_, -2); // L_: {} a |
97 | lua_insert( L_, -2); // {} a | 97 | lua_rawget(L_, -2); // L_: {} b |
98 | lua_rawget( L_, -2); // {} b | ||
99 | } | 98 | } |
100 | lua_remove( L_, -2); // a|b | 99 | lua_remove(L_, -2); // L_: a|b |
101 | STACK_CHECK( L_, 1); | 100 | STACK_CHECK(L_, 1); |
102 | } | 101 | } |
103 | 102 | ||
104 | // ################################################################################################# | 103 | // ################################################################################################# |
105 | 104 | ||
106 | /* | 105 | /* |
107 | * Return the registered factory for 'index' (deep userdata proxy), | 106 | * Return the registered factory for 'index' (deep userdata proxy), |
108 | * or nullptr if 'index' is not a deep userdata proxy. | 107 | * or nullptr if 'index' is not a deep userdata proxy. |
109 | */ | 108 | */ |
110 | [[nodiscard]] static inline DeepFactory* get_factory(lua_State* L_, int index_, LookupMode mode_) | 109 | [[nodiscard]] static inline DeepFactory* get_factory(lua_State* L_, int index_, LookupMode mode_) |
111 | { | 110 | { |
112 | // when looking inside a keeper, we are 100% sure the object is a deep userdata | 111 | // when looking inside a keeper, we are 100% sure the object is a deep userdata |
113 | if (mode_ == LookupMode::FromKeeper) | 112 | if (mode_ == LookupMode::FromKeeper) { |
114 | { | ||
115 | DeepPrelude* const proxy{ *lua_tofulluserdata<DeepPrelude*>(L_, index_) }; | 113 | DeepPrelude* const proxy{ *lua_tofulluserdata<DeepPrelude*>(L_, index_) }; |
116 | // we can (and must) cast and fetch the internally stored factory | 114 | // we can (and must) cast and fetch the internally stored factory |
117 | return &proxy->m_factory; | 115 | return &proxy->m_factory; |
118 | } | 116 | } else { |
119 | else | ||
120 | { | ||
121 | // essentially we are making sure that the metatable of the object we want to copy is stored in our metatable/factory database | 117 | // essentially we are making sure that the metatable of the object we want to copy is stored in our metatable/factory database |
122 | // it is the only way to ensure that the userdata is indeed a deep userdata! | 118 | // it is the only way to ensure that the userdata is indeed a deep userdata! |
123 | // of course, we could just trust the caller, but we won't | 119 | // of course, we could just trust the caller, but we won't |
124 | STACK_GROW( L_, 1); | 120 | STACK_GROW(L_, 1); |
125 | STACK_CHECK_START_REL(L_, 0); | 121 | STACK_CHECK_START_REL(L_, 0); |
126 | 122 | ||
127 | if (!lua_getmetatable( L_, index_)) // deep ... metatable? | 123 | if (!lua_getmetatable(L_, index_)) { // L_: deep ... metatable? |
128 | { | ||
129 | return nullptr; // no metatable: can't be a deep userdata object! | 124 | return nullptr; // no metatable: can't be a deep userdata object! |
130 | } | 125 | } |
131 | 126 | ||
132 | // replace metatable with the factory pointer, if it is actually a deep userdata | 127 | // replace metatable with the factory pointer, if it is actually a deep userdata |
133 | get_deep_lookup( L_); // deep ... factory|nil | 128 | get_deep_lookup(L_); // L_: deep ... factory|nil |
134 | 129 | ||
135 | DeepFactory* const ret{ lua_tolightuserdata<DeepFactory>(L_, -1) }; // nullptr if not a userdata | 130 | DeepFactory* const ret{ lua_tolightuserdata<DeepFactory>(L_, -1) }; // nullptr if not a userdata |
136 | lua_pop( L_, 1); | 131 | lua_pop(L_, 1); |
137 | STACK_CHECK( L_, 0); | 132 | STACK_CHECK(L_, 0); |
138 | return ret; | 133 | return ret; |
139 | } | 134 | } |
140 | } | 135 | } |
@@ -165,19 +160,15 @@ void DeepFactory::DeleteDeepObject(lua_State* L_, DeepPrelude* o_) | |||
165 | // in that case, we are not multithreaded and locking isn't necessary anyway | 160 | // in that case, we are not multithreaded and locking isn't necessary anyway |
166 | bool const isLastRef{ p->m_refcount.fetch_sub(1, std::memory_order_relaxed) == 1 }; | 161 | bool const isLastRef{ p->m_refcount.fetch_sub(1, std::memory_order_relaxed) == 1 }; |
167 | 162 | ||
168 | if (isLastRef) | 163 | if (isLastRef) { |
169 | { | ||
170 | // retrieve wrapped __gc | 164 | // retrieve wrapped __gc |
171 | lua_pushvalue(L_, lua_upvalueindex( 1)); // self __gc? | 165 | lua_pushvalue(L_, lua_upvalueindex(1)); // L_: self __gc? |
172 | if (!lua_isnil(L_, -1)) | 166 | if (!lua_isnil(L_, -1)) { |
173 | { | 167 | lua_insert(L_, -2); // L_: __gc self |
174 | lua_insert(L_, -2); // __gc self | 168 | lua_call(L_, 1, 0); // L_: |
175 | lua_call(L_, 1, 0); // | 169 | } else { |
176 | } | ||
177 | else | ||
178 | { | ||
179 | // need an empty stack in case we are GC_ing from a Keeper, so that empty stack checks aren't triggered | 170 | // need an empty stack in case we are GC_ing from a Keeper, so that empty stack checks aren't triggered |
180 | lua_pop(L_, 2); | 171 | lua_pop(L_, 2); // L_: |
181 | } | 172 | } |
182 | DeepFactory::DeleteDeepObject(L_, p); | 173 | DeepFactory::DeleteDeepObject(L_, p); |
183 | } | 174 | } |
@@ -198,133 +189,111 @@ void DeepFactory::DeleteDeepObject(lua_State* L_, DeepPrelude* o_) | |||
198 | char const* DeepFactory::PushDeepProxy(DestState L_, DeepPrelude* prelude_, int nuv_, LookupMode mode_) | 189 | char const* DeepFactory::PushDeepProxy(DestState L_, DeepPrelude* prelude_, int nuv_, LookupMode mode_) |
199 | { | 190 | { |
200 | // Check if a proxy already exists | 191 | // Check if a proxy already exists |
201 | push_registry_subtable_mode(L_, kDeepProxyCacheRegKey, "v"); // DPC | 192 | push_registry_subtable_mode(L_, kDeepProxyCacheRegKey, "v"); // L_: DPC |
202 | lua_pushlightuserdata(L_, prelude_); // DPC deep | 193 | lua_pushlightuserdata(L_, prelude_); // L_: DPC deep |
203 | lua_rawget(L_, -2); // DPC proxy | 194 | lua_rawget(L_, -2); // L_: DPC proxy |
204 | if (!lua_isnil(L_, -1)) | 195 | if (!lua_isnil(L_, -1)) { |
205 | { | 196 | lua_remove(L_, -2); // L_: proxy |
206 | lua_remove(L_, -2); // proxy | ||
207 | return nullptr; | 197 | return nullptr; |
208 | } | 198 | } else { |
209 | else | 199 | lua_pop(L_, 1); // L_: DPC |
210 | { | ||
211 | lua_pop(L_, 1); // DPC | ||
212 | } | 200 | } |
213 | 201 | ||
214 | STACK_GROW(L_, 7); | 202 | STACK_GROW(L_, 7); |
215 | STACK_CHECK_START_REL(L_, 0); | 203 | STACK_CHECK_START_REL(L_, 0); |
216 | 204 | ||
217 | // a new full userdata, fitted with the specified number of uservalue slots (always 1 for Lua < 5.4) | 205 | // a new full userdata, fitted with the specified number of uservalue slots (always 1 for Lua < 5.4) |
218 | DeepPrelude** const proxy{ lua_newuserdatauv<DeepPrelude*>(L_, nuv_) }; // DPC proxy | 206 | DeepPrelude** const proxy{ lua_newuserdatauv<DeepPrelude*>(L_, nuv_) }; // L_: DPC proxy |
219 | LUA_ASSERT(L_, proxy); | 207 | LUA_ASSERT(L_, proxy); |
220 | *proxy = prelude_; | 208 | *proxy = prelude_; |
221 | prelude_->m_refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data | 209 | prelude_->m_refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data |
222 | 210 | ||
223 | // Get/create metatable for 'factory' (in this state) | 211 | // Get/create metatable for 'factory' (in this state) |
224 | DeepFactory& factory = prelude_->m_factory; | 212 | DeepFactory& factory = prelude_->m_factory; |
225 | lua_pushlightuserdata(L_, std::bit_cast<void*>(&factory)); // DPC proxy factory | 213 | lua_pushlightuserdata(L_, std::bit_cast<void*>(&factory)); // L_: DPC proxy factory |
226 | get_deep_lookup(L_); // DPC proxy metatable? | 214 | get_deep_lookup(L_); // L_: DPC proxy metatable? |
227 | 215 | ||
228 | if (lua_isnil(L_, -1)) // // No metatable yet. | 216 | if (lua_isnil(L_, -1)) { // No metatable yet. |
229 | { | 217 | lua_pop(L_, 1); // L_: DPC proxy |
230 | lua_pop(L_, 1); // DPC proxy | ||
231 | int const oldtop{ lua_gettop(L_) }; | 218 | int const oldtop{ lua_gettop(L_) }; |
232 | // 1 - make one and register it | 219 | // 1 - make one and register it |
233 | if (mode_ != LookupMode::ToKeeper) | 220 | if (mode_ != LookupMode::ToKeeper) { |
234 | { | 221 | factory.createMetatable(L_); // L_: DPC proxy metatable |
235 | factory.createMetatable(L_); // DPC proxy metatable | 222 | if (lua_gettop(L_) - oldtop != 1 || !lua_istable(L_, -1)) { |
236 | if (lua_gettop(L_) - oldtop != 1 || !lua_istable(L_, -1)) | ||
237 | { | ||
238 | // factory didn't push exactly 1 value, or the value it pushed is not a table: ERROR! | 223 | // factory didn't push exactly 1 value, or the value it pushed is not a table: ERROR! |
239 | lua_settop(L_, oldtop); // DPC proxy X | 224 | lua_settop(L_, oldtop); // L_: DPC proxy X |
240 | lua_pop(L_, 3); // | 225 | lua_pop(L_, 3); // L_: |
241 | return "Bad DeepFactory::createMetatable overload: unexpected pushed value"; | 226 | return "Bad DeepFactory::createMetatable overload: unexpected pushed value"; |
242 | } | 227 | } |
243 | // if the metatable contains a __gc, we will call it from our own | 228 | // if the metatable contains a __gc, we will call it from our own |
244 | lua_getfield(L_, -1, "__gc"); // DPC proxy metatable __gc | 229 | lua_getfield(L_, -1, "__gc"); // L_: DPC proxy metatable __gc |
245 | } | 230 | } else { |
246 | else | ||
247 | { | ||
248 | // keepers need a minimal metatable that only contains our own __gc | 231 | // keepers need a minimal metatable that only contains our own __gc |
249 | lua_newtable(L_); // DPC proxy metatable | 232 | lua_newtable(L_); // L_: DPC proxy metatable |
250 | lua_pushnil(L_); // DPC proxy metatable nil | 233 | lua_pushnil(L_); // L_: DPC proxy metatable nil |
251 | } | 234 | } |
252 | if (lua_isnil(L_, -1)) | 235 | if (lua_isnil(L_, -1)) { |
253 | { | ||
254 | // Add our own '__gc' method | 236 | // Add our own '__gc' method |
255 | lua_pop(L_, 1); // DPC proxy metatable | 237 | lua_pop(L_, 1); // L_: DPC proxy metatable |
256 | lua_pushcfunction(L_, deep_userdata_gc); // DPC proxy metatable deep_userdata_gc | 238 | lua_pushcfunction(L_, deep_userdata_gc); // L_: DPC proxy metatable deep_userdata_gc |
257 | } | 239 | } else { |
258 | else | ||
259 | { | ||
260 | // Add our own '__gc' method wrapping the original | 240 | // Add our own '__gc' method wrapping the original |
261 | lua_pushcclosure(L_, deep_userdata_gc, 1); // DPC proxy metatable deep_userdata_gc | 241 | lua_pushcclosure(L_, deep_userdata_gc, 1); // DPC proxy metatable deep_userdata_gc |
262 | } | 242 | } |
263 | lua_setfield(L_, -2, "__gc"); // DPC proxy metatable | 243 | lua_setfield(L_, -2, "__gc"); // DPC proxy metatable |
264 | 244 | ||
265 | // Memorize for later rounds | 245 | // Memorize for later rounds |
266 | lua_pushvalue(L_, -1); // DPC proxy metatable metatable | 246 | lua_pushvalue(L_, -1); // L_: DPC proxy metatable metatable |
267 | lua_pushlightuserdata(L_, std::bit_cast<void*>(&factory)); // DPC proxy metatable metatable factory | 247 | lua_pushlightuserdata(L_, std::bit_cast<void*>(&factory)); // L_: DPC proxy metatable metatable factory |
268 | set_deep_lookup(L_); // DPC proxy metatable | 248 | set_deep_lookup(L_); // L_: DPC proxy metatable |
269 | 249 | ||
270 | // 2 - cause the target state to require the module that exported the factory | 250 | // 2 - cause the target state to require the module that exported the factory |
271 | if (char const* const modname{ factory.moduleName() }; modname) // we actually got a module name | 251 | if (char const* const modname{ factory.moduleName() }; modname) { // we actually got a module name |
272 | { | ||
273 | // L.registry._LOADED exists without having registered the 'package' library. | 252 | // L.registry._LOADED exists without having registered the 'package' library. |
274 | lua_getglobal(L_, "require"); // DPC proxy metatable require() | 253 | lua_getglobal(L_, "require"); // DPC proxy metatable require() |
275 | // check that the module is already loaded (or being loaded, we are happy either way) | 254 | // check that the module is already loaded (or being loaded, we are happy either way) |
276 | if (lua_isfunction(L_, -1)) | 255 | if (lua_isfunction(L_, -1)) { |
277 | { | 256 | lua_pushstring(L_, modname); // L_: DPC proxy metatable require() "module" |
278 | lua_pushstring(L_, modname); // DPC proxy metatable require() "module" | 257 | lua_getfield(L_, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); // L_: DPC proxy metatable require() "module" _R._LOADED |
279 | lua_getfield(L_, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); // DPC proxy metatable require() "module" _R._LOADED | 258 | if (lua_istable(L_, -1)) { |
280 | if (lua_istable(L_, -1)) | 259 | lua_pushvalue(L_, -2); // L_: DPC proxy metatable require() "module" _R._LOADED "module" |
281 | { | 260 | lua_rawget(L_, -2); // L_: DPC proxy metatable require() "module" _R._LOADED module |
282 | lua_pushvalue(L_, -2); // DPC proxy metatable require() "module" _R._LOADED "module" | ||
283 | lua_rawget(L_, -2); // DPC proxy metatable require() "module" _R._LOADED module | ||
284 | int const alreadyloaded = lua_toboolean(L_, -1); | 261 | int const alreadyloaded = lua_toboolean(L_, -1); |
285 | if (!alreadyloaded) // not loaded | 262 | if (!alreadyloaded) { // not loaded |
286 | { | ||
287 | int require_result; | 263 | int require_result; |
288 | lua_pop(L_, 2); // DPC proxy metatable require() "module" | 264 | lua_pop(L_, 2); // L_: DPC proxy metatable require() "module" |
289 | // require "modname" | 265 | // require "modname" |
290 | require_result = lua_pcall(L_, 1, 0, 0); // DPC proxy metatable error? | 266 | require_result = lua_pcall(L_, 1, 0, 0); // L_: DPC proxy metatable error? |
291 | if (require_result != LUA_OK) | 267 | if (require_result != LUA_OK) { |
292 | { | ||
293 | // failed, return the error message | 268 | // failed, return the error message |
294 | lua_pushfstring(L_, "error while requiring '%s' identified by DeepFactory::moduleName: ", modname); | 269 | lua_pushfstring(L_, "error while requiring '%s' identified by DeepFactory::moduleName: ", modname); |
295 | lua_insert(L_, -2); // DPC proxy metatable prefix error | 270 | lua_insert(L_, -2); // L_: DPC proxy metatable prefix error |
296 | lua_concat(L_, 2); // DPC proxy metatable error | 271 | lua_concat(L_, 2); // L_: DPC proxy metatable error |
297 | return lua_tostring(L_, -1); | 272 | return lua_tostring(L_, -1); |
298 | } | 273 | } |
274 | } else { // already loaded, we are happy | ||
275 | lua_pop(L_, 4); // L_: DPC proxy metatable | ||
299 | } | 276 | } |
300 | else // already loaded, we are happy | 277 | } else { // no L.registry._LOADED; can this ever happen? |
301 | { | 278 | lua_pop(L_, 6); // L_: |
302 | lua_pop(L_, 4); // DPC proxy metatable | ||
303 | } | ||
304 | } | ||
305 | else // no L.registry._LOADED; can this ever happen? | ||
306 | { | ||
307 | lua_pop(L_, 6); // | ||
308 | return "unexpected error while requiring a module identified by DeepFactory::moduleName"; | 279 | return "unexpected error while requiring a module identified by DeepFactory::moduleName"; |
309 | } | 280 | } |
310 | } | 281 | } else { // a module name, but no require() function :-( |
311 | else // a module name, but no require() function :-( | 282 | lua_pop(L_, 4); // L_: |
312 | { | ||
313 | lua_pop(L_, 4); // | ||
314 | return "lanes receiving deep userdata should register the 'package' library"; | 283 | return "lanes receiving deep userdata should register the 'package' library"; |
315 | } | 284 | } |
316 | } | 285 | } |
317 | } | 286 | } |
318 | STACK_CHECK(L_, 2); // DPC proxy metatable | 287 | STACK_CHECK(L_, 2); // DPC proxy metatable |
319 | LUA_ASSERT(L_, lua_type_as_enum(L_, -2) == LuaType::USERDATA); | 288 | LUA_ASSERT(L_, lua_type_as_enum(L_, -2) == LuaType::USERDATA); |
320 | LUA_ASSERT(L_, lua_istable(L_, -1)); | 289 | LUA_ASSERT(L_, lua_istable(L_, -1)); |
321 | lua_setmetatable(L_, -2); // DPC proxy | 290 | lua_setmetatable(L_, -2); // DPC proxy |
322 | 291 | ||
323 | // If we're here, we obviously had to create a new proxy, so cache it. | 292 | // If we're here, we obviously had to create a new proxy, so cache it. |
324 | lua_pushlightuserdata(L_, prelude_); // DPC proxy deep | 293 | lua_pushlightuserdata(L_, prelude_); // L_: DPC proxy deep |
325 | lua_pushvalue(L_, -2); // DPC proxy deep proxy | 294 | lua_pushvalue(L_, -2); // L_: DPC proxy deep proxy |
326 | lua_rawset(L_, -4); // DPC proxy | 295 | lua_rawset(L_, -4); // L_: DPC proxy |
327 | lua_remove(L_, -2); // proxy | 296 | lua_remove(L_, -2); // L_: proxy |
328 | LUA_ASSERT(L_, lua_type_as_enum(L_, -1) == LuaType::USERDATA); | 297 | LUA_ASSERT(L_, lua_type_as_enum(L_, -1) == LuaType::USERDATA); |
329 | STACK_CHECK(L_, 0); | 298 | STACK_CHECK(L_, 0); |
330 | return nullptr; | 299 | return nullptr; |
@@ -333,33 +302,31 @@ char const* DeepFactory::PushDeepProxy(DestState L_, DeepPrelude* prelude_, int | |||
333 | // ################################################################################################# | 302 | // ################################################################################################# |
334 | 303 | ||
335 | /* | 304 | /* |
336 | * Create a deep userdata | 305 | * Create a deep userdata |
337 | * | 306 | * |
338 | * proxy_ud= deep_userdata( [...] ) | 307 | * proxy_ud= deep_userdata( [...] ) |
339 | * | 308 | * |
340 | * Creates a deep userdata entry of the type defined by the factory. | 309 | * Creates a deep userdata entry of the type defined by the factory. |
341 | * Parameters found on the stack are left as is and passed on to DeepFactory::newDeepObjectInternal. | 310 | * Parameters found on the stack are left as is and passed on to DeepFactory::newDeepObjectInternal. |
342 | * | 311 | * |
343 | * Reference counting and true userdata proxying are taken care of for the actual data type. | 312 | * Reference counting and true userdata proxying are taken care of for the actual data type. |
344 | * | 313 | * |
345 | * Types using the deep userdata system (and only those!) can be passed between | 314 | * Types using the deep userdata system (and only those!) can be passed between |
346 | * separate Lua states via 'luaG_inter_move()'. | 315 | * separate Lua states via 'luaG_inter_move()'. |
347 | * | 316 | * |
348 | * Returns: 'proxy' userdata for accessing the deep data via 'DeepFactory::toDeep()' | 317 | * Returns: 'proxy' userdata for accessing the deep data via 'DeepFactory::toDeep()' |
349 | */ | 318 | */ |
350 | int DeepFactory::pushDeepUserdata(DestState L_, int nuv_) const | 319 | int DeepFactory::pushDeepUserdata(DestState L_, int nuv_) const |
351 | { | 320 | { |
352 | STACK_GROW(L_, 1); | 321 | STACK_GROW(L_, 1); |
353 | STACK_CHECK_START_REL(L_, 0); | 322 | STACK_CHECK_START_REL(L_, 0); |
354 | int const oldtop{ lua_gettop(L_) }; | 323 | int const oldtop{ lua_gettop(L_) }; |
355 | DeepPrelude* const prelude{ newDeepObjectInternal(L_) }; | 324 | DeepPrelude* const prelude{ newDeepObjectInternal(L_) }; |
356 | if (prelude == nullptr) | 325 | if (prelude == nullptr) { |
357 | { | ||
358 | raise_luaL_error(L_, "DeepFactory::newDeepObjectInternal failed to create deep userdata (out of memory)"); | 326 | raise_luaL_error(L_, "DeepFactory::newDeepObjectInternal failed to create deep userdata (out of memory)"); |
359 | } | 327 | } |
360 | 328 | ||
361 | if (prelude->m_magic != kDeepVersion) | 329 | if (prelude->m_magic != kDeepVersion) { |
362 | { | ||
363 | // just in case, don't leak the newly allocated deep userdata object | 330 | // just in case, don't leak the newly allocated deep userdata object |
364 | deleteDeepObjectInternal(L_, prelude); | 331 | deleteDeepObjectInternal(L_, prelude); |
365 | raise_luaL_error(L_, "Bad Deep Factory: kDeepVersion is incorrect, rebuild your implementation with the latest deep implementation"); | 332 | raise_luaL_error(L_, "Bad Deep Factory: kDeepVersion is incorrect, rebuild your implementation with the latest deep implementation"); |
@@ -368,16 +335,14 @@ int DeepFactory::pushDeepUserdata(DestState L_, int nuv_) const | |||
368 | LUA_ASSERT(L_, prelude->m_refcount.load(std::memory_order_relaxed) == 0); // 'DeepFactory::PushDeepProxy' will lift it to 1 | 335 | LUA_ASSERT(L_, prelude->m_refcount.load(std::memory_order_relaxed) == 0); // 'DeepFactory::PushDeepProxy' will lift it to 1 |
369 | LUA_ASSERT(L_, &prelude->m_factory == this); | 336 | LUA_ASSERT(L_, &prelude->m_factory == this); |
370 | 337 | ||
371 | if (lua_gettop(L_) - oldtop != 0) | 338 | if (lua_gettop(L_) - oldtop != 0) { |
372 | { | ||
373 | // just in case, don't leak the newly allocated deep userdata object | 339 | // just in case, don't leak the newly allocated deep userdata object |
374 | deleteDeepObjectInternal(L_, prelude); | 340 | deleteDeepObjectInternal(L_, prelude); |
375 | raise_luaL_error(L_, "Bad DeepFactory::newDeepObjectInternal overload: should not push anything on the stack"); | 341 | raise_luaL_error(L_, "Bad DeepFactory::newDeepObjectInternal overload: should not push anything on the stack"); |
376 | } | 342 | } |
377 | 343 | ||
378 | char const* const errmsg{ DeepFactory::PushDeepProxy(L_, prelude, nuv_, LookupMode::LaneBody) }; // proxy | 344 | char const* const errmsg{ DeepFactory::PushDeepProxy(L_, prelude, nuv_, LookupMode::LaneBody) }; // proxy |
379 | if (errmsg != nullptr) | 345 | if (errmsg != nullptr) { |
380 | { | ||
381 | raise_luaL_error(L_, errmsg); | 346 | raise_luaL_error(L_, errmsg); |
382 | } | 347 | } |
383 | STACK_CHECK(L_, 1); | 348 | STACK_CHECK(L_, 1); |
@@ -387,17 +352,16 @@ int DeepFactory::pushDeepUserdata(DestState L_, int nuv_) const | |||
387 | // ################################################################################################# | 352 | // ################################################################################################# |
388 | 353 | ||
389 | /* | 354 | /* |
390 | * Access deep userdata through a proxy. | 355 | * Access deep userdata through a proxy. |
391 | * | 356 | * |
392 | * Reference count is not changed, and access to the deep userdata is not | 357 | * Reference count is not changed, and access to the deep userdata is not |
393 | * serialized. It is the module's responsibility to prevent conflicting usage. | 358 | * serialized. It is the module's responsibility to prevent conflicting usage. |
394 | */ | 359 | */ |
395 | DeepPrelude* DeepFactory::toDeep(lua_State* L_, int index_) const | 360 | DeepPrelude* DeepFactory::toDeep(lua_State* L_, int index_) const |
396 | { | 361 | { |
397 | STACK_CHECK_START_REL(L_, 0); | 362 | STACK_CHECK_START_REL(L_, 0); |
398 | // ensure it is actually a deep userdata we created | 363 | // ensure it is actually a deep userdata we created |
399 | if (get_factory(L_, index_, LookupMode::LaneBody) != this) | 364 | if (get_factory(L_, index_, LookupMode::LaneBody) != this) { |
400 | { | ||
401 | return nullptr; // no metatable, or wrong kind | 365 | return nullptr; // no metatable, or wrong kind |
402 | } | 366 | } |
403 | STACK_CHECK(L_, 0); | 367 | STACK_CHECK(L_, 0); |
@@ -415,12 +379,11 @@ DeepPrelude* DeepFactory::toDeep(lua_State* L_, int index_) const | |||
415 | * the id function of the copied value, or nullptr for non-deep userdata | 379 | * the id function of the copied value, or nullptr for non-deep userdata |
416 | * (not copied) | 380 | * (not copied) |
417 | */ | 381 | */ |
418 | [[nodiscard]] bool InterCopyContext::copydeep() const | 382 | [[nodiscard]] bool InterCopyContext::copyDeep() const |
419 | { | 383 | { |
420 | DeepFactory* const factory { get_factory(L1, L1_i, mode) }; | 384 | DeepFactory* const factory{ get_factory(L1, L1_i, mode) }; |
421 | if (factory == nullptr) | 385 | if (factory == nullptr) { |
422 | { | 386 | return false; // not a deep userdata |
423 | return false; // not a deep userdata | ||
424 | } | 387 | } |
425 | 388 | ||
426 | STACK_CHECK_START_REL(L1, 0); | 389 | STACK_CHECK_START_REL(L1, 0); |
@@ -428,39 +391,36 @@ DeepPrelude* DeepFactory::toDeep(lua_State* L_, int index_) const | |||
428 | 391 | ||
429 | // extract all uservalues of the source | 392 | // extract all uservalues of the source |
430 | int nuv = 0; | 393 | int nuv = 0; |
431 | while (lua_getiuservalue(L1, L1_i, nuv + 1) != LUA_TNONE) // ... u [uv]* nil | 394 | while (lua_getiuservalue(L1, L1_i, nuv + 1) != LUA_TNONE) { // L1: ... u [uv]* nil |
432 | { | 395 | ++nuv; |
433 | ++ nuv; | ||
434 | } | 396 | } |
435 | // last call returned TNONE and pushed nil, that we don't need | 397 | // last call returned TNONE and pushed nil, that we don't need |
436 | lua_pop(L1, 1); // ... u [uv]* | 398 | lua_pop(L1, 1); // L1: ... u [uv]* |
437 | STACK_CHECK(L1, nuv); | 399 | STACK_CHECK(L1, nuv); |
438 | 400 | ||
439 | char const* errmsg{ DeepFactory::PushDeepProxy(L2, *lua_tofulluserdata<DeepPrelude*>(L1, L1_i), nuv, mode) }; // u | 401 | DeepPrelude* const u{ *lua_tofulluserdata<DeepPrelude*>(L1, L1_i) }; |
402 | char const* errmsg{ DeepFactory::PushDeepProxy(L2, u, nuv, mode) }; // L2: u | ||
440 | 403 | ||
441 | // transfer all uservalues of the source in the destination | 404 | // transfer all uservalues of the source in the destination |
442 | { | 405 | { |
443 | InterCopyContext c{ U, L2, L1, L2_cache_i, {}, VT::NORMAL, mode, name }; | 406 | InterCopyContext c{ U, L2, L1, L2_cache_i, {}, VT::NORMAL, mode, name }; |
444 | int const clone_i{ lua_gettop(L2) }; | 407 | int const clone_i{ lua_gettop(L2) }; |
445 | while (nuv) | 408 | while (nuv) { |
446 | { | ||
447 | c.L1_i = SourceIndex{ lua_absindex(L1, -1) }; | 409 | c.L1_i = SourceIndex{ lua_absindex(L1, -1) }; |
448 | if (!c.inter_copy_one()) // u uv | 410 | if (!c.inter_copy_one()) { // L2: u uv |
449 | { | ||
450 | raise_luaL_error(L1, "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); | 411 | raise_luaL_error(L1, "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); |
451 | } | 412 | } |
452 | lua_pop(L1, 1); // ... u [uv]* | 413 | lua_pop(L1, 1); // L1: ... u [uv]* |
453 | // this pops the value from the stack | 414 | // this pops the value from the stack |
454 | lua_setiuservalue(L2, clone_i, nuv); // u | 415 | lua_setiuservalue(L2, clone_i, nuv); // L2: u |
455 | -- nuv; | 416 | --nuv; |
456 | } | 417 | } |
457 | } | 418 | } |
458 | 419 | ||
459 | STACK_CHECK(L2, 1); | 420 | STACK_CHECK(L2, 1); |
460 | STACK_CHECK(L1, 0); | 421 | STACK_CHECK(L1, 0); |
461 | 422 | ||
462 | if (errmsg != nullptr) | 423 | if (errmsg != nullptr) { |
463 | { | ||
464 | // raise the error in the proper state (not the keeper) | 424 | // raise the error in the proper state (not the keeper) |
465 | lua_State* const errL{ (mode == LookupMode::FromKeeper) ? L2 : L1 }; | 425 | lua_State* const errL{ (mode == LookupMode::FromKeeper) ? L2 : L1 }; |
466 | raise_luaL_error(errL, errmsg); | 426 | raise_luaL_error(errL, errmsg); |