aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2022-02-08 10:39:48 +0100
committerBenoit Germain <bnt.germain@gmail.com>2022-02-08 10:39:48 +0100
commit2c0000d5169cacf950d06637ada1a371cf382896 (patch)
treeedfe62d964b98cc745d867f09feac2df2eab758f
parent54152c35e76acd1f21b477caf0a4403128032039 (diff)
downloadlanes-2c0000d5169cacf950d06637ada1a371cf382896.tar.gz
lanes-2c0000d5169cacf950d06637ada1a371cf382896.tar.bz2
lanes-2c0000d5169cacf950d06637ada1a371cf382896.zip
__lanesclone is now called only once with 3 parameters dest, source, size -> BREAKS CUSTOM DEEP USERDATA API
-rw-r--r--CHANGES4
-rw-r--r--deep_test/deep_test.c13
-rw-r--r--deep_test/deep_test.vcxproj.user2
-rw-r--r--deep_test/deeptest.lua24
-rw-r--r--docs/index.html28
-rw-r--r--lanes-3.16.0-0.rockspec (renamed from lanes-3.15.1-0.rockspec)4
-rw-r--r--src/lanes.h4
-rw-r--r--src/tools.c220
8 files changed, 142 insertions, 157 deletions
diff --git a/CHANGES b/CHANGES
index f356c26..490d651 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 152: BGe 7-Feb-22
4 * bumped version to 3.16.0
5 * __lanesclone is now called only once with 3 parameters dest, source, size -> BREAKS CUSTOM DEEP USERDATA API
6
3CHANGE 151: BGe 7-Feb-22 7CHANGE 151: BGe 7-Feb-22
4 * bumped version to 3.15.2 8 * bumped version to 3.15.2
5 * Lanes no longer relies on malloc/free for internal allocations, but uses the primary alloc function from the master Lua state 9 * Lanes no longer relies on malloc/free for internal allocations, but uses the primary alloc function from the master Lua state
diff --git a/deep_test/deep_test.c b/deep_test/deep_test.c
index a725902..cb89741 100644
--- a/deep_test/deep_test.c
+++ b/deep_test/deep_test.c
@@ -1,5 +1,6 @@
1#include <malloc.h> 1#include <malloc.h>
2#include <memory.h> 2#include <memory.h>
3#include <assert.h>
3 4
4#include "lua.h" 5#include "lua.h"
5#include "lualib.h" 6#include "lualib.h"
@@ -196,18 +197,12 @@ static int clonable_lanesclone( lua_State* L)
196{ 197{
197 switch( lua_gettop( L)) 198 switch( lua_gettop( L))
198 { 199 {
199 case 1: 200 case 3:
200 {
201 // in case we need it to compute the amount of memory we need
202 struct s_MyClonableUserdata* self = lua_touserdata( L, 1);
203 lua_pushinteger( L, sizeof( struct s_MyClonableUserdata));
204 }
205 return 1;
206
207 case 2:
208 { 201 {
209 struct s_MyClonableUserdata* self = lua_touserdata( L, 1); 202 struct s_MyClonableUserdata* self = lua_touserdata( L, 1);
210 struct s_MyClonableUserdata* from = lua_touserdata( L, 2); 203 struct s_MyClonableUserdata* from = lua_touserdata( L, 2);
204 size_t len = lua_tointeger( L, 3);
205 assert( len == sizeof(struct s_MyClonableUserdata));
211 *self = *from; 206 *self = *from;
212 } 207 }
213 return 0; 208 return 0;
diff --git a/deep_test/deep_test.vcxproj.user b/deep_test/deep_test.vcxproj.user
index c5d6237..6ffc0ba 100644
--- a/deep_test/deep_test.vcxproj.user
+++ b/deep_test/deep_test.vcxproj.user
@@ -13,7 +13,7 @@
13 <LocalDebuggerWorkingDirectory>D:\Boulot\anubis\Lua\bindings\Lanes\lanes\deep_test\</LocalDebuggerWorkingDirectory> 13 <LocalDebuggerWorkingDirectory>D:\Boulot\anubis\Lua\bindings\Lanes\lanes\deep_test\</LocalDebuggerWorkingDirectory>
14 </PropertyGroup> 14 </PropertyGroup>
15 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'"> 15 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">
16 <LocalDebuggerCommand>D:\Boulot\anubis\Lua\framework\lua53.exe</LocalDebuggerCommand> 16 <LocalDebuggerCommand>D:\Boulot\anubis\Lua\framework\lua54.exe</LocalDebuggerCommand>
17 <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> 17 <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
18 <LocalDebuggerCommandArguments>-i deeptest.lua</LocalDebuggerCommandArguments> 18 <LocalDebuggerCommandArguments>-i deeptest.lua</LocalDebuggerCommandArguments>
19 <LocalDebuggerWorkingDirectory>D:\Boulot\anubis\Lua\bindings\Lanes\lanes\deep_test\</LocalDebuggerWorkingDirectory> 19 <LocalDebuggerWorkingDirectory>D:\Boulot\anubis\Lua\bindings\Lanes\lanes\deep_test\</LocalDebuggerWorkingDirectory>
diff --git a/deep_test/deeptest.lua b/deep_test/deeptest.lua
index 3c89c3d..cbd08de 100644
--- a/deep_test/deeptest.lua
+++ b/deep_test/deeptest.lua
@@ -6,7 +6,8 @@ local dt = lanes.require "deep_test"
6 6
7local test_deep = true 7local test_deep = true
8local test_clonable = true 8local test_clonable = true
9local test_uvtype = "function" 9local test_uvtype = "string"
10local nupvals = _VERSION == "Lua 5.4" and 2 or 1
10 11
11local makeUserValue = function( obj_) 12local makeUserValue = function( obj_)
12 if test_uvtype == "string" then 13 if test_uvtype == "string" then
@@ -21,14 +22,17 @@ local makeUserValue = function( obj_)
21end 22end
22 23
23local printDeep = function( prefix_, obj_, t_) 24local printDeep = function( prefix_, obj_, t_)
24 local uservalue = obj_:getuv( 1) 25 print( prefix_, obj_)
25 print( prefix_) 26 for uvi = 1, nupvals do
26 print ( obj_, uservalue, type( uservalue) == "function" and uservalue() or "") 27 local uservalue = obj_:getuv( 1)
28 print ( "uv #" .. uvi, uservalue, type( uservalue) == "function" and uservalue() or "")
29 end
27 if t_ then 30 if t_ then
28 for k, v in pairs( t_) do 31 for k, v in pairs( t_) do
29 print( k, v) 32 print( k, v)
30 end 33 end
31 end 34 end
35 print()
32end 36end
33 37
34local performTest = function( obj_) 38local performTest = function( obj_)
@@ -38,12 +42,14 @@ local performTest = function( obj_)
38 -- lua 5.3 supports an arbitrary type uservalue 42 -- lua 5.3 supports an arbitrary type uservalue
39 obj_:setuv( 1, makeUserValue( obj_)) 43 obj_:setuv( 1, makeUserValue( obj_))
40 -- lua 5.4 supports multiple uservalues of arbitrary types 44 -- lua 5.4 supports multiple uservalues of arbitrary types
41 -- obj_:setuv( 2, "ENDUV") 45 if nupvals > 1 then
46 obj_:setuv( 2, "ENDUV")
47 end
42 48
43 local t = 49 local t =
44 { 50 {
45 ["key"] = obj_, 51 ["key"] = obj_,
46 -- [obj_] = "val" 52 [obj_] = "val" -- this one won't transfer because we don't support full uservalue as keys
47 } 53 }
48 54
49 -- read back the contents of the object 55 -- read back the contents of the object
@@ -76,11 +82,13 @@ local performTest = function( obj_)
76end 82end
77 83
78if test_deep then 84if test_deep then
85 print "================================================================"
79 print "DEEP" 86 print "DEEP"
80 performTest( dt.new_deep()) 87 performTest( dt.new_deep(nupvals))
81end 88end
82 89
83if test_clonable then 90if test_clonable then
91 print "================================================================"
84 print "CLONABLE" 92 print "CLONABLE"
85 performTest( dt.new_clonable()) 93 performTest( dt.new_clonable(nupvals))
86end 94end
diff --git a/docs/index.html b/docs/index.html
index 290383e..0e1a30b 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -70,7 +70,7 @@
70 </p> 70 </p>
71 71
72 <p> 72 <p>
73 This document was revised on 8-Feb-22, and applies to version <tt>3.15.2</tt>. 73 This document was revised on 8-Feb-22, and applies to version <tt>3.16.0</tt>.
74 </p> 74 </p>
75 </font> 75 </font>
76 </center> 76 </center>
@@ -1550,27 +1550,20 @@ events to a common Linda, but... :).</font>
1550<h3 id="clonable_userdata">Clonable full userdata in your own apps</h3> 1550<h3 id="clonable_userdata">Clonable full userdata in your own apps</h3>
1551<p> 1551<p>
1552 Starting with version 3.13.0, a new way of passing full userdata across lanes uses a new <tt>__lanesclone</tt> metamethod. 1552 Starting with version 3.13.0, a new way of passing full userdata across lanes uses a new <tt>__lanesclone</tt> metamethod.
1553 When a deep userdata is cloned, Lanes calls <tt>__lanesclone</tt> twice, in the context of the source lane.</br> 1553 When a deep userdata is cloned, Lanes calls <tt>__lanesclone</tt> once, in the context of the source lane.</br>
1554 The first call receives the original as light userdata, as in <tt>ud:__lanesclone()</tt>, and should return the amount of memory used to create the cloned full userdata.</br> 1554 The call receives the clone and original as light userdata, plus the actual userdata size, as in <tt>clone:__lanesclone(original,size)</tt>, and should perform the actual cloning.</br>
1555 The second call receives the clone and original as light userdata, as in <tt>clone:__lanesclone(original)</tt>, and should perform the actual cloning.</br> 1555 A typical implementation would look like (BEWARE, THIS CHANGED WITH VERSION 3.16.0):
1556 A typical implementation would look like:
1557<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> 1556<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre>
1558static int clonable_lanesclone( lua_State* L) 1557static int clonable_lanesclone( lua_State* L)
1559{ 1558{
1560 switch( lua_gettop( L)) 1559 switch( lua_gettop( L))
1561 { 1560 {
1562 case 1: // original:__lanesclone() 1561 case 3:
1563 {
1564 // the original (as light userdata), in case you need it to compute the size of the clone
1565 struct s_MyClonableUserdata* self = lua_touserdata( L, 1);
1566 lua_pushinteger( L, sizeof( struct s_MyClonableUserdata));
1567 }
1568 return 1;
1569
1570 case 2: // clone:__lanesclone(original)
1571 { 1562 {
1572 struct s_MyClonableUserdata* self = lua_touserdata( L, 1); 1563 struct s_MyClonableUserdata* self = lua_touserdata( L, 1);
1573 struct s_MyClonableUserdata* from = lua_touserdata( L, 2); 1564 struct s_MyClonableUserdata* from = lua_touserdata( L, 2);
1565 size_t len = lua_tointeger( L, 3);
1566 assert( len == sizeof(struct s_MyClonableUserdata));
1574 *self = *from; 1567 *self = *from;
1575 } 1568 }
1576 return 0; 1569 return 0;
@@ -1736,9 +1729,7 @@ int luaD_new_clonable( lua_State* L)
1736<h2 id="changes">Change log</h2> 1729<h2 id="changes">Change log</h2>
1737 1730
1738<p> 1731<p>
1739 v3.14.0: lane:cancel() rework: opt.cancelstep is gone, hook is installed by lane:cancel() if requested. 1732 See CHANGES.
1740
1741 For older stuff see CHANGES.
1742</p> 1733</p>
1743 1734
1744<!-- footnotes +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 1735<!-- footnotes +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -1754,5 +1745,4 @@ int luaD_new_clonable( lua_State* L)
1754</p> 1745</p>
1755 1746
1756</body> 1747</body>
1757</html> 1748</html> \ No newline at end of file
1758</pre></pre></pre></pre></pre></pre></pre> \ No newline at end of file
diff --git a/lanes-3.15.1-0.rockspec b/lanes-3.16.0-0.rockspec
index 5481269..170d9eb 100644
--- a/lanes-3.15.1-0.rockspec
+++ b/lanes-3.16.0-0.rockspec
@@ -7,11 +7,11 @@
7 7
8package = "Lanes" 8package = "Lanes"
9 9
10version = "3.15.1-0" 10version = "3.16.0-0"
11 11
12source= { 12source= {
13 url= "https://github.com/LuaLanes/lanes.git", 13 url= "https://github.com/LuaLanes/lanes.git",
14 branch= "v3.15.1" 14 branch= "v3.16.0"
15} 15}
16 16
17description = { 17description = {
diff --git a/src/lanes.h b/src/lanes.h
index 4c7cc5b..20524e6 100644
--- a/src/lanes.h
+++ b/src/lanes.h
@@ -11,8 +11,8 @@
11#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 11#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
12 12
13#define LANES_VERSION_MAJOR 3 13#define LANES_VERSION_MAJOR 3
14#define LANES_VERSION_MINOR 15 14#define LANES_VERSION_MINOR 16
15#define LANES_VERSION_PATCH 2 15#define LANES_VERSION_PATCH 0
16 16
17#define LANES_MIN_VERSION_REQUIRED(MAJOR, MINOR, PATCH) ((LANES_VERSION_MAJOR>MAJOR) || (LANES_VERSION_MAJOR==MAJOR && (LANES_VERSION_MINOR>MINOR || (LANES_VERSION_MINOR==MINOR && LANES_VERSION_PATCH>=PATCH)))) 17#define LANES_MIN_VERSION_REQUIRED(MAJOR, MINOR, PATCH) ((LANES_VERSION_MAJOR>MAJOR) || (LANES_VERSION_MAJOR==MAJOR && (LANES_VERSION_MINOR>MINOR || (LANES_VERSION_MINOR==MINOR && LANES_VERSION_PATCH>=PATCH))))
18#define LANES_VERSION_LESS_THAN(MAJOR, MINOR, PATCH) ((LANES_VERSION_MAJOR<MAJOR) || (LANES_VERSION_MAJOR==MAJOR && (LANES_VERSION_MINOR<MINOR || (LANES_VERSION_MINOR==MINOR && LANES_VERSION_PATCH<PATCH)))) 18#define LANES_VERSION_LESS_THAN(MAJOR, MINOR, PATCH) ((LANES_VERSION_MAJOR<MAJOR) || (LANES_VERSION_MAJOR==MAJOR && (LANES_VERSION_MINOR<MINOR || (LANES_VERSION_MINOR==MINOR && LANES_VERSION_PATCH<PATCH))))
diff --git a/src/tools.c b/src/tools.c
index e72d441..a297913 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -1479,16 +1479,17 @@ static void inter_copy_keyvaluepair( Universe* U, lua_State* L2, uint_t L2_cache
1479*/ 1479*/
1480static DECLARE_CONST_UNIQUE_KEY( CLONABLES_CACHE_KEY, 0xD04EE018B3DEE8F5); 1480static DECLARE_CONST_UNIQUE_KEY( CLONABLES_CACHE_KEY, 0xD04EE018B3DEE8F5);
1481 1481
1482static bool_t copyclone( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, LookupMode mode_, char const* upName_) 1482static bool_t copyclone( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t source_i_, LookupMode mode_, char const* upName_)
1483{ 1483{
1484 void* const source = lua_touserdata( L, i); 1484 void* const source = lua_touserdata( L, source_i_);
1485 source_i_ = lua_absindex( L, source_i_);
1485 1486
1486 STACK_CHECK( L, 0); 1487 STACK_CHECK( L, 0); // L (source) // L2 (destination)
1487 STACK_CHECK( L2, 0); 1488 STACK_CHECK( L2, 0);
1488 1489
1489 // Check if the source was already cloned during this copy 1490 // Check if the source was already cloned during this copy
1490 lua_pushlightuserdata( L2, source); // ... source 1491 lua_pushlightuserdata( L2, source); // ... source
1491 lua_rawget( L2, L2_cache_i); // ... clone? 1492 lua_rawget( L2, L2_cache_i); // ... clone?
1492 if ( !lua_isnil( L2, -1)) 1493 if ( !lua_isnil( L2, -1))
1493 { 1494 {
1494 STACK_MID( L2, 1); 1495 STACK_MID( L2, 1);
@@ -1496,107 +1497,97 @@ static bool_t copyclone( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_Stat
1496 } 1497 }
1497 else 1498 else
1498 { 1499 {
1499 lua_pop( L2, 1); // ... 1500 lua_pop( L2, 1); // ...
1500 } 1501 }
1501 STACK_MID( L2, 0); 1502 STACK_MID( L2, 0);
1502 1503
1503 // no metatable? -> not clonable 1504 // no metatable? -> not clonable
1504 if( !lua_getmetatable( L, i)) // ... mt? 1505 if( !lua_getmetatable( L, source_i_)) // ... mt?
1505 { 1506 {
1506 STACK_MID( L, 0); 1507 STACK_MID( L, 0);
1507 return FALSE; 1508 return FALSE;
1508 } 1509 }
1509 1510
1510 // no __lanesclone? -> not clonable 1511 // no __lanesclone? -> not clonable
1511 lua_getfield( L, -1, "__lanesclone"); // ... mt __lanesclone? 1512 lua_getfield( L, -1, "__lanesclone"); // ... mt __lanesclone?
1512 if( lua_isnil( L, -1)) 1513 if( lua_isnil( L, -1))
1513 { 1514 {
1514 lua_pop( L, 2); // ... 1515 lua_pop( L, 2); // ...
1515 STACK_MID( L, 0); 1516 STACK_MID( L, 0);
1516 return FALSE; 1517 return FALSE;
1517 } 1518 }
1518 1519
1520 // we need to copy over the uservalues of the userdata as well
1519 { 1521 {
1520 int const mt = lua_absindex( L, -2); 1522 int const mt = lua_absindex( L, -2); // ... mt __lanesclone
1521 size_t userdata_size = 0; 1523 size_t const userdata_size = (size_t) lua_rawlen( L, source_i_);
1522 void* clone = NULL; 1524 void* clone = NULL;
1523 lua_pushvalue( L, -1); // ... mt __lanesclone __lanesclone 1525 // extract all the uservalues, but don't transfer them yet
1524 // call the cloning function with 1 argument, should return the number of bytes to allocate for the clone 1526 int uvi = 0;
1525 lua_pushlightuserdata( L, source); // ... mt __lanesclone __lanesclone source 1527 while( lua_getiuservalue( L, source_i_, ++ uvi) != LUA_TNONE) {} // ... mt __lanesclone [uv]+ nil
1526 lua_call( L, 1, 1); // ... mt __lanesclone size 1528 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now
1527 STACK_MID( L, 3); 1529 lua_pop( L, 1); // ... mt __lanesclone [uv]+
1528 userdata_size = (size_t) lua_tointeger( L, -1); // ... mt __lanesclone size 1530 -- uvi;
1529 lua_pop( L, 1); // ... mt __lanesclone 1531 // create the clone userdata with the required number of uservalue slots
1530 // we need to copy over the uservalues of the userdata as well 1532 clone = lua_newuserdatauv( L2, userdata_size, uvi); // ... u
1533 // copy the metatable in the target state, and give it to the clone we put there
1534 if( inter_copy_one( U, L2, L2_cache_i, L, mt, VT_NORMAL, mode_, upName_)) // ... u mt|sentinel
1531 { 1535 {
1532 // extract all the uservalues, but don't transfer them yet 1536 if( eLM_ToKeeper == mode_) // ... u sentinel
1533 int uvi = 0;
1534 while( lua_getiuservalue( L, i, uvi + 1) != LUA_TNONE) // ... mt __lanesclone [uv]+ nil
1535 { 1537 {
1536 ++ uvi; 1538 ASSERT_L( lua_tocfunction( L2, -1) == table_lookup_sentinel);
1539 // we want to create a new closure with a 'clone sentinel' function, where the upvalues are the userdata and the metatable fqn
1540 lua_getupvalue( L2, -1, 1); // ... u sentinel fqn
1541 lua_remove( L2, -2); // ... u fqn
1542 lua_insert( L2, -2); // ... fqn u
1543 lua_pushcclosure( L2, userdata_clone_sentinel, 2); // ... userdata_clone_sentinel
1537 } 1544 }
1538 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now 1545 else // from keeper or direct // ... u mt
1539 lua_pop( L, 1); // ... mt __lanesclone [uv]+
1540 // create the clone userdata with the required number of uservalue slots
1541 clone = lua_newuserdatauv( L2, userdata_size, uvi); // ... u
1542 // copy the metatable in the target state, and give it to the clone we put there
1543 if( inter_copy_one( U, L2, L2_cache_i, L, mt, VT_NORMAL, mode_, upName_)) // ... u mt|sentinel
1544 { 1546 {
1545 if( eLM_ToKeeper == mode_) // ... u sentinel 1547 ASSERT_L( lua_istable( L2, -1));
1546 { 1548 lua_setmetatable( L2, -2); // ... u
1547 ASSERT_L( lua_tocfunction( L2, -1) == table_lookup_sentinel);
1548 // we want to create a new closure with a 'clone sentinel' function, where the upvalues are the userdata and the metatable fqn
1549 lua_getupvalue( L2, -1, 1); // ... u sentinel fqn
1550 lua_remove( L2, -2); // ... u fqn
1551 lua_insert( L2, -2); // ... fqn u
1552 lua_pushcclosure( L2, userdata_clone_sentinel, 2); // ... userdata_clone_sentinel
1553 }
1554 else // from keeper or direct // ... u mt
1555 {
1556 ASSERT_L( lua_istable( L2, -1));
1557 lua_setmetatable( L2, -2); // ... u
1558 }
1559 STACK_MID( L2, 1);
1560 }
1561 else
1562 {
1563 (void) luaL_error( L, "Error copying a metatable");
1564 }
1565 // first, add the entry in the cache (at this point it is either the actual userdata or the keeper sentinel
1566 lua_pushlightuserdata( L2, source); // ... u source
1567 lua_pushvalue( L2, -2); // ... u source u
1568 lua_rawset( L2, L2_cache_i); // ... u
1569 // make sure we have the userdata now
1570 if( eLM_ToKeeper == mode_) // ... userdata_clone_sentinel
1571 {
1572 lua_getupvalue( L2, -1, 2); // ... userdata_clone_sentinel u
1573 }
1574 // assign uservalues
1575 while( uvi > 0)
1576 {
1577 inter_copy_one( U, L2, L2_cache_i, L, lua_absindex( L, -1), VT_NORMAL, mode_, upName_); // ... u uv
1578 lua_pop( L, 1); // ... mt __lanesclone [uv]*
1579 // this pops the value from the stack
1580 lua_setiuservalue( L2, -2, uvi); // ... u
1581 -- uvi;
1582 }
1583 // when we are done, all uservalues are popped from the source stack, and we want only the single transferred value in the destination
1584 if( eLM_ToKeeper == mode_) // ... userdata_clone_sentinel u
1585 {
1586 lua_pop( L2, 1); // ... userdata_clone_sentinel
1587 } 1549 }
1588 STACK_MID( L2, 1); 1550 STACK_MID( L2, 1);
1589 STACK_MID( L, 2);
1590 // call cloning function in source state to perform the actual memory cloning
1591 lua_pushlightuserdata( L, clone); // ... mt __lanesclone clone
1592 lua_pushlightuserdata( L, source); // ... mt __lanesclone clone source
1593 lua_call( L, 2, 0); // ... mt
1594 STACK_MID( L, 1);
1595 } 1551 }
1552 else
1553 {
1554 (void) luaL_error( L, "Error copying a metatable");
1555 }
1556 // first, add the entry in the cache (at this point it is either the actual userdata or the keeper sentinel
1557 lua_pushlightuserdata( L2, source); // ... u source
1558 lua_pushvalue( L2, -2); // ... u source u
1559 lua_rawset( L2, L2_cache_i); // ... u
1560 // make sure we have the userdata now
1561 if( eLM_ToKeeper == mode_) // ... userdata_clone_sentinel
1562 {
1563 lua_getupvalue( L2, -1, 2); // ... userdata_clone_sentinel u
1564 }
1565 // assign uservalues
1566 while( uvi > 0)
1567 {
1568 inter_copy_one( U, L2, L2_cache_i, L, lua_absindex( L, -1), VT_NORMAL, mode_, upName_); // ... u uv
1569 lua_pop( L, 1); // ... mt __lanesclone [uv]*
1570 // this pops the value from the stack
1571 lua_setiuservalue( L2, -2, uvi); // ... u
1572 -- uvi;
1573 }
1574 // when we are done, all uservalues are popped from the source stack, and we want only the single transferred value in the destination
1575 if( eLM_ToKeeper == mode_) // ... userdata_clone_sentinel u
1576 {
1577 lua_pop( L2, 1); // ... userdata_clone_sentinel
1578 }
1579 STACK_MID( L2, 1);
1580 STACK_MID( L, 2);
1581 // call cloning function in source state to perform the actual memory cloning
1582 lua_pushlightuserdata( L, clone); // ... mt __lanesclone clone
1583 lua_pushlightuserdata( L, source); // ... mt __lanesclone clone source
1584 lua_pushinteger( L, userdata_size); // ... mt __lanesclone clone source size
1585 lua_call( L, 3, 0); // ... mt
1586 STACK_MID( L, 1);
1596 } 1587 }
1597 1588
1598 STACK_END( L2, 1); 1589 STACK_END( L2, 1);
1599 lua_pop( L, 1); // ... 1590 lua_pop( L, 1); // ...
1600 STACK_END( L, 0); 1591 STACK_END( L, 0);
1601 return TRUE; 1592 return TRUE;
1602} 1593}
@@ -1649,18 +1640,18 @@ static bool_t inter_copy_userdata( Universe* U, lua_State* L2, uint_t L2_cache_i
1649 return TRUE; 1640 return TRUE;
1650} 1641}
1651 1642
1652static bool_t inter_copy_function( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt, LookupMode mode_, char const* upName_) 1643static bool_t inter_copy_function( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t source_i_, enum e_vt vt, LookupMode mode_, char const* upName_)
1653{ 1644{
1654 if( vt == VT_KEY) 1645 if( vt == VT_KEY)
1655 { 1646 {
1656 return FALSE; 1647 return FALSE;
1657 } 1648 }
1658 1649
1659 STACK_CHECK( L, 0); 1650 STACK_CHECK( L, 0); // L (source) // L2 (destination)
1660 STACK_CHECK( L2, 0); 1651 STACK_CHECK( L2, 0);
1661 DEBUGSPEW_CODE( fprintf( stderr, "FUNCTION %s\n", upName_)); 1652 DEBUGSPEW_CODE( fprintf( stderr, "FUNCTION %s\n", upName_));
1662 1653
1663 if( lua_tocfunction( L, i) == userdata_clone_sentinel) // we are actually copying a clonable full userdata from a keeper 1654 if( lua_tocfunction( L, source_i_) == userdata_clone_sentinel) // we are actually copying a clonable full userdata from a keeper
1664 { 1655 {
1665 // clone the full userdata again 1656 // clone the full userdata again
1666 size_t userdata_size = 0; 1657 size_t userdata_size = 0;
@@ -1668,10 +1659,10 @@ static bool_t inter_copy_function( Universe* U, lua_State* L2, uint_t L2_cache_i
1668 void* clone; 1659 void* clone;
1669 1660
1670 // let's see if we already restored this userdata 1661 // let's see if we already restored this userdata
1671 lua_getupvalue( L, i, 2); // ... u 1662 lua_getupvalue( L, source_i_, 2); // ... u
1672 source = lua_touserdata( L, -1); 1663 source = lua_touserdata( L, -1);
1673 lua_pushlightuserdata( L2, source); // ... source 1664 lua_pushlightuserdata( L2, source); // ... source
1674 lua_rawget( L2, L2_cache_i); // ... u? 1665 lua_rawget( L2, L2_cache_i); // ... u?
1675 if( !lua_isnil( L2, -1)) 1666 if( !lua_isnil( L2, -1))
1676 { 1667 {
1677 lua_pop( L, 1); // ... 1668 lua_pop( L, 1); // ...
@@ -1679,66 +1670,63 @@ static bool_t inter_copy_function( Universe* U, lua_State* L2, uint_t L2_cache_i
1679 STACK_MID( L2, 1); 1670 STACK_MID( L2, 1);
1680 return TRUE; 1671 return TRUE;
1681 } 1672 }
1682 lua_pop( L2, 1); // ... 1673 lua_pop( L2, 1); // ...
1683 1674
1684 // this function has 2 upvalues: the fqn of its metatable, and the userdata itself 1675 // this function has 2 upvalues: the fqn of its metatable, and the userdata itself
1685 lookup_table( L2, L, i, mode_, upName_); // ... mt 1676 lookup_table( L2, L, source_i_, mode_, upName_); // ... mt
1686 // __lanesclone should always exist because we wouldn't be restoring data from a userdata_clone_sentinel closure to begin with 1677 // originally 'i' slot was the proxy closure, but from now on it indexes the actual userdata we extracted from it
1687 lua_getfield( L2, -1, "__lanesclone"); // ... mt __lanesclone 1678 source_i_ = lua_gettop( L);
1688 lua_pushvalue( L2, -1); // ... mt __lanesclone __lanesclone
1689 // 'i' slot is the closure, but from now on it is the actual userdata
1690 i = lua_gettop( L);
1691 source = lua_touserdata( L, -1); 1679 source = lua_touserdata( L, -1);
1692 // call the cloning function with 1 argument, should return the number of bytes to allocate for the clone 1680 // call the cloning function with 1 argument, should return the number of bytes to allocate for the clone
1693 lua_pushlightuserdata( L2, source); // ... mt __lanesclone __lanesclone source 1681 userdata_size = (size_t) lua_rawlen( L, -1);
1694 lua_call( L2, 1, 1); // ... mt __lanesclone size
1695 userdata_size = (size_t) lua_tointeger( L2, -1); // ... mt __lanesclone size
1696 lua_pop( L2, 1); // ... mt __lanesclone
1697 { 1682 {
1698 // extract uservalues (don't transfer them yet) 1683 // extract uservalues (don't transfer them yet)
1699 int uvi = 0; 1684 int uvi = 0;
1700 while( lua_getiuservalue( L, i, uvi + 1) != LUA_TNONE) // ... u uv 1685 while( lua_getiuservalue( L, source_i_, ++ uvi) != LUA_TNONE) {} // ... u uv
1701 {
1702 ++ uvi;
1703 }
1704 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now 1686 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now
1705 lua_pop( L, 1); // ... u [uv]* 1687 lua_pop( L, 1); // ... u [uv]*
1688 -- uvi;
1706 STACK_MID( L, uvi + 1); 1689 STACK_MID( L, uvi + 1);
1707 // create the clone userdata with the required number of uservalue slots 1690 // create the clone userdata with the required number of uservalue slots
1708 clone = lua_newuserdatauv( L2, userdata_size, uvi); // ... mt __lanesclone u 1691 clone = lua_newuserdatauv( L2, userdata_size, uvi); // ... mt u
1709 // add it in the cache 1692 // add it in the cache
1710 lua_pushlightuserdata( L2, source); // ... mt __lanesclone u source 1693 lua_pushlightuserdata( L2, source); // ... mt u source
1711 lua_pushvalue( L2, -2); // ... mt __lanesclone u source u 1694 lua_pushvalue( L2, -2); // ... mt u source u
1712 lua_rawset( L2, L2_cache_i); // ... mt __lanesclone u 1695 lua_rawset( L2, L2_cache_i); // ... mt u
1713 // set metatable 1696 // set metatable
1714 lua_pushvalue( L2, -3); // ... mt __lanesclone u mt 1697 lua_pushvalue( L2, -2); // ... mt u mt
1715 lua_setmetatable( L2, -2); // ... mt __lanesclone u 1698 lua_setmetatable( L2, -2); // ... mt u
1716 // transfer and assign uservalues 1699 // transfer and assign uservalues
1717 while( uvi > 0) 1700 while( uvi > 0)
1718 { 1701 {
1719 inter_copy_one( U, L2, L2_cache_i, L, lua_absindex( L, -1), vt, mode_, upName_); // ... mt __lanesclone u uv 1702 inter_copy_one( U, L2, L2_cache_i, L, lua_absindex( L, -1), vt, mode_, upName_); // ... mt u uv
1720 lua_pop( L, 1); // ... u [uv]* 1703 lua_pop( L, 1); // ... u [uv]*
1721 // this pops the value from the stack 1704 // this pops the value from the stack
1722 lua_setiuservalue( L2, -2, uvi); // ... mt __lanesclone u 1705 lua_setiuservalue( L2, -2, uvi); // ... mt u
1723 -- uvi; 1706 -- uvi;
1724 } 1707 }
1725 // when we are done, all uservalues are popped from the stack 1708 // when we are done, all uservalues are popped from the stack, we can pop the source as well
1726 lua_pop( L, 1); // ... 1709 lua_pop( L, 1); // ...
1727 STACK_MID( L, 0); 1710 STACK_MID( L, 0);
1728 STACK_MID( L2, 3); // ... mt __lanesclone u 1711 STACK_MID( L2, 2); // ... mt u
1729 } 1712 }
1730 // perform the custom cloning part 1713 // perform the custom cloning part
1731 lua_replace( L2, -3); // ... u __lanesclone 1714 lua_insert( L2, -2); // ... u mt
1732 lua_pushlightuserdata( L2, clone); // ... u __lanesclone clone 1715 // __lanesclone should always exist because we wouldn't be restoring data from a userdata_clone_sentinel closure to begin with
1733 lua_pushlightuserdata( L2, source); // ... u __lanesclone clone source 1716 lua_getfield(L2, -2, "__lanesclone"); // ... u mt __lanesclone
1734 lua_call( L2, 2, 0); // ... u 1717 lua_remove( L2, -2); // ... u __lanesclone
1718 lua_pushlightuserdata( L2, clone); // ... u __lanesclone clone
1719 lua_pushlightuserdata( L2, source); // ... u __lanesclone clone source
1720 lua_pushinteger( L2, userdata_size); // ... u __lanesclone clone source size
1721 // clone:__lanesclone(source, size)
1722 lua_call( L2, 3, 0); // ... u
1735 } 1723 }
1736 else 1724 else // regular function
1737 { 1725 {
1738 DEBUGSPEW_CODE( fprintf( stderr, "FUNCTION %s\n", upName_)); 1726 DEBUGSPEW_CODE( fprintf( stderr, "FUNCTION %s\n", upName_));
1739 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 1727 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
1740 STACK_CHECK( L2, 0); 1728 STACK_CHECK( L2, 0);
1741 copy_cached_func( U, L2, L2_cache_i, L, i, mode_, upName_); 1729 copy_cached_func( U, L2, L2_cache_i, L, source_i_, mode_, upName_); // ... f
1742 STACK_END( L2, 1); 1730 STACK_END( L2, 1);
1743 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 1731 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
1744 } 1732 }