aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m>2018-10-29 13:30:41 +0100
committerBenoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m>2018-10-29 13:30:41 +0100
commite2908369e92b14e661b16401b6389d6d4a026278 (patch)
tree2df10d504e3129d7a4006e9a83287853d41b4ccc
parent95ca27b5658c9b4da4ec67f6e922ff370eae05e5 (diff)
downloadlanes-e2908369e92b14e661b16401b6389d6d4a026278.tar.gz
lanes-e2908369e92b14e661b16401b6389d6d4a026278.tar.bz2
lanes-e2908369e92b14e661b16401b6389d6d4a026278.zip
add support for deep userdata cloning
-rw-r--r--deep_test/deep_test.c63
-rw-r--r--deep_test/deep_test.lua17
-rw-r--r--src/tools.c199
3 files changed, 181 insertions, 98 deletions
diff --git a/deep_test/deep_test.c b/deep_test/deep_test.c
index abe9fdc..8f34fe5 100644
--- a/deep_test/deep_test.c
+++ b/deep_test/deep_test.c
@@ -1,4 +1,5 @@
1#include <malloc.h> 1#include <malloc.h>
2#include <memory.h>
2 3
3#include "lua.h" 4#include "lua.h"
4#include "lualib.h" 5#include "lualib.h"
@@ -12,6 +13,8 @@
12#define LANES_API 13#define LANES_API
13#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 14#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
14 15
16// ################################################################################################
17
15struct s_MyDeepUserdata 18struct s_MyDeepUserdata
16{ 19{
17 lua_Integer val; 20 lua_Integer val;
@@ -33,7 +36,7 @@ static int deep_set( lua_State* L)
33static int deep_tostring( lua_State* L) 36static int deep_tostring( lua_State* L)
34{ 37{
35 struct s_MyDeepUserdata* self = luaG_todeep( L, deep_test_id, 1); 38 struct s_MyDeepUserdata* self = luaG_todeep( L, deep_test_id, 1);
36 lua_pushfstring( L, "deep_test(%d)", self->val); 39 lua_pushfstring( L, "deep(%d)", self->val);
37 return 1; 40 return 1;
38} 41}
39 42
@@ -103,10 +106,68 @@ int luaD_new_deep( lua_State* L)
103} 106}
104 107
105// ################################################################################################ 108// ################################################################################################
109// ################################################################################################
110
111struct s_MyClonableUserdata
112{
113 lua_Integer val;
114};
115
116// ################################################################################################
117
118static int clonable_tostring(lua_State* L)
119{
120 struct s_MyClonableUserdata* self = (struct s_MyClonableUserdata*) lua_touserdata( L, 1);
121 lua_pushfstring( L, "clonable(%d)", self->val);
122 return 1;
123}
124
125// ################################################################################################
126
127static int clonable_lanesclone( lua_State* L)
128{
129 // no need to set the metatable, the Lane copying mechanism will take care of it
130 struct s_MyClonableUserdata* self = lua_touserdata( L, 1);
131 struct s_MyClonableUserdata* to = lua_newuserdata( L, sizeof( struct s_MyClonableUserdata));
132 memcpy( to, self, sizeof(struct s_MyClonableUserdata));
133 return 1;
134}
135
136// ################################################################################################
137
138static luaL_Reg const clonable_mt[] =
139{
140 { "__tostring", clonable_tostring},
141 //{ "__gc", deep_gc},
142 { "__lanesclone", clonable_lanesclone},
143 //{ "set", deep_set},
144 { NULL, NULL }
145};
146
147// ################################################################################################
148
149int luaD_new_clonable( lua_State* L)
150{
151 lua_newuserdata( L, sizeof( struct s_MyClonableUserdata));
152 if( luaL_getmetatable( L, "clonable") == LUA_TNIL) // u mt?
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;
162}
163
164// ################################################################################################
165// ################################################################################################
106 166
107static luaL_Reg const deep_module[] = 167static luaL_Reg const deep_module[] =
108{ 168{
109 { "new_deep", luaD_new_deep}, 169 { "new_deep", luaD_new_deep},
170 { "new_clonable", luaD_new_clonable},
110 { NULL, NULL} 171 { NULL, NULL}
111}; 172};
112 173
diff --git a/deep_test/deep_test.lua b/deep_test/deep_test.lua
index fd78115..3b514dd 100644
--- a/deep_test/deep_test.lua
+++ b/deep_test/deep_test.lua
@@ -4,12 +4,19 @@ local deep = dt.new_deep()
4deep:set(666) 4deep:set(666)
5print( deep) 5print( deep)
6 6
7local clonable = dt.new_clonable()
8
7-- now load Lanes and see if that userdata is transferable 9-- now load Lanes and see if that userdata is transferable
8--[[ 10--[[
9local lanes = require("lanes").configure() 11local lanes = require("lanes").configure()
10
11local l = lanes.linda "my linda" 12local l = lanes.linda "my linda"
12l.put( "key", deep) 13
13local out = l.get( "key") 14l:set( "key", deep)
14print( out) 15local deep_out = l:get( "key")
15]] \ No newline at end of file 16print( deep_out)
17
18lanes.register()
19l:set( "key", clonable)
20local clonable_out = l:get( "key")
21print( clonable_out)
22--]] \ No newline at end of file
diff --git a/src/tools.c b/src/tools.c
index 9403fd6..13e714d 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -1480,6 +1480,52 @@ static void push_cached_func( struct s_Universe* U, lua_State* L2, uint_t L2_cac
1480 } 1480 }
1481} 1481}
1482 1482
1483static bool_t push_cached_metatable( struct s_Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_)
1484{
1485 if( lua_getmetatable( L, i)) // ... mt
1486 {
1487 uint_t const mt_id = get_mt_id( U, L, -1); // Unique id for the metatable
1488
1489 STACK_CHECK( L2);
1490 STACK_GROW( L2, 4);
1491 // do we already know this metatable?
1492 push_registry_subtable( L2, REG_MTID); // rst
1493 lua_pushinteger( L2, mt_id); // rst id
1494 lua_rawget( L2, -2); // rst mt?
1495
1496 STACK_MID( L2, 2);
1497
1498 if( lua_isnil( L2, -1))
1499 { // L2 did not know the metatable
1500 lua_pop( L2, 1); // rst
1501 if( inter_copy_one_( U, L2, L2_cache_i, L, lua_gettop( L), VT_METATABLE, mode_, upName_)) // rst mt
1502 {
1503 STACK_MID( L2, 2);
1504 // mt_id -> metatable
1505 lua_pushinteger( L2, mt_id); // rst mt id
1506 lua_pushvalue( L2, -2); // rst mt id mt
1507 lua_rawset( L2, -4); // rst mt
1508
1509 // metatable -> mt_id
1510 lua_pushvalue( L2, -1); // rst mt mt
1511 lua_pushinteger( L2, mt_id); // rst mt mt id
1512 lua_rawset( L2, -4); // rst mt
1513 }
1514 else
1515 {
1516 (void) luaL_error( L, "Error copying a metatable");
1517 }
1518 STACK_MID( L2, 2);
1519 }
1520 lua_remove( L2, -2); // mt
1521
1522 lua_pop( L, 1); // ...
1523 STACK_END( L2, 1);
1524 return TRUE;
1525 }
1526 return FALSE;
1527}
1528
1483/* 1529/*
1484* Copies a value from 'L' state (at index 'i') to 'L2' state. Does not remove 1530* Copies a value from 'L' state (at index 'i') to 'L2' state. Does not remove
1485* the original value. 1531* the original value.
@@ -1496,17 +1542,17 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca
1496 bool_t ignore = FALSE; 1542 bool_t ignore = FALSE;
1497 int val_type = lua_type( L, i); 1543 int val_type = lua_type( L, i);
1498 STACK_GROW( L2, 1); 1544 STACK_GROW( L2, 1);
1499 STACK_CHECK( L2); 1545 STACK_CHECK( L2); // L // L2
1500 1546
1501 /* Skip the object if it has metatable with { __lanesignore = true } */ 1547 /* Skip the object if it has metatable with { __lanesignore = true } */
1502 if( lua_getmetatable( L, i)) // ... mt 1548 if( lua_getmetatable( L, i)) // ... mt
1503 { 1549 {
1504 lua_getfield( L, -1, "__lanesignore"); // ... mt ignore? 1550 lua_getfield( L, -1, "__lanesignore"); // ... mt ignore?
1505 if( lua_isboolean( L, -1) && lua_toboolean( L, -1)) 1551 if( lua_isboolean( L, -1) && lua_toboolean( L, -1))
1506 { 1552 {
1507 val_type = LUA_TNIL; 1553 val_type = LUA_TNIL;
1508 } 1554 }
1509 lua_pop( L, 2); // ... 1555 lua_pop( L, 2); // ...
1510 } 1556 }
1511 1557
1512 /* Lets push nil to L2 if the object should be ignored */ 1558 /* Lets push nil to L2 if the object should be ignored */
@@ -1563,27 +1609,61 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca
1563 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "USERDATA\n" INDENT_END)); 1609 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "USERDATA\n" INDENT_END));
1564 if( !copydeep( U, L, L2, i, mode_)) 1610 if( !copydeep( U, L, L2, i, mode_))
1565 { 1611 {
1566 // Not a deep full userdata 1612 if( lua_getmetatable( L, i)) // ... mt?
1567 bool_t demote = FALSE;
1568 lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY);
1569 if( lua_istable( L, -1)) // should not happen, but who knows...
1570 {
1571 lua_getfield( L, -1, "demote_full_userdata");
1572 demote = lua_toboolean( L, -1);
1573 lua_pop( L, 2);
1574 }
1575 else
1576 {
1577 lua_pop( L, 1);
1578 }
1579 if( demote) // attempt demotion to light userdata
1580 { 1613 {
1581 void* lud = lua_touserdata( L, i); 1614 lua_getfield( L, -1, "__lanesclone"); // ... mt clone?
1582 lua_pushlightuserdata( L2, lud); 1615 if( !lua_isnil( L, -1))
1616 {
1617 void* const source = lua_touserdata( L, i);
1618 // copy the metatable in the target state
1619 if( push_cached_metatable( U, L2, L2_cache_i, L, i, mode_, upName_)) // ... mt?
1620 {
1621 // retrieve cloning function
1622 lua_getfield( L2, -1, "__lanesclone"); // ... mt clone
1623 lua_pushlightuserdata( L2, source); // ... mt clone p
1624 // cloning function should create a new full userdata without a metatable
1625 if( lua_pcall( L2, 1, 1, 0) == LUA_OK) // ... mt u
1626 {
1627 lua_insert( L2, -2); // ... u mt
1628 lua_setmetatable( L2, -2); // ... u
1629 }
1630 else // ... mt err
1631 {
1632 // propagate any error to the source state
1633 char const* errmsg = lua_tostring( L2, -1);
1634 (void) luaL_error( L, "can't copy non-deep full userdata across lanes: %s", errmsg);
1635 }
1636 }
1637 else
1638 {
1639 (void) luaL_error( L, "Error copying a metatable");
1640 }
1641 }
1642 lua_pop( L, 2); // ...
1583 } 1643 }
1584 else // raise an error
1585 { 1644 {
1586 (void) luaL_error( L, "can't copy non-deep full userdata across lanes"); 1645 // Not a deep or clonable full userdata
1646 bool_t demote = FALSE;
1647 lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY);
1648 if( lua_istable( L, -1)) // should not happen, but who knows...
1649 {
1650 lua_getfield( L, -1, "demote_full_userdata");
1651 demote = lua_toboolean( L, -1);
1652 lua_pop( L, 2);
1653 }
1654 else
1655 {
1656 lua_pop( L, 1);
1657 }
1658 if( demote) // attempt demotion to light userdata
1659 {
1660 void* lud = lua_touserdata( L, i);
1661 lua_pushlightuserdata( L2, lud);
1662 }
1663 else // raise an error
1664 {
1665 (void) luaL_error( L, "can't copy non-deep full userdata across lanes");
1666 }
1587 } 1667 }
1588 } 1668 }
1589 break; 1669 break;
@@ -1687,7 +1767,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca
1687 } 1767 }
1688 else 1768 else
1689 { 1769 {
1690 luaL_error( L, "Unable to copy over type '%s' (in %s)", luaL_typename( L, val_i), (vt == VT_NORMAL) ? "table" : "metatable"); 1770 (void) luaL_error( L, "Unable to copy over type '%s' (in %s)", luaL_typename( L, val_i), (vt == VT_NORMAL) ? "table" : "metatable");
1691 } 1771 }
1692 } 1772 }
1693 lua_pop( L, 1); // pop value (next round) 1773 lua_pop( L, 1); // pop value (next round)
@@ -1695,75 +1775,10 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca
1695 STACK_MID( L, 0); 1775 STACK_MID( L, 0);
1696 STACK_MID( L2, 1); 1776 STACK_MID( L2, 1);
1697 1777
1698 /* Metatables are expected to be immutable, and copied only once. 1778 // Metatables are expected to be immutable, and copied only once.
1699 */ 1779 if( push_cached_metatable( U, L2, L2_cache_i, L, i, mode_, upName_)) // ... t mt?
1700 if( lua_getmetatable( L, i))
1701 { 1780 {
1702 // 1781 lua_setmetatable( L2, -2); // ... t
1703 // L [-1]: metatable
1704
1705 uint_t mt_id = get_mt_id( U, L, -1); // Unique id for the metatable
1706
1707 STACK_GROW( L2, 4);
1708
1709 push_registry_subtable( L2, REG_MTID);
1710 STACK_MID( L2, 2);
1711 lua_pushinteger( L2, mt_id);
1712 lua_rawget( L2, -2);
1713 //
1714 // L2 ([-3]: copied table)
1715 // [-2]: reg[REG_MTID]
1716 // [-1]: nil/metatable pre-known in L2
1717
1718 STACK_MID( L2, 3);
1719
1720 if( lua_isnil( L2, -1))
1721 { /* L2 did not know the metatable */
1722 lua_pop( L2, 1);
1723 STACK_MID( L2, 2);
1724 ASSERT_L( lua_istable( L,-1));
1725 if( inter_copy_one_( U, L2, L2_cache_i /*for function cacheing*/, L, lua_gettop( L) /*[-1]*/, VT_METATABLE, mode_, upName_))
1726 {
1727 //
1728 // L2 ([-3]: copied table)
1729 // [-2]: reg[REG_MTID]
1730 // [-1]: metatable (copied from L)
1731
1732 STACK_MID( L2, 3);
1733 // mt_id -> metatable
1734 //
1735 lua_pushinteger( L2, mt_id);
1736 lua_pushvalue( L2, -2);
1737 lua_rawset( L2, -4);
1738
1739 // metatable -> mt_id
1740 //
1741 lua_pushvalue( L2, -1);
1742 lua_pushinteger( L2, mt_id);
1743 lua_rawset( L2, -4);
1744
1745 STACK_MID( L2, 3);
1746 }
1747 else
1748 {
1749 luaL_error( L, "Error copying a metatable");
1750 }
1751 STACK_MID( L2, 3);
1752 }
1753 // L2 ([-3]: copied table)
1754 // [-2]: reg[REG_MTID]
1755 // [-1]: metatable (pre-known or copied from L)
1756
1757 lua_remove( L2, -2); // take away 'reg[REG_MTID]'
1758 //
1759 // L2: ([-2]: copied table)
1760 // [-1]: metatable for that table
1761
1762 lua_setmetatable( L2, -2);
1763
1764 // L2: [-1]: copied table (with metatable set if source had it)
1765
1766 lua_pop( L, 1); // remove source metatable (L, not L2!)
1767 } 1782 }
1768 STACK_END( L2, 1); 1783 STACK_END( L2, 1);
1769 STACK_END( L, 0); 1784 STACK_END( L, 0);
@@ -1773,7 +1788,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca
1773 /* The following types cannot be copied */ 1788 /* The following types cannot be copied */
1774 1789
1775 case 10: // LuaJIT CDATA 1790 case 10: // LuaJIT CDATA
1776 case LUA_TTHREAD: 1791 case LUA_TTHREAD:
1777 ret = FALSE; 1792 ret = FALSE;
1778 break; 1793 break;
1779 } 1794 }