diff options
Diffstat (limited to 'src/deep.cpp')
-rw-r--r-- | src/deep.cpp | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/src/deep.cpp b/src/deep.cpp new file mode 100644 index 0000000..58da457 --- /dev/null +++ b/src/deep.cpp | |||
@@ -0,0 +1,501 @@ | |||
1 | /* | ||
2 | * DEEP.C Copyright (c) 2017, Benoit Germain | ||
3 | * | ||
4 | * Deep userdata support, separate in its own source file to help integration | ||
5 | * without enforcing a Lanes dependency | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | =============================================================================== | ||
10 | |||
11 | Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com> | ||
12 | 2011-17 Benoit Germain <bnt.germain@gmail.com> | ||
13 | |||
14 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
15 | of this software and associated documentation files (the "Software"), to deal | ||
16 | in the Software without restriction, including without limitation the rights | ||
17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
18 | copies of the Software, and to permit persons to whom the Software is | ||
19 | furnished to do so, subject to the following conditions: | ||
20 | |||
21 | The above copyright notice and this permission notice shall be included in | ||
22 | all copies or substantial portions of the Software. | ||
23 | |||
24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
30 | THE SOFTWARE. | ||
31 | |||
32 | =============================================================================== | ||
33 | */ | ||
34 | |||
35 | #include <stdio.h> | ||
36 | #include <assert.h> | ||
37 | #include <string.h> | ||
38 | #include <ctype.h> | ||
39 | #include <stdlib.h> | ||
40 | #if !defined(__APPLE__) | ||
41 | #include <malloc.h> | ||
42 | #endif | ||
43 | |||
44 | #include "compat.h" | ||
45 | #include "deep.h" | ||
46 | #include "tools.h" | ||
47 | #include "universe.h" | ||
48 | #include "uniquekey.h" | ||
49 | |||
50 | /*-- Metatable copying --*/ | ||
51 | |||
52 | /*---=== Deep userdata ===---*/ | ||
53 | |||
54 | /* | ||
55 | * 'registry[REGKEY]' is a two-way lookup table for 'idfunc's and those type's | ||
56 | * metatables: | ||
57 | * | ||
58 | * metatable -> idfunc | ||
59 | * idfunc -> metatable | ||
60 | */ | ||
61 | // crc64/we of string "DEEP_LOOKUP_KEY" generated at http://www.nitrxgen.net/hashgen/ | ||
62 | static DECLARE_CONST_UNIQUE_KEY( DEEP_LOOKUP_KEY, 0x9fb9b4f3f633d83d); | ||
63 | |||
64 | /* | ||
65 | * The deep proxy cache is a weak valued table listing all deep UD proxies indexed by the deep UD that they are proxying | ||
66 | * crc64/we of string "DEEP_PROXY_CACHE_KEY" generated at http://www.nitrxgen.net/hashgen/ | ||
67 | */ | ||
68 | static DECLARE_CONST_UNIQUE_KEY( DEEP_PROXY_CACHE_KEY, 0x05773d6fc26be106); | ||
69 | |||
70 | /* | ||
71 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. | ||
72 | * Pops the both values off the stack. | ||
73 | */ | ||
74 | static void set_deep_lookup( lua_State* L) | ||
75 | { | ||
76 | STACK_GROW( L, 3); | ||
77 | STACK_CHECK( L, 2); // a b | ||
78 | push_registry_subtable( L, DEEP_LOOKUP_KEY); // a b {} | ||
79 | STACK_MID( L, 3); | ||
80 | lua_insert( L, -3); // {} a b | ||
81 | lua_pushvalue( L, -1); // {} a b b | ||
82 | lua_pushvalue( L,-3); // {} a b b a | ||
83 | lua_rawset( L, -5); // {} a b | ||
84 | lua_rawset( L, -3); // {} | ||
85 | lua_pop( L, 1); // | ||
86 | STACK_END( L, 0); | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * Pops the key (metatable or idfunc) off the stack, and replaces with the | ||
91 | * deep lookup value (idfunc/metatable/nil). | ||
92 | */ | ||
93 | static void get_deep_lookup( lua_State* L) | ||
94 | { | ||
95 | STACK_GROW( L, 1); | ||
96 | STACK_CHECK( L, 1); // a | ||
97 | REGISTRY_GET( L, DEEP_LOOKUP_KEY); // a {} | ||
98 | if( !lua_isnil( L, -1)) | ||
99 | { | ||
100 | lua_insert( L, -2); // {} a | ||
101 | lua_rawget( L, -2); // {} b | ||
102 | } | ||
103 | lua_remove( L, -2); // a|b | ||
104 | STACK_END( L, 1); | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * Return the registered ID function for 'index' (deep userdata proxy), | ||
109 | * or NULL if 'index' is not a deep userdata proxy. | ||
110 | */ | ||
111 | static inline luaG_IdFunction get_idfunc( lua_State* L, int index, LookupMode mode_) | ||
112 | { | ||
113 | // when looking inside a keeper, we are 100% sure the object is a deep userdata | ||
114 | if( mode_ == eLM_FromKeeper) | ||
115 | { | ||
116 | DeepPrelude** proxy = (DeepPrelude**) lua_touserdata( L, index); | ||
117 | // we can (and must) cast and fetch the internally stored idfunc | ||
118 | return (*proxy)->idfunc; | ||
119 | } | ||
120 | else | ||
121 | { | ||
122 | // essentially we are making sure that the metatable of the object we want to copy is stored in our metatable/idfunc database | ||
123 | // it is the only way to ensure that the userdata is indeed a deep userdata! | ||
124 | // of course, we could just trust the caller, but we won't | ||
125 | luaG_IdFunction ret; | ||
126 | STACK_GROW( L, 1); | ||
127 | STACK_CHECK( L, 0); | ||
128 | |||
129 | if( !lua_getmetatable( L, index)) // deep ... metatable? | ||
130 | { | ||
131 | return NULL; // no metatable: can't be a deep userdata object! | ||
132 | } | ||
133 | |||
134 | // replace metatable with the idfunc pointer, if it is actually a deep userdata | ||
135 | get_deep_lookup( L); // deep ... idfunc|nil | ||
136 | |||
137 | ret = (luaG_IdFunction) lua_touserdata( L, -1); // NULL if not a userdata | ||
138 | lua_pop( L, 1); | ||
139 | STACK_END( L, 0); | ||
140 | return ret; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | |||
145 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_) | ||
146 | { | ||
147 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup | ||
148 | lua_pushlightuserdata( L, prelude_); | ||
149 | ASSERT_L( prelude_->idfunc); | ||
150 | prelude_->idfunc( L, eDO_delete); | ||
151 | } | ||
152 | |||
153 | |||
154 | /* | ||
155 | * void= mt.__gc( proxy_ud ) | ||
156 | * | ||
157 | * End of life for a proxy object; reduce the deep reference count and clean it up if reaches 0. | ||
158 | * | ||
159 | */ | ||
160 | static int deep_userdata_gc( lua_State* L) | ||
161 | { | ||
162 | DeepPrelude** proxy = (DeepPrelude**) lua_touserdata( L, 1); | ||
163 | DeepPrelude* p = *proxy; | ||
164 | Universe* U = universe_get( L); | ||
165 | int v; | ||
166 | |||
167 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded | ||
168 | // in that case, we are not multithreaded and locking isn't necessary anyway | ||
169 | if( U) MUTEX_LOCK( &U->deep_lock); | ||
170 | v = -- (p->refcount); | ||
171 | if (U) MUTEX_UNLOCK( &U->deep_lock); | ||
172 | |||
173 | if( v == 0) | ||
174 | { | ||
175 | // retrieve wrapped __gc | ||
176 | lua_pushvalue( L, lua_upvalueindex( 1)); // self __gc? | ||
177 | if( !lua_isnil( L, -1)) | ||
178 | { | ||
179 | lua_insert( L, -2); // __gc self | ||
180 | lua_call( L, 1, 0); // | ||
181 | } | ||
182 | // 'idfunc' expects a clean stack to work on | ||
183 | lua_settop( L, 0); | ||
184 | free_deep_prelude( L, p); | ||
185 | |||
186 | // top was set to 0, then userdata was pushed. "delete" might want to pop the userdata (we don't care), but should not push anything! | ||
187 | if ( lua_gettop( L) > 1) | ||
188 | { | ||
189 | luaL_error( L, "Bad idfunc(eDO_delete): should not push anything"); | ||
190 | } | ||
191 | } | ||
192 | *proxy = NULL; // make sure we don't use it any more, just in case | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | |||
197 | /* | ||
198 | * Push a proxy userdata on the stack. | ||
199 | * returns NULL if ok, else some error string related to bad idfunc behavior or module require problem | ||
200 | * (error cannot happen with mode_ == eLM_ToKeeper) | ||
201 | * | ||
202 | * Initializes necessary structures if it's the first time 'idfunc' is being | ||
203 | * used in this Lua state (metatable, registring it). Otherwise, increments the | ||
204 | * reference count. | ||
205 | */ | ||
206 | char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_) | ||
207 | { | ||
208 | DeepPrelude** proxy; | ||
209 | |||
210 | // Check if a proxy already exists | ||
211 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC | ||
212 | lua_pushlightuserdata( L, prelude); // DPC deep | ||
213 | lua_rawget( L, -2); // DPC proxy | ||
214 | if ( !lua_isnil( L, -1)) | ||
215 | { | ||
216 | lua_remove( L, -2); // proxy | ||
217 | return NULL; | ||
218 | } | ||
219 | else | ||
220 | { | ||
221 | lua_pop( L, 1); // DPC | ||
222 | } | ||
223 | |||
224 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded | ||
225 | // in that case, we are not multithreaded and locking isn't necessary anyway | ||
226 | if( U) MUTEX_LOCK( &U->deep_lock); | ||
227 | ++ (prelude->refcount); // one more proxy pointing to this deep data | ||
228 | if( U) MUTEX_UNLOCK( &U->deep_lock); | ||
229 | |||
230 | STACK_GROW( L, 7); | ||
231 | STACK_CHECK( L, 0); | ||
232 | |||
233 | // a new full userdata, fitted with the specified number of uservalue slots (always 1 for Lua < 5.4) | ||
234 | proxy = (DeepPrelude**) lua_newuserdatauv( L, sizeof(DeepPrelude*), nuv_); // DPC proxy | ||
235 | ASSERT_L( proxy); | ||
236 | *proxy = prelude; | ||
237 | |||
238 | // Get/create metatable for 'idfunc' (in this state) | ||
239 | lua_pushlightuserdata( L, (void*)(ptrdiff_t)(prelude->idfunc)); // DPC proxy idfunc | ||
240 | get_deep_lookup( L); // DPC proxy metatable? | ||
241 | |||
242 | if( lua_isnil( L, -1)) // // No metatable yet. | ||
243 | { | ||
244 | char const* modname; | ||
245 | int oldtop = lua_gettop( L); // DPC proxy nil | ||
246 | lua_pop( L, 1); // DPC proxy | ||
247 | // 1 - make one and register it | ||
248 | if( mode_ != eLM_ToKeeper) | ||
249 | { | ||
250 | (void) prelude->idfunc( L, eDO_metatable); // DPC proxy metatable | ||
251 | if( lua_gettop( L) - oldtop != 0 || !lua_istable( L, -1)) | ||
252 | { | ||
253 | lua_settop( L, oldtop); // DPC proxy X | ||
254 | lua_pop( L, 3); // | ||
255 | return "Bad idfunc(eOP_metatable): unexpected pushed value"; | ||
256 | } | ||
257 | // if the metatable contains a __gc, we will call it from our own | ||
258 | lua_getfield( L, -1, "__gc"); // DPC proxy metatable __gc | ||
259 | } | ||
260 | else | ||
261 | { | ||
262 | // keepers need a minimal metatable that only contains our own __gc | ||
263 | lua_newtable( L); // DPC proxy metatable | ||
264 | lua_pushnil( L); // DPC proxy metatable nil | ||
265 | } | ||
266 | if( lua_isnil( L, -1)) | ||
267 | { | ||
268 | // Add our own '__gc' method | ||
269 | lua_pop( L, 1); // DPC proxy metatable | ||
270 | lua_pushcfunction( L, deep_userdata_gc); // DPC proxy metatable deep_userdata_gc | ||
271 | } | ||
272 | else | ||
273 | { | ||
274 | // Add our own '__gc' method wrapping the original | ||
275 | lua_pushcclosure( L, deep_userdata_gc, 1); // DPC proxy metatable deep_userdata_gc | ||
276 | } | ||
277 | lua_setfield( L, -2, "__gc"); // DPC proxy metatable | ||
278 | |||
279 | // Memorize for later rounds | ||
280 | lua_pushvalue( L, -1); // DPC proxy metatable metatable | ||
281 | lua_pushlightuserdata( L, (void*)(ptrdiff_t)(prelude->idfunc)); // DPC proxy metatable metatable idfunc | ||
282 | set_deep_lookup( L); // DPC proxy metatable | ||
283 | |||
284 | // 2 - cause the target state to require the module that exported the idfunc | ||
285 | // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc | ||
286 | { | ||
287 | int oldtop_module = lua_gettop( L); | ||
288 | modname = (char const*) prelude->idfunc( L, eDO_module); // DPC proxy metatable | ||
289 | // make sure the function pushed nothing on the stack! | ||
290 | if( lua_gettop( L) - oldtop_module != 0) | ||
291 | { | ||
292 | lua_pop( L, 3); // | ||
293 | return "Bad idfunc(eOP_module): should not push anything"; | ||
294 | } | ||
295 | } | ||
296 | if( NULL != modname) // we actually got a module name | ||
297 | { | ||
298 | // L.registry._LOADED exists without having registered the 'package' library. | ||
299 | lua_getglobal( L, "require"); // DPC proxy metatable require() | ||
300 | // check that the module is already loaded (or being loaded, we are happy either way) | ||
301 | if( lua_isfunction( L, -1)) | ||
302 | { | ||
303 | lua_pushstring( L, modname); // DPC proxy metatable require() "module" | ||
304 | lua_getfield( L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); // DPC proxy metatable require() "module" _R._LOADED | ||
305 | if( lua_istable( L, -1)) | ||
306 | { | ||
307 | bool_t alreadyloaded; | ||
308 | lua_pushvalue( L, -2); // DPC proxy metatable require() "module" _R._LOADED "module" | ||
309 | lua_rawget( L, -2); // DPC proxy metatable require() "module" _R._LOADED module | ||
310 | alreadyloaded = lua_toboolean( L, -1); | ||
311 | if( !alreadyloaded) // not loaded | ||
312 | { | ||
313 | int require_result; | ||
314 | lua_pop( L, 2); // DPC proxy metatable require() "module" | ||
315 | // require "modname" | ||
316 | require_result = lua_pcall( L, 1, 0, 0); // DPC proxy metatable error? | ||
317 | if( require_result != LUA_OK) | ||
318 | { | ||
319 | // failed, return the error message | ||
320 | lua_pushfstring( L, "error while requiring '%s' identified by idfunc(eOP_module): ", modname); | ||
321 | lua_insert( L, -2); // DPC proxy metatable prefix error | ||
322 | lua_concat( L, 2); // DPC proxy metatable error | ||
323 | return lua_tostring( L, -1); | ||
324 | } | ||
325 | } | ||
326 | else // already loaded, we are happy | ||
327 | { | ||
328 | lua_pop( L, 4); // DPC proxy metatable | ||
329 | } | ||
330 | } | ||
331 | else // no L.registry._LOADED; can this ever happen? | ||
332 | { | ||
333 | lua_pop( L, 6); // | ||
334 | return "unexpected error while requiring a module identified by idfunc(eOP_module)"; | ||
335 | } | ||
336 | } | ||
337 | else // a module name, but no require() function :-( | ||
338 | { | ||
339 | lua_pop( L, 4); // | ||
340 | return "lanes receiving deep userdata should register the 'package' library"; | ||
341 | } | ||
342 | } | ||
343 | } | ||
344 | STACK_MID( L, 2); // DPC proxy metatable | ||
345 | ASSERT_L( lua_isuserdata( L, -2)); | ||
346 | ASSERT_L( lua_istable( L, -1)); | ||
347 | lua_setmetatable( L, -2); // DPC proxy | ||
348 | |||
349 | // If we're here, we obviously had to create a new proxy, so cache it. | ||
350 | lua_pushlightuserdata( L, prelude); // DPC proxy deep | ||
351 | lua_pushvalue( L, -2); // DPC proxy deep proxy | ||
352 | lua_rawset( L, -4); // DPC proxy | ||
353 | lua_remove( L, -2); // proxy | ||
354 | ASSERT_L( lua_isuserdata( L, -1)); | ||
355 | STACK_END( L, 0); | ||
356 | return NULL; | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * Create a deep userdata | ||
361 | * | ||
362 | * proxy_ud= deep_userdata( idfunc [, ...] ) | ||
363 | * | ||
364 | * Creates a deep userdata entry of the type defined by 'idfunc'. | ||
365 | * Parameters found on the stack are left as is passed on to the 'idfunc' "new" invocation. | ||
366 | * | ||
367 | * 'idfunc' must fulfill the following features: | ||
368 | * | ||
369 | * lightuserdata = idfunc( eDO_new [, ...] ) -- creates a new deep data instance | ||
370 | * void = idfunc( eDO_delete, lightuserdata ) -- releases a deep data instance | ||
371 | * tbl = idfunc( eDO_metatable ) -- gives metatable for userdata proxies | ||
372 | * | ||
373 | * Reference counting and true userdata proxying are taken care of for the | ||
374 | * actual data type. | ||
375 | * | ||
376 | * Types using the deep userdata system (and only those!) can be passed between | ||
377 | * separate Lua states via 'luaG_inter_move()'. | ||
378 | * | ||
379 | * Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' | ||
380 | */ | ||
381 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc, int nuv_) | ||
382 | { | ||
383 | char const* errmsg; | ||
384 | |||
385 | STACK_GROW( L, 1); | ||
386 | STACK_CHECK( L, 0); | ||
387 | { | ||
388 | int const oldtop = lua_gettop( L); | ||
389 | DeepPrelude* prelude = (DeepPrelude*) idfunc( L, eDO_new); | ||
390 | if( prelude == NULL) | ||
391 | { | ||
392 | return luaL_error( L, "idfunc(eDO_new) failed to create deep userdata (out of memory)"); | ||
393 | } | ||
394 | if( prelude->magic.value != DEEP_VERSION.value) | ||
395 | { | ||
396 | // just in case, don't leak the newly allocated deep userdata object | ||
397 | lua_pushlightuserdata( L, prelude); | ||
398 | idfunc( L, eDO_delete); | ||
399 | return luaL_error( L, "Bad idfunc(eDO_new): DEEP_VERSION is incorrect, rebuild your implementation with the latest deep implementation"); | ||
400 | } | ||
401 | prelude->refcount = 0; // 'push_deep_proxy' will lift it to 1 | ||
402 | prelude->idfunc = idfunc; | ||
403 | |||
404 | if( lua_gettop( L) - oldtop != 0) | ||
405 | { | ||
406 | // just in case, don't leak the newly allocated deep userdata object | ||
407 | lua_pushlightuserdata( L, prelude); | ||
408 | idfunc( L, eDO_delete); | ||
409 | return luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); | ||
410 | } | ||
411 | errmsg = push_deep_proxy( universe_get( L), L, prelude, nuv_, eLM_LaneBody); // proxy | ||
412 | if( errmsg != NULL) | ||
413 | { | ||
414 | return luaL_error( L, errmsg); | ||
415 | } | ||
416 | } | ||
417 | STACK_END( L, 1); | ||
418 | return 1; | ||
419 | } | ||
420 | |||
421 | |||
422 | /* | ||
423 | * Access deep userdata through a proxy. | ||
424 | * | ||
425 | * Reference count is not changed, and access to the deep userdata is not | ||
426 | * serialized. It is the module's responsibility to prevent conflicting usage. | ||
427 | */ | ||
428 | void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) | ||
429 | { | ||
430 | DeepPrelude** proxy; | ||
431 | |||
432 | STACK_CHECK( L, 0); | ||
433 | // ensure it is actually a deep userdata | ||
434 | if( get_idfunc( L, index, eLM_LaneBody) != idfunc) | ||
435 | { | ||
436 | return NULL; // no metatable, or wrong kind | ||
437 | } | ||
438 | |||
439 | proxy = (DeepPrelude**) lua_touserdata( L, index); | ||
440 | STACK_END( L, 0); | ||
441 | |||
442 | return *proxy; | ||
443 | } | ||
444 | |||
445 | |||
446 | /* | ||
447 | * Copy deep userdata between two separate Lua states (from L to L2) | ||
448 | * | ||
449 | * Returns: | ||
450 | * the id function of the copied value, or NULL for non-deep userdata | ||
451 | * (not copied) | ||
452 | */ | ||
453 | bool_t copydeep( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, LookupMode mode_, char const* upName_) | ||
454 | { | ||
455 | char const* errmsg; | ||
456 | luaG_IdFunction idfunc = get_idfunc( L, i, mode_); | ||
457 | int nuv = 0; | ||
458 | |||
459 | if( idfunc == NULL) | ||
460 | { | ||
461 | return FALSE; // not a deep userdata | ||
462 | } | ||
463 | |||
464 | STACK_CHECK( L, 0); | ||
465 | STACK_CHECK( L2, 0); | ||
466 | |||
467 | // extract all uservalues of the source | ||
468 | while( lua_getiuservalue( L, i, nuv + 1) != LUA_TNONE) // ... u [uv]* nil | ||
469 | { | ||
470 | ++ nuv; | ||
471 | } | ||
472 | // last call returned TNONE and pushed nil, that we don't need | ||
473 | lua_pop( L, 1); // ... u [uv]* | ||
474 | STACK_MID( L, nuv); | ||
475 | |||
476 | errmsg = push_deep_proxy( U, L2, *(DeepPrelude**) lua_touserdata( L, i), nuv, mode_); // u | ||
477 | |||
478 | // transfer all uservalues of the source in the destination | ||
479 | { | ||
480 | int const clone_i = lua_gettop( L2); | ||
481 | while( nuv) | ||
482 | { | ||
483 | inter_copy_one( U, L2, L2_cache_i, L, lua_absindex( L, -1), VT_NORMAL, mode_, upName_); // u uv | ||
484 | lua_pop( L, 1); // ... u [uv]* | ||
485 | // this pops the value from the stack | ||
486 | lua_setiuservalue( L2, clone_i, nuv); // u | ||
487 | -- nuv; | ||
488 | } | ||
489 | } | ||
490 | |||
491 | STACK_END( L2, 1); | ||
492 | STACK_END( L, 0); | ||
493 | |||
494 | if( errmsg != NULL) | ||
495 | { | ||
496 | // raise the error in the proper state (not the keeper) | ||
497 | lua_State* errL = (mode_ == eLM_FromKeeper) ? L2 : L; | ||
498 | luaL_error( errL, errmsg); | ||
499 | } | ||
500 | return TRUE; | ||
501 | } \ No newline at end of file | ||