aboutsummaryrefslogtreecommitdiff
path: root/src/deep.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/deep.cpp')
-rw-r--r--src/deep.cpp330
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
57static constexpr RegistryUniqueKey kDeepLookupRegKey{ 0xC6788345703C6059ull }; 57static 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 */
63static constexpr RegistryUniqueKey kDeepProxyCacheRegKey{ 0xEBCD49AE1A3DD35Eull }; 63static 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 */
69static void set_deep_lookup(lua_State* L_) 69static 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 */
90static void get_deep_lookup(lua_State* L_) 90static 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_)
198char const* DeepFactory::PushDeepProxy(DestState L_, DeepPrelude* prelude_, int nuv_, LookupMode mode_) 189char 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 */
350int DeepFactory::pushDeepUserdata(DestState L_, int nuv_) const 319int 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 */
395DeepPrelude* DeepFactory::toDeep(lua_State* L_, int index_) const 360DeepPrelude* 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);