diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2022-02-08 10:39:48 +0100 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2022-02-08 10:39:48 +0100 |
commit | 2c0000d5169cacf950d06637ada1a371cf382896 (patch) | |
tree | edfe62d964b98cc745d867f09feac2df2eab758f | |
parent | 54152c35e76acd1f21b477caf0a4403128032039 (diff) | |
download | lanes-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-- | CHANGES | 4 | ||||
-rw-r--r-- | deep_test/deep_test.c | 13 | ||||
-rw-r--r-- | deep_test/deep_test.vcxproj.user | 2 | ||||
-rw-r--r-- | deep_test/deeptest.lua | 24 | ||||
-rw-r--r-- | docs/index.html | 28 | ||||
-rw-r--r-- | lanes-3.16.0-0.rockspec (renamed from lanes-3.15.1-0.rockspec) | 4 | ||||
-rw-r--r-- | src/lanes.h | 4 | ||||
-rw-r--r-- | src/tools.c | 220 |
8 files changed, 142 insertions, 157 deletions
@@ -1,5 +1,9 @@ | |||
1 | CHANGES: | 1 | CHANGES: |
2 | 2 | ||
3 | CHANGE 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 | |||
3 | CHANGE 151: BGe 7-Feb-22 | 7 | CHANGE 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 | ||
7 | local test_deep = true | 7 | local test_deep = true |
8 | local test_clonable = true | 8 | local test_clonable = true |
9 | local test_uvtype = "function" | 9 | local test_uvtype = "string" |
10 | local nupvals = _VERSION == "Lua 5.4" and 2 or 1 | ||
10 | 11 | ||
11 | local makeUserValue = function( obj_) | 12 | local makeUserValue = function( obj_) |
12 | if test_uvtype == "string" then | 13 | if test_uvtype == "string" then |
@@ -21,14 +22,17 @@ local makeUserValue = function( obj_) | |||
21 | end | 22 | end |
22 | 23 | ||
23 | local printDeep = function( prefix_, obj_, t_) | 24 | local 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() | ||
32 | end | 36 | end |
33 | 37 | ||
34 | local performTest = function( obj_) | 38 | local 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_) | |||
76 | end | 82 | end |
77 | 83 | ||
78 | if test_deep then | 84 | if test_deep then |
85 | print "================================================================" | ||
79 | print "DEEP" | 86 | print "DEEP" |
80 | performTest( dt.new_deep()) | 87 | performTest( dt.new_deep(nupvals)) |
81 | end | 88 | end |
82 | 89 | ||
83 | if test_clonable then | 90 | if test_clonable then |
91 | print "================================================================" | ||
84 | print "CLONABLE" | 92 | print "CLONABLE" |
85 | performTest( dt.new_clonable()) | 93 | performTest( dt.new_clonable(nupvals)) |
86 | end | 94 | end |
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> |
1558 | static int clonable_lanesclone( lua_State* L) | 1557 | static 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 | ||
8 | package = "Lanes" | 8 | package = "Lanes" |
9 | 9 | ||
10 | version = "3.15.1-0" | 10 | version = "3.16.0-0" |
11 | 11 | ||
12 | source= { | 12 | source= { |
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 | ||
17 | description = { | 17 | description = { |
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 | */ |
1480 | static DECLARE_CONST_UNIQUE_KEY( CLONABLES_CACHE_KEY, 0xD04EE018B3DEE8F5); | 1480 | static DECLARE_CONST_UNIQUE_KEY( CLONABLES_CACHE_KEY, 0xD04EE018B3DEE8F5); |
1481 | 1481 | ||
1482 | static bool_t copyclone( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, LookupMode mode_, char const* upName_) | 1482 | static 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 | ||
1652 | static 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_) | 1643 | static 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 | } |