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 | ||
