diff options
author | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2018-11-07 19:16:36 +0100 |
---|---|---|
committer | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2018-11-07 19:16:36 +0100 |
commit | a142eb1e1ee81919d10b55bb7fa2e33636098d85 (patch) | |
tree | 21ef5c830ce4b4e845454af4274beabd073cc720 | |
parent | 91155c74fc10fa98ad6257d5309bfd13d4a61cf0 (diff) | |
download | lanes-a142eb1e1ee81919d10b55bb7fa2e33636098d85.tar.gz lanes-a142eb1e1ee81919d10b55bb7fa2e33636098d85.tar.bz2 lanes-a142eb1e1ee81919d10b55bb7fa2e33636098d85.zip |
__lanesclone mechanism should actually work now
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | deep_test/deep_test.c | 80 | ||||
-rw-r--r-- | deep_test/deeptest.lua | 53 | ||||
-rw-r--r-- | docs/index.html | 65 | ||||
-rw-r--r-- | src/lanes.c | 1 | ||||
-rw-r--r-- | src/tools.c | 89 |
6 files changed, 230 insertions, 61 deletions
@@ -1,5 +1,8 @@ | |||
1 | CHANGES: | 1 | CHANGES: |
2 | 2 | ||
3 | CHANGE 132: BGe 7-Nov-18 | ||
4 | * __lanesclone mechanism should actually work now | ||
5 | |||
3 | CHANGE 131: BGe 7-Nov-18 | 6 | CHANGE 131: BGe 7-Nov-18 |
4 | * Fix potential crash at application shutdown when deep userdata were created before Lanes is required | 7 | * Fix potential crash at application shutdown when deep userdata were created before Lanes is required |
5 | 8 | ||
diff --git a/deep_test/deep_test.c b/deep_test/deep_test.c index 8f34fe5..4aac586 100644 --- a/deep_test/deep_test.c +++ b/deep_test/deep_test.c | |||
@@ -80,10 +80,7 @@ static void* deep_test_id( lua_State* L, enum eDeepOp op_) | |||
80 | 80 | ||
81 | case eDO_metatable: | 81 | case eDO_metatable: |
82 | { | 82 | { |
83 | lua_newtable( L); // mt | 83 | luaL_getmetatable( L, "deep"); // mt |
84 | luaL_setfuncs( L, deep_mt, 0); // mt | ||
85 | lua_pushvalue( L, -1); // mt mt | ||
86 | lua_setfield( L, -2, "__index"); // mt | ||
87 | luaG_pushdeepversion( L); // mt version | 84 | luaG_pushdeepversion( L); // mt version |
88 | return NULL; | 85 | return NULL; |
89 | } | 86 | } |
@@ -115,6 +112,16 @@ struct s_MyClonableUserdata | |||
115 | 112 | ||
116 | // ################################################################################################ | 113 | // ################################################################################################ |
117 | 114 | ||
115 | static int clonable_set( lua_State* L) | ||
116 | { | ||
117 | struct s_MyClonableUserdata* self = (struct s_MyClonableUserdata*) lua_touserdata( L, 1); | ||
118 | lua_Integer i = lua_tointeger( L, 2); | ||
119 | self->val = i; | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | // ################################################################################################ | ||
124 | |||
118 | static int clonable_tostring(lua_State* L) | 125 | static int clonable_tostring(lua_State* L) |
119 | { | 126 | { |
120 | struct s_MyClonableUserdata* self = (struct s_MyClonableUserdata*) lua_touserdata( L, 1); | 127 | struct s_MyClonableUserdata* self = (struct s_MyClonableUserdata*) lua_touserdata( L, 1); |
@@ -124,13 +131,34 @@ static int clonable_tostring(lua_State* L) | |||
124 | 131 | ||
125 | // ################################################################################################ | 132 | // ################################################################################################ |
126 | 133 | ||
134 | static int clonable_gc( lua_State* L) | ||
135 | { | ||
136 | struct s_MyClonableUserdata* self = (struct s_MyClonableUserdata*) lua_touserdata( L, 1); | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | // ################################################################################################ | ||
141 | |||
127 | static int clonable_lanesclone( lua_State* L) | 142 | static int clonable_lanesclone( lua_State* L) |
128 | { | 143 | { |
129 | // no need to set the metatable, the Lane copying mechanism will take care of it | 144 | switch( lua_gettop( L)) |
130 | struct s_MyClonableUserdata* self = lua_touserdata( L, 1); | 145 | { |
131 | struct s_MyClonableUserdata* to = lua_newuserdata( L, sizeof( struct s_MyClonableUserdata)); | 146 | case 0: |
132 | memcpy( to, self, sizeof(struct s_MyClonableUserdata)); | 147 | lua_pushinteger( L, sizeof( struct s_MyClonableUserdata)); |
133 | return 1; | 148 | return 1; |
149 | |||
150 | case 2: | ||
151 | { | ||
152 | struct s_MyClonableUserdata* self = lua_touserdata( L, 1); | ||
153 | struct s_MyClonableUserdata* from = lua_touserdata( L, 2); | ||
154 | *self = *from; | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | default: | ||
159 | (void) luaL_error( L, "Lanes called clonable_lanesclone with unexpected parameters"); | ||
160 | } | ||
161 | return 0; | ||
134 | } | 162 | } |
135 | 163 | ||
136 | // ################################################################################################ | 164 | // ################################################################################################ |
@@ -138,9 +166,9 @@ static int clonable_lanesclone( lua_State* L) | |||
138 | static luaL_Reg const clonable_mt[] = | 166 | static luaL_Reg const clonable_mt[] = |
139 | { | 167 | { |
140 | { "__tostring", clonable_tostring}, | 168 | { "__tostring", clonable_tostring}, |
141 | //{ "__gc", deep_gc}, | 169 | { "__gc", clonable_gc}, |
142 | { "__lanesclone", clonable_lanesclone}, | 170 | { "__lanesclone", clonable_lanesclone}, |
143 | //{ "set", deep_set}, | 171 | { "set", clonable_set}, |
144 | { NULL, NULL } | 172 | { NULL, NULL } |
145 | }; | 173 | }; |
146 | 174 | ||
@@ -149,15 +177,7 @@ static luaL_Reg const clonable_mt[] = | |||
149 | int luaD_new_clonable( lua_State* L) | 177 | int luaD_new_clonable( lua_State* L) |
150 | { | 178 | { |
151 | lua_newuserdata( L, sizeof( struct s_MyClonableUserdata)); | 179 | lua_newuserdata( L, sizeof( struct s_MyClonableUserdata)); |
152 | if( luaL_getmetatable( L, "clonable") == LUA_TNIL) // u mt? | 180 | luaL_setmetatable( L, "clonable"); |
153 | { | ||
154 | lua_pop( L, 1); // u | ||
155 | lua_newtable( L); // u mt | ||
156 | luaL_setfuncs( L, clonable_mt, 0); | ||
157 | lua_pushvalue(L, -1); // u mt mt | ||
158 | lua_setfield(L, -2, "__index"); // u mt | ||
159 | } | ||
160 | lua_setmetatable( L, -2); // u | ||
161 | return 1; | 181 | return 1; |
162 | } | 182 | } |
163 | 183 | ||
@@ -175,6 +195,24 @@ static luaL_Reg const deep_module[] = | |||
175 | 195 | ||
176 | extern int __declspec(dllexport) luaopen_deep_test(lua_State* L) | 196 | extern int __declspec(dllexport) luaopen_deep_test(lua_State* L) |
177 | { | 197 | { |
178 | luaL_newlib( L, deep_module); | 198 | luaL_newlib( L, deep_module); // M |
199 | |||
200 | // preregister the metatables for the types we can instanciate so that Lanes can know about them | ||
201 | if( luaL_newmetatable( L, "clonable")) // M mt | ||
202 | { | ||
203 | luaL_setfuncs( L, clonable_mt, 0); | ||
204 | lua_pushvalue(L, -1); // M mt mt | ||
205 | lua_setfield(L, -2, "__index"); // M mt | ||
206 | } | ||
207 | lua_setfield(L, -2, "__clonableMT"); // M | ||
208 | |||
209 | if( luaL_newmetatable( L, "deep")) // mt | ||
210 | { | ||
211 | luaL_setfuncs( L, deep_mt, 0); | ||
212 | lua_pushvalue(L, -1); // mt mt | ||
213 | lua_setfield(L, -2, "__index"); // mt | ||
214 | } | ||
215 | lua_setfield(L, -2, "__deepMT"); // M | ||
216 | |||
179 | return 1; | 217 | return 1; |
180 | } | 218 | } |
diff --git a/deep_test/deeptest.lua b/deep_test/deeptest.lua index 3b514dd..c0bbab4 100644 --- a/deep_test/deeptest.lua +++ b/deep_test/deeptest.lua | |||
@@ -1,22 +1,39 @@ | |||
1 | -- create a deep-aware full userdata while Lanes isn't loaded | 1 | local lanes = require("lanes").configure{ with_timers = false} |
2 | local dt = require "deep_test" | 2 | local l = lanes.linda "my linda" |
3 | local deep = dt.new_deep() | ||
4 | deep:set(666) | ||
5 | print( deep) | ||
6 | 3 | ||
7 | local clonable = dt.new_clonable() | 4 | -- we will transfer userdata created by this module, so we need to make Lanes aware of it |
5 | local dt = lanes.require "deep_test" | ||
8 | 6 | ||
9 | -- now load Lanes and see if that userdata is transferable | 7 | local test_deep = true |
10 | --[[ | 8 | local test_clonable = false |
11 | local lanes = require("lanes").configure() | 9 | |
12 | local l = lanes.linda "my linda" | 10 | local performTest = function( obj_) |
11 | obj_:set(666) | ||
12 | print( "immediate:", obj_) | ||
13 | |||
14 | l:set( "key", obj_) | ||
15 | local out = l:get( "key") | ||
16 | print( "out of linda:", out) | ||
17 | |||
18 | local g = lanes.gen( | ||
19 | "package" | ||
20 | , { | ||
21 | required = { "deep_test"} -- we will transfer userdata created by this module, so we need to make this lane aware of it | ||
22 | } | ||
23 | , function( obj_) | ||
24 | print( "in lane:", obj_) | ||
25 | return obj_ | ||
26 | end | ||
27 | ) | ||
28 | h = g( obj_) | ||
29 | local from_lane = h[1] | ||
30 | print( "from lane:", from_lane) | ||
31 | end | ||
13 | 32 | ||
14 | l:set( "key", deep) | 33 | if test_deep then |
15 | local deep_out = l:get( "key") | 34 | performTest( dt.new_deep()) |
16 | print( deep_out) | 35 | end |
17 | 36 | ||
18 | lanes.register() | 37 | if test_clonable then |
19 | l:set( "key", clonable) | 38 | performTest( dt.new_clonable()) |
20 | local clonable_out = l:get( "key") | 39 | end |
21 | print( clonable_out) | ||
22 | --]] \ No newline at end of file | ||
diff --git a/docs/index.html b/docs/index.html index aa12a36..9c76bef 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 4-Nov-18, and applies to version <tt>3.13</tt>. | 73 | This document was revised on 7-Nov-18, and applies to version <tt>3.13</tt>. |
74 | </p> | 74 | </p> |
75 | </font> | 75 | </font> |
76 | </center> | 76 | </center> |
@@ -1516,15 +1516,68 @@ events to a common Linda, but... :).</font> | |||
1516 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> | 1516 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> |
1517 | static int clonable_lanesclone( lua_State* L) | 1517 | static int clonable_lanesclone( lua_State* L) |
1518 | { | 1518 | { |
1519 | // no need to set the metatable, the Lane copying mechanism will take care of it | 1519 | switch( lua_gettop( L)) |
1520 | struct s_MyClonableUserdata* self = lua_touserdata( L, 1); | 1520 | { |
1521 | struct s_MyClonableUserdata* to = lua_newuserdata( L, sizeof( struct s_MyClonableUserdata)); | 1521 | case 0: |
1522 | memcpy( to, self, sizeof(struct s_MyClonableUserdata)); | 1522 | lua_pushinteger( L, sizeof( struct s_MyClonableUserdata)); |
1523 | return 1; | ||
1524 | |||
1525 | case 2: | ||
1526 | { | ||
1527 | struct s_MyClonableUserdata* self = lua_touserdata( L, 1); | ||
1528 | struct s_MyClonableUserdata* from = lua_touserdata( L, 2); | ||
1529 | *self = *from; | ||
1530 | return 0; | ||
1531 | } | ||
1532 | |||
1533 | default: | ||
1534 | (void) luaL_error( L, "Lanes called clonable_lanesclone with unexpected parameters"); | ||
1535 | } | ||
1536 | return 0; | ||
1537 | } | ||
1538 | </pre></td></tr></table> | ||
1539 | </p> | ||
1540 | |||
1541 | <p> | ||
1542 | Of course, more complex objects may require smarter cloning behavior than a simple <tt>memcpy</tt>. Also, the module initialisation code should make each metatable accessible from the module table itself as in: | ||
1543 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> | ||
1544 | int luaopen_deep_test(lua_State* L) | ||
1545 | { | ||
1546 | luaL_newlib( L, deep_module); | ||
1547 | |||
1548 | // preregister the metatables for the types we can instanciate so that Lanes can know about them | ||
1549 | if( luaL_newmetatable( L, "clonable")) | ||
1550 | { | ||
1551 | luaL_setfuncs( L, clonable_mt, 0); | ||
1552 | lua_pushvalue(L, -1); | ||
1553 | lua_setfield(L, -2, "__index"); | ||
1554 | } | ||
1555 | lua_setfield(L, -2, "__clonableMT"); // actual name is not important | ||
1556 | |||
1557 | if( luaL_newmetatable( L, "deep")) | ||
1558 | { | ||
1559 | luaL_setfuncs( L, deep_mt, 0); | ||
1560 | lua_pushvalue(L, -1); | ||
1561 | lua_setfield(L, -2, "__index"); | ||
1562 | } | ||
1563 | lua_setfield(L, -2, "__deepMT"); // actual name is not important | ||
1564 | |||
1565 | return 1; | ||
1566 | } | ||
1567 | </pre></td></tr></table> | ||
1568 | </p> | ||
1569 | |||
1570 | <p> | ||
1571 | Then a new clonable userdata instance can just do like any non-Lanes aware userdata, as long as its metatable contains the aforementionned <tt>__lanesclone</tt> method. Note that the current implementation doesn't support uservalues on such userdata. | ||
1572 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> | ||
1573 | int luaD_new_clonable( lua_State* L) | ||
1574 | { | ||
1575 | lua_newuserdata( L, sizeof( struct s_MyClonableUserdata)); | ||
1576 | luaL_setmetatable( L, "clonable"); | ||
1523 | return 1; | 1577 | return 1; |
1524 | } | 1578 | } |
1525 | </pre></td></tr></table> | 1579 | </pre></td></tr></table> |
1526 | </p> | 1580 | </p> |
1527 | Of course, more complex objects may require smarter cloning behavior than a simple <tt>memcpy</tt>. | ||
1528 | 1581 | ||
1529 | <h3 id="deep_userdata">Deep userdata in your own apps</h3> | 1582 | <h3 id="deep_userdata">Deep userdata in your own apps</h3> |
1530 | 1583 | ||
diff --git a/src/lanes.c b/src/lanes.c index d4b4c73..c3e64fb 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
@@ -2289,6 +2289,7 @@ LUAG_FUNC( lane_new) | |||
2289 | // require the module in the target state, and populate the lookup table there too | 2289 | // require the module in the target state, and populate the lookup table there too |
2290 | size_t len; | 2290 | size_t len; |
2291 | char const* name = lua_tolstring( L, -1, &len); | 2291 | char const* name = lua_tolstring( L, -1, &len); |
2292 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: require '%s'\n" INDENT_END, name)); | ||
2292 | 2293 | ||
2293 | // require the module in the target lane | 2294 | // require the module in the target lane |
2294 | lua_getglobal( L2, "require"); // require()? | 2295 | lua_getglobal( L2, "require"); // require()? |
diff --git a/src/tools.c b/src/tools.c index 2f9de7b..8e886b5 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -825,6 +825,12 @@ static int table_lookup_sentinel( lua_State* L) | |||
825 | return luaL_error( L, "table lookup sentinel for %s, should never be called", lua_tostring( L, lua_upvalueindex( 1))); | 825 | return luaL_error( L, "table lookup sentinel for %s, should never be called", lua_tostring( L, lua_upvalueindex( 1))); |
826 | } | 826 | } |
827 | 827 | ||
828 | // function sentinel used to transfer cloned full userdata from/to keeper states | ||
829 | static int userdata_clone_sentinel( lua_State* L) | ||
830 | { | ||
831 | return luaL_error( L, "userdata clone sentinel for %s, should never be called", lua_tostring( L, lua_upvalueindex( 1))); | ||
832 | } | ||
833 | |||
828 | /* | 834 | /* |
829 | * retrieve the name of a function/table in the lookup database | 835 | * retrieve the name of a function/table in the lookup database |
830 | */ | 836 | */ |
@@ -838,7 +844,7 @@ static char const* find_lookup_name( lua_State* L, uint_t i, LookupMode mode_, c | |||
838 | if( mode_ == eLM_FromKeeper) | 844 | if( mode_ == eLM_FromKeeper) |
839 | { | 845 | { |
840 | lua_CFunction f = lua_tocfunction( L, i); // should *always* be func_lookup_sentinel or table_lookup_sentinel! | 846 | lua_CFunction f = lua_tocfunction( L, i); // should *always* be func_lookup_sentinel or table_lookup_sentinel! |
841 | if( f == func_lookup_sentinel || f == table_lookup_sentinel) | 847 | if( f == func_lookup_sentinel || f == table_lookup_sentinel || f == userdata_clone_sentinel) |
842 | { | 848 | { |
843 | lua_getupvalue( L, i, 1); // ... v ... "f.q.n" | 849 | lua_getupvalue( L, i, 1); // ... v ... "f.q.n" |
844 | } | 850 | } |
@@ -1594,6 +1600,7 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu | |||
1594 | bool_t ignore = FALSE; | 1600 | bool_t ignore = FALSE; |
1595 | int val_type = lua_type( L, i); | 1601 | int val_type = lua_type( L, i); |
1596 | STACK_GROW( L2, 1); | 1602 | STACK_GROW( L2, 1); |
1603 | STACK_CHECK( L); // L // L2 | ||
1597 | STACK_CHECK( L2); // L // L2 | 1604 | STACK_CHECK( L2); // L // L2 |
1598 | 1605 | ||
1599 | /* Skip the object if it has metatable with { __lanesignore = true } */ | 1606 | /* Skip the object if it has metatable with { __lanesignore = true } */ |
@@ -1662,30 +1669,53 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu | |||
1662 | { | 1669 | { |
1663 | break; | 1670 | break; |
1664 | } | 1671 | } |
1672 | STACK_MID( L, 0); | ||
1665 | 1673 | ||
1666 | if( lua_getmetatable( L, i)) // ... mt? | 1674 | if( lua_getmetatable( L, i)) // ... mt? |
1667 | { | 1675 | { |
1668 | lua_getfield( L, -1, "__lanesclone"); // ... mt clone? | 1676 | lua_getfield( L, -1, "__lanesclone"); // ... mt __lanesclone? |
1669 | if( !lua_isnil( L, -1)) | 1677 | if( lua_isnil( L, -1)) |
1678 | { | ||
1679 | lua_pop( L, 2); // ... | ||
1680 | } | ||
1681 | else | ||
1670 | { | 1682 | { |
1683 | FuncSubType fst; | ||
1684 | lua_CFunction cloneFunc = luaG_tocfunction( L, -1, &fst); | ||
1685 | size_t userdata_size = 0; | ||
1671 | void* const source = lua_touserdata( L, i); | 1686 | void* const source = lua_touserdata( L, i); |
1687 | void* clone = NULL; | ||
1688 | lua_pushvalue( L, -1); // ... mt __lanesclone __lanesclone | ||
1689 | // call the cloning function with 0 arguments, should return the number of bytes to allocate for the clone | ||
1690 | lua_call( L, 0, 1); // ... mt __lanesclone size | ||
1691 | STACK_MID( L, 3); | ||
1692 | userdata_size = (size_t) lua_tointeger( L, -1); // ... mt __lanesclone size | ||
1693 | lua_pop( L, 1); // ... mt __lanesclone | ||
1694 | clone = lua_newuserdata( L2, userdata_size); // ... u | ||
1695 | // call cloning function in source state to perform the actual memory cloning | ||
1696 | lua_pushlightuserdata( L, clone); // ... mt __lanesclone clone | ||
1697 | lua_pushlightuserdata( L, source); // ... mt __lanesclone source | ||
1698 | lua_call( L, 2, 0); // ... mt | ||
1699 | STACK_MID( L, 1); | ||
1672 | // copy the metatable in the target state | 1700 | // copy the metatable in the target state |
1673 | if( push_cached_metatable( U, L2, L2_cache_i, L, i, mode_, upName_)) // ... mt? | 1701 | if( inter_copy_one_( U, L2, L2_cache_i, L, lua_absindex( L, -1), VT_NORMAL, mode_, upName_)) // ... u mt? |
1674 | { | 1702 | { |
1675 | // retrieve cloning function | 1703 | lua_pop( L, 1); // ... |
1676 | lua_getfield( L2, -1, "__lanesclone"); // ... mt clone | 1704 | STACK_MID( L, 0); |
1677 | lua_pushlightuserdata( L2, source); // ... mt clone p | 1705 | // when writing to a keeper state, we have here a sentinel function with the metatable's fqn as upvalue |
1678 | // cloning function should create a new full userdata without a metatable | 1706 | if( eLM_ToKeeper == mode_) // ... u sentinel |
1679 | if( lua_pcall( L2, 1, 1, 0) == LUA_OK) // ... mt u | ||
1680 | { | 1707 | { |
1681 | lua_insert( L2, -2); // ... u mt | 1708 | ASSERT_L( lua_tocfunction( L2, -1) == table_lookup_sentinel); |
1682 | lua_setmetatable( L2, -2); // ... u | 1709 | // we want to create a new closure with a 'clone sentinel' function, where the upvalues are the userdata and the metatable fqn |
1710 | lua_getupvalue( L2, -1, 1); // ... u sentinel fqn | ||
1711 | lua_remove( L2, -2); // ... u fqn | ||
1712 | lua_insert( L2, -2); // ... fqn u | ||
1713 | lua_pushcclosure( L2, userdata_clone_sentinel, 2); // ... userdata_clone_sentinel | ||
1683 | } | 1714 | } |
1684 | else // ... mt err | 1715 | else // from keeper or direct, we have the userdata and the metatable |
1685 | { | 1716 | { |
1686 | // propagate any error to the source state | 1717 | ASSERT_L( lua_istable( L2, -1)); |
1687 | char const* errmsg = lua_tostring( L2, -1); | 1718 | lua_setmetatable( L2, -2); // ... u |
1688 | (void) luaL_error( L, "can't copy non-deep full userdata across lanes: %s", errmsg); | ||
1689 | } | 1719 | } |
1690 | } | 1720 | } |
1691 | else | 1721 | else |
@@ -1693,7 +1723,6 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu | |||
1693 | (void) luaL_error( L, "Error copying a metatable"); | 1723 | (void) luaL_error( L, "Error copying a metatable"); |
1694 | } | 1724 | } |
1695 | } | 1725 | } |
1696 | lua_pop( L, 2); // ... | ||
1697 | break; | 1726 | break; |
1698 | } | 1727 | } |
1699 | 1728 | ||
@@ -1724,6 +1753,33 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu | |||
1724 | ret = FALSE; | 1753 | ret = FALSE; |
1725 | break; | 1754 | break; |
1726 | } | 1755 | } |
1756 | |||
1757 | if( lua_tocfunction( L, i) == userdata_clone_sentinel) // we are actually copying a clonable full userdata | ||
1758 | { | ||
1759 | // clone the full userdata again | ||
1760 | size_t userdata_size = 0; | ||
1761 | void* source; | ||
1762 | void* clone; | ||
1763 | // this function has 2 upvalues: the fqn of its metatable, and the userdata itself | ||
1764 | lua_getupvalue( L, i, 2); // ... u | ||
1765 | source = lua_touserdata( L, -1); | ||
1766 | lookup_table( L2, L, i, mode_, upName_); // ... u // ... mt | ||
1767 | // __lanesclone should always exist because we woudln't be restoring data from a userdata_clone_sentinel closure to begin with | ||
1768 | lua_getfield( L2, -1, "__lanesclone"); // // ... mt __lanesclone | ||
1769 | lua_pushvalue( L2, -1); // ... mt __lanesclone __lanesclone | ||
1770 | // call the cloning function with 0 arguments, should return the number of bytes to allocate for the clone | ||
1771 | lua_call( L2, 0, 1); // ... mt __lanesclone size | ||
1772 | userdata_size = (size_t) lua_tointeger( L2, -1); // ... mt __lanesclone size | ||
1773 | lua_pop( L2, 1); // ... mt __lanesclone | ||
1774 | clone = lua_newuserdata( L2, userdata_size); // ... mt __lanesclone u | ||
1775 | lua_insert( L2, -3); // ... u mt __lanesclone | ||
1776 | lua_pushlightuserdata( L2, clone); // ... u mt __lanesclone clone | ||
1777 | lua_pushlightuserdata( L2, source); // ... u mt __lanesclone clone source | ||
1778 | lua_call( L2, 2, 0); // ... u mt | ||
1779 | lua_setmetatable( L2, -2); // ... u | ||
1780 | lua_pop( L, 1); // ... | ||
1781 | } | ||
1782 | else | ||
1727 | { | 1783 | { |
1728 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "FUNCTION %s\n" INDENT_END, upName_)); | 1784 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "FUNCTION %s\n" INDENT_END, upName_)); |
1729 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 1785 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
@@ -1802,6 +1858,7 @@ static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lu | |||
1802 | } | 1858 | } |
1803 | 1859 | ||
1804 | STACK_END( L2, ret ? 1 : 0); | 1860 | STACK_END( L2, ret ? 1 : 0); |
1861 | STACK_END( L, 0); | ||
1805 | return ret; | 1862 | return ret; |
1806 | } | 1863 | } |
1807 | 1864 | ||