aboutsummaryrefslogtreecommitdiff
path: root/src
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 /src
parent95ca27b5658c9b4da4ec67f6e922ff370eae05e5 (diff)
downloadlanes-e2908369e92b14e661b16401b6389d6d4a026278.tar.gz
lanes-e2908369e92b14e661b16401b6389d6d4a026278.tar.bz2
lanes-e2908369e92b14e661b16401b6389d6d4a026278.zip
add support for deep userdata cloning
Diffstat (limited to 'src')
-rw-r--r--src/tools.c199
1 files changed, 107 insertions, 92 deletions
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 }