aboutsummaryrefslogtreecommitdiff
path: root/src/tools.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools.cpp')
-rw-r--r--src/tools.cpp251
1 files changed, 124 insertions, 127 deletions
diff --git a/src/tools.cpp b/src/tools.cpp
index 4083a57..9207df6 100644
--- a/src/tools.cpp
+++ b/src/tools.cpp
@@ -1393,50 +1393,49 @@ static void copy_cached_func(Universe* U, Dest L2, int L2_cache_i, Source L, int
1393[[nodiscard]] static bool push_cached_metatable(Universe* U, Dest L2, int L2_cache_i, Source L, int i, LookupMode mode_, char const* upName_) 1393[[nodiscard]] static bool push_cached_metatable(Universe* U, Dest L2, int L2_cache_i, Source L, int i, LookupMode mode_, char const* upName_)
1394{ 1394{
1395 STACK_CHECK_START_REL(L, 0); 1395 STACK_CHECK_START_REL(L, 0);
1396 if( lua_getmetatable( L, i)) // ... mt 1396 if (!lua_getmetatable(L, i)) // ... mt
1397 { 1397 {
1398 lua_Integer const mt_id = get_mt_id( U, L, -1); // Unique id for the metatable 1398 STACK_CHECK( L, 0);
1399 return false;
1400 }
1401 STACK_CHECK(L, 1);
1399 1402
1400 STACK_CHECK_START_REL(L2, 0); 1403 lua_Integer const mt_id{ get_mt_id(U, L, -1) }; // Unique id for the metatable
1401 STACK_GROW( L2, 4); 1404
1402 // do we already know this metatable? 1405 STACK_CHECK_START_REL(L2, 0);
1403 push_registry_subtable( L2, REG_MTID); // _R[REG_MTID] 1406 STACK_GROW(L2, 4);
1404 lua_pushinteger( L2, mt_id); // _R[REG_MTID] id 1407 // do we already know this metatable?
1405 lua_rawget( L2, -2); // _R[REG_MTID] mt? 1408 push_registry_subtable(L2, REG_MTID); // _R[REG_MTID]
1406 1409 lua_pushinteger(L2, mt_id); // _R[REG_MTID] id
1407 STACK_CHECK( L2, 2); 1410 lua_rawget(L2, -2); // _R[REG_MTID] mt|nil
1408 1411 STACK_CHECK(L2, 2);
1409 if( lua_isnil( L2, -1)) 1412
1410 { // L2 did not know the metatable 1413 if (lua_isnil(L2, -1))
1411 lua_pop( L2, 1); // _R[REG_MTID] 1414 { // L2 did not know the metatable
1412 if (inter_copy_one(U, L2, L2_cache_i, L, lua_gettop( L), VT::METATABLE, mode_, upName_)) // _R[REG_MTID] mt 1415 lua_pop(L2, 1); // _R[REG_MTID]
1413 { 1416 if (!inter_copy_one(U, L2, L2_cache_i, L, lua_gettop(L), VT::METATABLE, mode_, upName_)) // _R[REG_MTID] mt?
1414 STACK_CHECK( L2, 2); 1417 {
1415 // mt_id -> metatable 1418 std::ignore = luaL_error(L, "Error copying a metatable"); // doesn't return
1416 lua_pushinteger( L2, mt_id); // _R[REG_MTID] mt id
1417 lua_pushvalue( L2, -2); // _R[REG_MTID] mt id mt
1418 lua_rawset( L2, -4); // _R[REG_MTID] mt
1419
1420 // metatable -> mt_id
1421 lua_pushvalue( L2, -1); // _R[REG_MTID] mt mt
1422 lua_pushinteger( L2, mt_id); // _R[REG_MTID] mt mt id
1423 lua_rawset( L2, -4); // _R[REG_MTID] mt
1424 }
1425 else
1426 {
1427 (void) luaL_error( L, "Error copying a metatable");
1428 }
1429 STACK_CHECK( L2, 2);
1430 } 1419 }
1431 lua_remove( L2, -2); // mt
1432 1420
1433 lua_pop( L, 1); // ... 1421 STACK_CHECK(L2, 2); // _R[REG_MTID] mt
1434 STACK_CHECK( L2, 1); 1422 // mt_id -> metatable
1435 STACK_CHECK( L, 0); 1423 lua_pushinteger(L2, mt_id); // _R[REG_MTID] mt id
1436 return true; 1424 lua_pushvalue(L2, -2); // _R[REG_MTID] mt id mt
1425 lua_rawset(L2, -4); // _R[REG_MTID] mt
1426
1427 // metatable -> mt_id
1428 lua_pushvalue(L2, -1); // _R[REG_MTID] mt mt
1429 lua_pushinteger(L2, mt_id); // _R[REG_MTID] mt mt id
1430 lua_rawset(L2, -4); // _R[REG_MTID] mt
1431 STACK_CHECK(L2, 2);
1437 } 1432 }
1438 STACK_CHECK( L, 0); 1433 lua_remove(L2, -2); // mt
1439 return false; 1434
1435 lua_pop(L, 1); // ...
1436 STACK_CHECK(L2, 1);
1437 STACK_CHECK(L, 0);
1438 return true;
1440} 1439}
1441 1440
1442// ################################################################################################# 1441// #################################################################################################
@@ -1599,11 +1598,10 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull };
1599 // assign uservalues 1598 // assign uservalues
1600 while( uvi > 0) 1599 while( uvi > 0)
1601 { 1600 {
1602 std::ignore = inter_copy_one(U 1601 if (!inter_copy_one(U, L2, L2_cache_i, L, lua_absindex(L, -1), VT::NORMAL, mode_, upName_)) // ... u uv
1603 , L2, L2_cache_i 1602 {
1604 , L, lua_absindex(L, -1) 1603 std::ignore = luaL_error(L, "Cannot copy upvalue type '%s'", luaL_typename(L, -1)); // doesn't return
1605 , VT::NORMAL, mode_, upName_ 1604 }
1606 ); // ... u uv
1607 lua_pop( L, 1); // ... mt __lanesclone [uv]* 1605 lua_pop( L, 1); // ... mt __lanesclone [uv]*
1608 // this pops the value from the stack 1606 // this pops the value from the stack
1609 lua_setiuservalue( L2, -2, uvi); // ... u 1607 lua_setiuservalue( L2, -2, uvi); // ... u
@@ -1644,39 +1642,39 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull };
1644 // try clonable userdata first 1642 // try clonable userdata first
1645 if( copyclone( U, L2, L2_cache_i, L, i, mode_, upName_)) 1643 if( copyclone( U, L2, L2_cache_i, L, i, mode_, upName_))
1646 { 1644 {
1647 STACK_CHECK( L, 0); 1645 STACK_CHECK(L, 0);
1648 STACK_CHECK( L2, 1); 1646 STACK_CHECK(L2, 1);
1649 return true; 1647 return true;
1650 } 1648 }
1651 1649
1652 STACK_CHECK( L, 0); 1650 STACK_CHECK(L, 0);
1653 STACK_CHECK( L2, 0); 1651 STACK_CHECK(L2, 0);
1654 1652
1655 // Allow only deep userdata entities to be copied across 1653 // Allow only deep userdata entities to be copied across
1656 DEBUGSPEW_CODE( fprintf( stderr, "USERDATA\n")); 1654 DEBUGSPEW_CODE(fprintf(stderr, "USERDATA\n"));
1657 if( copydeep( U, L2, L2_cache_i, L, i, mode_, upName_)) 1655 if (copydeep(U, L2, L2_cache_i, L, i, mode_, upName_))
1658 { 1656 {
1659 STACK_CHECK( L, 0); 1657 STACK_CHECK(L, 0);
1660 STACK_CHECK( L2, 1); 1658 STACK_CHECK(L2, 1);
1661 return true; 1659 return true;
1662 } 1660 }
1663 1661
1664 STACK_CHECK( L, 0); 1662 STACK_CHECK(L, 0);
1665 STACK_CHECK( L2, 0); 1663 STACK_CHECK(L2, 0);
1666 1664
1667 // Not a deep or clonable full userdata 1665 // Not a deep or clonable full userdata
1668 if( U->demoteFullUserdata) // attempt demotion to light userdata 1666 if (U->demoteFullUserdata) // attempt demotion to light userdata
1669 { 1667 {
1670 void* lud = lua_touserdata( L, i); 1668 void* lud = lua_touserdata(L, i);
1671 lua_pushlightuserdata( L2, lud); 1669 lua_pushlightuserdata(L2, lud);
1672 } 1670 }
1673 else // raise an error 1671 else // raise an error
1674 { 1672 {
1675 (void) luaL_error( L, "can't copy non-deep full userdata across lanes"); 1673 std::ignore = luaL_error(L, "can't copy non-deep full userdata across lanes"); // doesn't return
1676 } 1674 }
1677 1675
1678 STACK_CHECK( L2, 1); 1676 STACK_CHECK(L2, 1);
1679 STACK_CHECK( L, 0); 1677 STACK_CHECK(L, 0);
1680 return true; 1678 return true;
1681} 1679}
1682 1680
@@ -1689,91 +1687,90 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull };
1689 return false; 1687 return false;
1690 } 1688 }
1691 1689
1692 STACK_CHECK_START_REL(L, 0); // L (source) // L2 (destination) 1690 STACK_CHECK_START_REL(L, 0); // L (source) // L2 (destination)
1693 STACK_CHECK_START_REL(L2, 0); 1691 STACK_CHECK_START_REL(L2, 0);
1694 DEBUGSPEW_CODE( fprintf( stderr, "FUNCTION %s\n", upName_)); 1692 DEBUGSPEW_CODE(fprintf(stderr, "FUNCTION %s\n", upName_));
1695 1693
1696 if( lua_tocfunction( L, source_i_) == userdata_clone_sentinel) // we are actually copying a clonable full userdata from a keeper 1694 if (lua_tocfunction(L, source_i_) == userdata_clone_sentinel) // we are actually copying a clonable full userdata from a keeper
1697 { 1695 {
1698 // clone the full userdata again 1696 // clone the full userdata again
1699 1697
1700 // let's see if we already restored this userdata 1698 // let's see if we already restored this userdata
1701 lua_getupvalue( L, source_i_, 2); // ... u 1699 lua_getupvalue(L, source_i_, 2); // ... u
1702 void* source = lua_touserdata( L, -1); 1700 void* source = lua_touserdata(L, -1);
1703 lua_pushlightuserdata( L2, source); // ... source 1701 lua_pushlightuserdata(L2, source); // ... source
1704 lua_rawget( L2, L2_cache_i); // ... u? 1702 lua_rawget(L2, L2_cache_i); // ... u?
1705 if( !lua_isnil( L2, -1)) 1703 if (!lua_isnil(L2, -1))
1706 { 1704 {
1707 lua_pop( L, 1); // ... 1705 lua_pop(L, 1); // ...
1708 STACK_CHECK( L, 0); 1706 STACK_CHECK(L, 0);
1709 STACK_CHECK( L2, 1); 1707 STACK_CHECK(L2, 1);
1710 return true; 1708 return true;
1711 } 1709 }
1712 lua_pop( L2, 1); // ... 1710 lua_pop(L2, 1); // ...
1713 1711
1714 // this function has 2 upvalues: the fqn of its metatable, and the userdata itself 1712 // this function has 2 upvalues: the fqn of its metatable, and the userdata itself
1715 std::ignore = lookup_table( L2, L, source_i_, mode_, upName_); // ... mt 1713 std::ignore = lookup_table(L2, L, source_i_, mode_, upName_); // ... mt
1716 // originally 'source_i_' slot was the proxy closure, but from now on it indexes the actual userdata we extracted from it 1714 // originally 'source_i_' slot was the proxy closure, but from now on it indexes the actual userdata we extracted from it
1717 source_i_ = lua_gettop( L); 1715 source_i_ = lua_gettop(L);
1718 source = lua_touserdata( L, -1); 1716 source = lua_touserdata(L, -1);
1719 void* clone{ nullptr }; 1717 void* clone{ nullptr };
1720 // get the number of bytes to allocate for the clone 1718 // get the number of bytes to allocate for the clone
1721 size_t const userdata_size { lua_rawlen(L, -1) }; 1719 size_t const userdata_size{ lua_rawlen(L, -1) };
1722 { 1720 {
1723 // extract uservalues (don't transfer them yet) 1721 // extract uservalues (don't transfer them yet)
1724 int uvi = 0; 1722 int uvi = 0;
1725 while( lua_getiuservalue( L, source_i_, ++ uvi) != LUA_TNONE) {} // ... u uv 1723 while (lua_getiuservalue(L, source_i_, ++uvi) != LUA_TNONE) {} // ... u uv
1726 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now 1724 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now
1727 lua_pop( L, 1); // ... u [uv]* 1725 lua_pop(L, 1); // ... u [uv]*
1728 -- uvi; 1726 --uvi;
1729 STACK_CHECK( L, uvi + 1); 1727 STACK_CHECK(L, uvi + 1);
1730 // create the clone userdata with the required number of uservalue slots 1728 // create the clone userdata with the required number of uservalue slots
1731 clone = lua_newuserdatauv( L2, userdata_size, uvi); // ... mt u 1729 clone = lua_newuserdatauv(L2, userdata_size, uvi); // ... mt u
1732 // add it in the cache 1730 // add it in the cache
1733 lua_pushlightuserdata( L2, source); // ... mt u source 1731 lua_pushlightuserdata(L2, source); // ... mt u source
1734 lua_pushvalue( L2, -2); // ... mt u source u 1732 lua_pushvalue(L2, -2); // ... mt u source u
1735 lua_rawset( L2, L2_cache_i); // ... mt u 1733 lua_rawset(L2, L2_cache_i); // ... mt u
1736 // set metatable 1734 // set metatable
1737 lua_pushvalue( L2, -2); // ... mt u mt 1735 lua_pushvalue(L2, -2); // ... mt u mt
1738 lua_setmetatable( L2, -2); // ... mt u 1736 lua_setmetatable(L2, -2); // ... mt u
1739 // transfer and assign uservalues 1737 // transfer and assign uservalues
1740 while( uvi > 0) 1738 while (uvi > 0)
1741 { 1739 {
1742 std::ignore = inter_copy_one(U 1740 if (!inter_copy_one(U, L2, L2_cache_i, L, lua_absindex(L, -1), vt_, mode_, upName_)) // ... mt u uv
1743 , L2, L2_cache_i 1741 {
1744 , L, lua_absindex(L, -1) 1742 std::ignore = luaL_error(L, "Cannot copy upvalue type '%s'", luaL_typename(L, -1)); // doesn't return
1745 , vt_, mode_, upName_ 1743 }
1746 ); // ... mt u uv 1744 lua_pop(L, 1); // ... u [uv]*
1747 lua_pop( L, 1); // ... u [uv]*
1748 // this pops the value from the stack 1745 // this pops the value from the stack
1749 lua_setiuservalue( L2, -2, uvi); // ... mt u 1746 lua_setiuservalue(L2, -2, uvi); // ... mt u
1750 -- uvi; 1747 -- uvi;
1751 } 1748 }
1752 // when we are done, all uservalues are popped from the stack, we can pop the source as well 1749 // when we are done, all uservalues are popped from the stack, we can pop the source as well
1753 lua_pop( L, 1); // ... 1750 lua_pop(L, 1); // ...
1754 STACK_CHECK( L, 0); 1751 STACK_CHECK(L, 0);
1755 STACK_CHECK( L2, 2); // ... mt u 1752 STACK_CHECK(L2, 2); // ... mt u
1756 } 1753 }
1757 // perform the custom cloning part 1754 // perform the custom cloning part
1758 lua_insert( L2, -2); // ... u mt 1755 lua_insert(L2, -2); // ... u mt
1759 // __lanesclone should always exist because we wouldn't be restoring data from a userdata_clone_sentinel closure to begin with 1756 // __lanesclone should always exist because we wouldn't be restoring data from a userdata_clone_sentinel closure to begin with
1760 lua_getfield(L2, -1, "__lanesclone"); // ... u mt __lanesclone 1757 lua_getfield(L2, -1, "__lanesclone"); // ... u mt __lanesclone
1761 lua_remove( L2, -2); // ... u __lanesclone 1758 lua_remove(L2, -2); // ... u __lanesclone
1762 lua_pushlightuserdata( L2, clone); // ... u __lanesclone clone 1759 lua_pushlightuserdata(L2, clone); // ... u __lanesclone clone
1763 lua_pushlightuserdata( L2, source); // ... u __lanesclone clone source 1760 lua_pushlightuserdata(L2, source); // ... u __lanesclone clone source
1764 lua_pushinteger( L2, userdata_size); // ... u __lanesclone clone source size 1761 lua_pushinteger(L2, userdata_size); // ... u __lanesclone clone source size
1765 // clone:__lanesclone(dest, source, size) 1762 // clone:__lanesclone(dest, source, size)
1766 lua_call( L2, 3, 0); // ... u 1763 lua_call(L2, 3, 0); // ... u
1767 } 1764 }
1768 else // regular function 1765 else // regular function
1769 { 1766 {
1770 DEBUGSPEW_CODE(fprintf( stderr, "FUNCTION %s\n", upName_)); 1767 DEBUGSPEW_CODE(fprintf( stderr, "FUNCTION %s\n", upName_));
1771 DEBUGSPEW_CODE(U->debugspew_indent_depth.fetch_add(1, std::memory_order_relaxed)); 1768 DEBUGSPEW_CODE(U->debugspew_indent_depth.fetch_add(1, std::memory_order_relaxed));
1772 copy_cached_func( U, L2, L2_cache_i, L, source_i_, mode_, upName_); // ... f 1769 copy_cached_func(U, L2, L2_cache_i, L, source_i_, mode_, upName_); // ... f
1773 DEBUGSPEW_CODE(U->debugspew_indent_depth.fetch_sub(1, std::memory_order_relaxed)); 1770 DEBUGSPEW_CODE(U->debugspew_indent_depth.fetch_sub(1, std::memory_order_relaxed));
1774 } 1771 }
1775 STACK_CHECK( L2, 1); 1772 STACK_CHECK(L2, 1);
1776 STACK_CHECK( L, 0); 1773 STACK_CHECK(L, 0);
1777 return true; 1774 return true;
1778} 1775}
1779 1776
@@ -1788,15 +1785,15 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull };
1788 1785
1789 STACK_CHECK_START_REL(L, 0); 1786 STACK_CHECK_START_REL(L, 0);
1790 STACK_CHECK_START_REL(L2, 0); 1787 STACK_CHECK_START_REL(L2, 0);
1791 DEBUGSPEW_CODE( fprintf( stderr, "TABLE %s\n", upName_)); 1788 DEBUGSPEW_CODE(fprintf(stderr, "TABLE %s\n", upName_));
1792 1789
1793 /* 1790 /*
1794 * First, let's try to see if this table is special (aka is it some table that we registered in our lookup databases during module registration?) 1791 * First, let's try to see if this table is special (aka is it some table that we registered in our lookup databases during module registration?)
1795 * Note that this table CAN be a module table, but we just didn't register it, in which case we'll send it through the table cloning mechanism 1792 * Note that this table CAN be a module table, but we just didn't register it, in which case we'll send it through the table cloning mechanism
1796 */ 1793 */
1797 if( lookup_table( L2, L, i, mode_, upName_)) 1794 if (lookup_table(L2, L, i, mode_, upName_))
1798 { 1795 {
1799 ASSERT_L( lua_istable( L2, -1) || (lua_tocfunction( L2, -1) == table_lookup_sentinel)); // from lookup datables // can also be table_lookup_sentinel if this is a table we know 1796 ASSERT_L(lua_istable(L2, -1) || (lua_tocfunction(L2, -1) == table_lookup_sentinel)); // from lookup data. can also be table_lookup_sentinel if this is a table we know
1800 return true; 1797 return true;
1801 } 1798 }
1802 1799
@@ -1809,33 +1806,33 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull };
1809 * Note: Even metatables need to go through this test; to detect 1806 * Note: Even metatables need to go through this test; to detect
1810 * loops such as those in required module tables (getmetatable(lanes).lanes == lanes) 1807 * loops such as those in required module tables (getmetatable(lanes).lanes == lanes)
1811 */ 1808 */
1812 if( push_cached_table( L2, L2_cache_i, L, i)) 1809 if (push_cached_table(L2, L2_cache_i, L, i))
1813 { 1810 {
1814 ASSERT_L( lua_istable( L2, -1)); // from cache 1811 ASSERT_L(lua_istable(L2, -1)); // from cache
1815 return true; 1812 return true;
1816 } 1813 }
1817 ASSERT_L( lua_istable( L2, -1)); 1814 ASSERT_L(lua_istable(L2, -1));
1818 1815
1819 STACK_GROW( L, 2); 1816 STACK_GROW(L, 2);
1820 STACK_GROW( L2, 2); 1817 STACK_GROW(L2, 2);
1821 1818
1822 lua_pushnil( L); // start iteration 1819 lua_pushnil(L); // start iteration
1823 while( lua_next( L, i)) 1820 while (lua_next(L, i))
1824 { 1821 {
1825 // need a function to prevent overflowing the stack with verboseErrors-induced alloca() 1822 // need a function to prevent overflowing the stack with verboseErrors-induced alloca()
1826 inter_copy_keyvaluepair(U, L2, L2_cache_i, L, vt_, mode_, upName_); 1823 inter_copy_keyvaluepair(U, L2, L2_cache_i, L, vt_, mode_, upName_);
1827 lua_pop( L, 1); // pop value (next round) 1824 lua_pop(L, 1); // pop value (next round)
1828 } 1825 }
1829 STACK_CHECK( L, 0); 1826 STACK_CHECK(L, 0);
1830 STACK_CHECK( L2, 1); 1827 STACK_CHECK(L2, 1);
1831 1828
1832 // Metatables are expected to be immutable, and copied only once. 1829 // Metatables are expected to be immutable, and copied only once.
1833 if( push_cached_metatable( U, L2, L2_cache_i, L, i, mode_, upName_)) // ... t mt? 1830 if (push_cached_metatable(U, L2, L2_cache_i, L, i, mode_, upName_)) // ... t mt?
1834 { 1831 {
1835 lua_setmetatable( L2, -2); // ... t 1832 lua_setmetatable(L2, -2); // ... t
1836 } 1833 }
1837 STACK_CHECK( L2, 1); 1834 STACK_CHECK(L2, 1);
1838 STACK_CHECK( L, 0); 1835 STACK_CHECK(L, 0);
1839 return true; 1836 return true;
1840} 1837}
1841 1838