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-10-29 13:30:41 +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-10-29 13:30:41 +0100 |
commit | e2908369e92b14e661b16401b6389d6d4a026278 (patch) | |
tree | 2df10d504e3129d7a4006e9a83287853d41b4ccc /src | |
parent | 95ca27b5658c9b4da4ec67f6e922ff370eae05e5 (diff) | |
download | lanes-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.c | 199 |
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 | ||
1483 | static 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 | } |