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> | 2013-09-26 21:11:24 +0200 |
---|---|---|
committer | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2013-09-26 21:11:24 +0200 |
commit | f823c6887e28c815234f8b4bd355887b4f554857 (patch) | |
tree | 862b37cc93d6779c3c2577e78ed6ff5389412f90 /src/tools.c | |
parent | c97ad8630ea9dcb92b4e9db16c4dbade1de18884 (diff) | |
download | lanes-f823c6887e28c815234f8b4bd355887b4f554857.tar.gz lanes-f823c6887e28c815234f8b4bd355887b4f554857.tar.bz2 lanes-f823c6887e28c815234f8b4bd355887b4f554857.zip |
Reduce memory footprint, simplify module order setup in conjuction with Lanes, and send over native functions a bit faster as well
* Lanes no longer has to internally require modules inside the keeper
states because they no longer need a lookup database. the lookup name is
stored as-is and actually converted in the destination state
*
optimisation: bypass cache when sending native functions over
* removed
all the KEEPER_MODEL_LUA code, as it can no longer work anyway
Diffstat (limited to 'src/tools.c')
-rw-r--r-- | src/tools.c | 446 |
1 files changed, 230 insertions, 216 deletions
diff --git a/src/tools.c b/src/tools.c index a3cc6b7..a957f41 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -515,8 +515,6 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* _name) | |||
515 | * Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL. | 515 | * Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL. |
516 | * | 516 | * |
517 | */ | 517 | */ |
518 | extern void register_core_libfuncs_for_keeper( lua_State* L); | ||
519 | |||
520 | lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs) | 518 | lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs) |
521 | { | 519 | { |
522 | // reuse alloc function from the originating state | 520 | // reuse alloc function from the originating state |
@@ -534,6 +532,7 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con | |||
534 | { | 532 | { |
535 | return L; | 533 | return L; |
536 | } | 534 | } |
535 | // if we are here, no keeper state is involved (because libs == NULL when we init keepers) | ||
537 | 536 | ||
538 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END)); | 537 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END)); |
539 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | 538 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
@@ -549,9 +548,8 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con | |||
549 | if( libs) | 548 | if( libs) |
550 | { | 549 | { |
551 | // special "*" case (mainly to help with LuaJIT compatibility) | 550 | // special "*" case (mainly to help with LuaJIT compatibility) |
552 | // "K" is used when opening keeper states: almost the same as "*", but for the fact we don't open lanes.core | ||
553 | // as we are called from luaopen_lanes_core() already, and that would deadlock | 551 | // as we are called from luaopen_lanes_core() already, and that would deadlock |
554 | if( (libs[0] == '*' || libs[0] == 'K') && libs[1] == 0) | 552 | if( libs[0] == '*' && libs[1] == 0) |
555 | { | 553 | { |
556 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); | 554 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); |
557 | luaL_openlibs( L); | 555 | luaL_openlibs( L); |
@@ -560,12 +558,6 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con | |||
560 | // don't forget lanes.core for regular lane states | 558 | // don't forget lanes.core for regular lane states |
561 | open1lib( L, "lanes.core", 10); | 559 | open1lib( L, "lanes.core", 10); |
562 | } | 560 | } |
563 | else | ||
564 | { | ||
565 | // In keeper states however, we only want to register the lanes.core functions to be able to transfer them through lindas | ||
566 | // (we don't care about a full lanes.core init in the keeper states as we won't call anything in there) | ||
567 | register_core_libfuncs_for_keeper( L); | ||
568 | } | ||
569 | libs = NULL; // done with libs | 561 | libs = NULL; // done with libs |
570 | } | 562 | } |
571 | else | 563 | else |
@@ -622,7 +614,7 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con | |||
622 | STACK_CHECK( _from); | 614 | STACK_CHECK( _from); |
623 | // Lua function: transfer as usual (should work as long as it only uses base libraries) | 615 | // Lua function: transfer as usual (should work as long as it only uses base libraries) |
624 | lua_pushvalue( _from, _on_state_create); | 616 | lua_pushvalue( _from, _on_state_create); |
625 | luaG_inter_move( _from, L, 1); | 617 | luaG_inter_move( _from, L, 1, eLM_LaneBody); |
626 | STACK_END( _from, 0); | 618 | STACK_END( _from, 0); |
627 | } | 619 | } |
628 | // capture error and forward it to main state | 620 | // capture error and forward it to main state |
@@ -1283,59 +1275,6 @@ static bool_t push_cached_table( lua_State *L2, uint_t L2_cache_i, lua_State *L, | |||
1283 | } | 1275 | } |
1284 | 1276 | ||
1285 | 1277 | ||
1286 | /* | ||
1287 | * Check if we've already copied the same function from 'L', and reuse the old | ||
1288 | * copy. | ||
1289 | * | ||
1290 | * Always pushes a function to 'L2'. | ||
1291 | */ | ||
1292 | static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, char const* upName_); | ||
1293 | |||
1294 | static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, char const* upName_) | ||
1295 | { | ||
1296 | void* const aspointer = (void*)lua_topointer( L, i); | ||
1297 | // TBD: Merge this and same code for tables | ||
1298 | ASSERT_L( L2_cache_i != 0); | ||
1299 | |||
1300 | STACK_GROW( L2, 2); | ||
1301 | |||
1302 | // L2_cache[id_str]= function | ||
1303 | // | ||
1304 | STACK_CHECK( L2); | ||
1305 | |||
1306 | // We don't need to use the from state ('L') in ID since the life span | ||
1307 | // is only for the duration of a copy (both states are locked). | ||
1308 | // | ||
1309 | |||
1310 | // push a light userdata uniquely representing the function | ||
1311 | lua_pushlightuserdata( L2, aspointer); // ... {cache} ... p | ||
1312 | |||
1313 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); | ||
1314 | |||
1315 | lua_pushvalue( L2, -1); // ... {cache} ... p p | ||
1316 | lua_rawget( L2, L2_cache_i); // ... {cache} ... p function|nil|true | ||
1317 | |||
1318 | if( lua_isnil(L2,-1)) // function is unknown | ||
1319 | { | ||
1320 | lua_pop( L2, 1); // ... {cache} ... p | ||
1321 | |||
1322 | // Set to 'true' for the duration of creation; need to find self-references | ||
1323 | // via upvalues | ||
1324 | // | ||
1325 | // pushes a copy of the func, stores a reference in the cache | ||
1326 | inter_copy_func( L2, L2_cache_i, L, i, upName_); // ... {cache} ... function | ||
1327 | } | ||
1328 | else // found function in the cache | ||
1329 | { | ||
1330 | lua_remove( L2, -2); // ... {cache} ... function | ||
1331 | } | ||
1332 | STACK_END( L2, 1); | ||
1333 | // | ||
1334 | // L2 [-1]: function | ||
1335 | |||
1336 | ASSERT_L( lua_isfunction( L2, -1)); | ||
1337 | } | ||
1338 | |||
1339 | /* | 1278 | /* |
1340 | * Return some name helping to identify an object | 1279 | * Return some name helping to identify an object |
1341 | */ | 1280 | */ |
@@ -1509,24 +1448,41 @@ int luaG_nameof( lua_State* L) | |||
1509 | return 2; | 1448 | return 2; |
1510 | } | 1449 | } |
1511 | 1450 | ||
1451 | // function sentinel used to transfer native functions from/to keeper states | ||
1452 | static int sentinelfunc( lua_State* L) | ||
1453 | { | ||
1454 | return luaL_error( L, "transfer sentinel function for %s, should never be called", lua_tostring( L, lua_upvalueindex( 1))); | ||
1455 | } | ||
1456 | |||
1512 | /* | 1457 | /* |
1513 | * Push a looked-up native/LuaJIT function. | 1458 | * Push a looked-up native/LuaJIT function. |
1514 | */ | 1459 | */ |
1515 | static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, char const* upName_) | 1460 | static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) |
1516 | { | 1461 | { |
1517 | char const* fqn; // L // L2 | 1462 | char const* fqn; // L // L2 |
1518 | size_t len; | 1463 | size_t len; |
1519 | _ASSERT_L( L, lua_isfunction( L, i)); // ... f ... | 1464 | _ASSERT_L( L, lua_isfunction( L, i)); // ... f ... |
1520 | STACK_CHECK( L); | 1465 | STACK_CHECK( L); |
1521 | // fetch the name from the source state's lookup table | 1466 | if( mode_ == eLM_FromKeeper) |
1522 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // ... f ... {} | 1467 | { |
1523 | _ASSERT_L( L, lua_istable( L, -1)); | 1468 | lua_CFunction f = lua_tocfunction( L, i); // should *always* be sentinelfunc! |
1524 | lua_pushvalue( L, i); // ... f ... {} f | 1469 | _ASSERT_L( L, f == sentinelfunc); |
1525 | lua_rawget( L, -2); // ... f ... {} "f.q.n" | 1470 | lua_getupvalue( L, i, 1); // ... f ... "f.q.n" |
1526 | fqn = lua_tolstring( L, -1, &len); | 1471 | fqn = lua_tolstring( L, -1, &len); |
1472 | } | ||
1473 | else | ||
1474 | { | ||
1475 | // fetch the name from the source state's lookup table | ||
1476 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // ... f ... {} | ||
1477 | _ASSERT_L( L, lua_istable( L, -1)); | ||
1478 | lua_pushvalue( L, i); // ... f ... {} f | ||
1479 | lua_rawget( L, -2); // ... f ... {} "f.q.n" | ||
1480 | fqn = lua_tolstring( L, -1, &len); | ||
1481 | } | ||
1527 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END, fqn)); | 1482 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END, fqn)); |
1528 | // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database | 1483 | // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database |
1529 | lua_pop( L, 2); // ... f ... | 1484 | lua_pop( L, (mode_ == eLM_FromKeeper) ? 1 : 2); // ... f ... |
1485 | STACK_MID( L, 0); | ||
1530 | if( !fqn) | 1486 | if( !fqn) |
1531 | { | 1487 | { |
1532 | char const *from, *typewhat, *what, *gotchaA, *gotchaB; | 1488 | char const *from, *typewhat, *what, *gotchaA, *gotchaB; |
@@ -1556,21 +1512,30 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, char cons | |||
1556 | STACK_END( L, 0); | 1512 | STACK_END( L, 0); |
1557 | // push the equivalent function in the destination's stack, retrieved from the lookup table | 1513 | // push the equivalent function in the destination's stack, retrieved from the lookup table |
1558 | STACK_CHECK( L2); | 1514 | STACK_CHECK( L2); |
1559 | lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_KEY); // {} | 1515 | if( mode_ == eLM_ToKeeper) |
1560 | _ASSERT_L( L2, lua_istable( L2, -1)); | ||
1561 | lua_pushlstring( L2, fqn, len); // {} "f.q.n" | ||
1562 | lua_rawget( L2, -2); // {} f | ||
1563 | if( !lua_isfunction( L2, -1)) | ||
1564 | { | 1516 | { |
1565 | char const* from, * to; | 1517 | // push a sentinel closure that holds the lookup name as upvalue |
1566 | lua_getglobal( L, "decoda_name"); // // ... f ... decoda_name | 1518 | lua_pushlstring( L2, fqn, len); // "f.q.n" |
1567 | from = lua_tostring( L, -1); | 1519 | lua_pushcclosure( L2, sentinelfunc, 1); // f |
1568 | lua_getglobal( L2, "decoda_name"); // {} f decoda_name | 1520 | } |
1569 | to = lua_tostring( L2, -1); | 1521 | else |
1570 | (void) luaL_error( L, "%s: function '%s' not found in %s destination transfer database.", from ? from : "main", fqn, to ? to : "main"); | 1522 | { |
1571 | return; | 1523 | lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_KEY); // {} |
1524 | _ASSERT_L( L2, lua_istable( L2, -1)); | ||
1525 | lua_pushlstring( L2, fqn, len); // {} "f.q.n" | ||
1526 | lua_rawget( L2, -2); // {} f | ||
1527 | if( !lua_isfunction( L2, -1)) | ||
1528 | { | ||
1529 | char const* from, * to; | ||
1530 | lua_getglobal( L, "decoda_name"); // ... f ... decoda_name | ||
1531 | from = lua_tostring( L, -1); | ||
1532 | lua_getglobal( L2, "decoda_name"); // {} f decoda_name | ||
1533 | to = lua_tostring( L2, -1); | ||
1534 | (void) luaL_error( L, "%s: function '%s' not found in %s destination transfer database.", from ? from : "main", fqn, to ? to : "main"); | ||
1535 | return; | ||
1536 | } | ||
1537 | lua_remove( L2, -2); // f | ||
1572 | } | 1538 | } |
1573 | lua_remove( L2, -2); // f | ||
1574 | STACK_END( L2, 1); | 1539 | STACK_END( L2, 1); |
1575 | } | 1540 | } |
1576 | 1541 | ||
@@ -1581,159 +1546,207 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, char cons | |||
1581 | enum e_vt { | 1546 | enum e_vt { |
1582 | VT_NORMAL, VT_KEY, VT_METATABLE | 1547 | VT_NORMAL, VT_KEY, VT_METATABLE |
1583 | }; | 1548 | }; |
1584 | static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt value_type, char const* upName_); | 1549 | static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt value_type, enum eLookupMode mode_, char const* upName_); |
1585 | 1550 | ||
1586 | static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, char const* upName_) | 1551 | static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) |
1587 | { | 1552 | { |
1588 | FuncSubType funcSubType; | 1553 | int n, needToPush; |
1589 | /*lua_CFunction cfunc =*/ luaG_tocfunction( L, i, &funcSubType); // NULL for LuaJIT-fast && bytecode functions | 1554 | luaL_Buffer b; |
1590 | |||
1591 | ASSERT_L( L2_cache_i != 0); // ... {cache} ... p | 1555 | ASSERT_L( L2_cache_i != 0); // ... {cache} ... p |
1592 | STACK_GROW(L,2); | 1556 | STACK_GROW(L,2); |
1593 | STACK_CHECK( L); | 1557 | STACK_CHECK( L); |
1594 | 1558 | ||
1595 | if( funcSubType == FST_Bytecode) | 1559 | // 'lua_dump()' needs the function at top of stack |
1560 | // if already on top of the stack, no need to push again | ||
1561 | needToPush = (i != (uint_t)lua_gettop( L)); | ||
1562 | if( needToPush) | ||
1596 | { | 1563 | { |
1597 | int n; | 1564 | lua_pushvalue( L, i); // ... f |
1598 | luaL_Buffer b; | 1565 | } |
1599 | // 'lua_dump()' needs the function at top of stack | ||
1600 | // if already on top of the stack, no need to push again | ||
1601 | int needToPush = (i != (uint_t)lua_gettop( L)); | ||
1602 | if( needToPush) | ||
1603 | { | ||
1604 | lua_pushvalue( L, i); // ... f | ||
1605 | } | ||
1606 | 1566 | ||
1607 | luaL_buffinit( L, &b); | 1567 | luaL_buffinit( L, &b); |
1608 | // | 1568 | // |
1609 | // "value returned is the error code returned by the last call | 1569 | // "value returned is the error code returned by the last call |
1610 | // to the writer" (and we only return 0) | 1570 | // to the writer" (and we only return 0) |
1611 | // not sure this could ever fail but for memory shortage reasons | 1571 | // not sure this could ever fail but for memory shortage reasons |
1612 | if( lua_dump( L, buf_writer, &b) != 0) | 1572 | if( lua_dump( L, buf_writer, &b) != 0) |
1613 | { | 1573 | { |
1614 | luaL_error( L, "internal error: function dump failed."); | 1574 | luaL_error( L, "internal error: function dump failed."); |
1615 | } | 1575 | } |
1616 | 1576 | ||
1617 | // pushes dumped string on 'L' | 1577 | // pushes dumped string on 'L' |
1618 | luaL_pushresult( &b); // ... f b | 1578 | luaL_pushresult( &b); // ... f b |
1619 | 1579 | ||
1620 | // if not pushed, no need to pop | 1580 | // if not pushed, no need to pop |
1621 | if( needToPush) | 1581 | if( needToPush) |
1582 | { | ||
1583 | lua_remove( L, -2); // ... b | ||
1584 | } | ||
1585 | |||
1586 | // transfer the bytecode, then the upvalues, to create a similar closure | ||
1587 | { | ||
1588 | char const* name = NULL; | ||
1589 | |||
1590 | #if LOG_FUNC_INFO | ||
1591 | // "To get information about a function you push it onto the | ||
1592 | // stack and start the what string with the character '>'." | ||
1593 | // | ||
1622 | { | 1594 | { |
1623 | lua_remove( L, -2); // ... b | 1595 | lua_Debug ar; |
1596 | lua_pushvalue( L, i); // ... b f | ||
1597 | // fills 'name' 'namewhat' and 'linedefined', pops function | ||
1598 | lua_getinfo(L, ">nS", &ar); // ... b | ||
1599 | name = ar.namewhat; | ||
1600 | fprintf( stderr, INDENT_BEGIN "FNAME: %s @ %d\n", i, s_indent, ar.short_src, ar.linedefined); // just gives NULL | ||
1624 | } | 1601 | } |
1625 | 1602 | #endif // LOG_FUNC_INFO | |
1626 | // transfer the bytecode, then the upvalues, to create a similar closure | ||
1627 | { | 1603 | { |
1628 | char const* name = NULL; | 1604 | size_t sz; |
1629 | 1605 | char const* s = lua_tolstring( L, -1, &sz); // ... b | |
1630 | #if LOG_FUNC_INFO | 1606 | ASSERT_L( s && sz); |
1631 | // "To get information about a function you push it onto the | 1607 | STACK_GROW( L2, 2); |
1632 | // stack and start the what string with the character '>'." | 1608 | // Note: Line numbers seem to be taken precisely from the |
1609 | // original function. 'name' is not used since the chunk | ||
1610 | // is precompiled (it seems...). | ||
1633 | // | 1611 | // |
1612 | // TBD: Can we get the function's original name through, as well? | ||
1613 | // | ||
1614 | if( luaL_loadbuffer( L2, s, sz, name) != 0) // ... {cache} ... p function | ||
1634 | { | 1615 | { |
1635 | lua_Debug ar; | 1616 | // chunk is precompiled so only LUA_ERRMEM can happen |
1636 | lua_pushvalue( L, i); // ... b f | 1617 | // "Otherwise, it pushes an error message" |
1637 | // fills 'name' 'namewhat' and 'linedefined', pops function | ||
1638 | lua_getinfo(L, ">nS", &ar); // ... b | ||
1639 | name = ar.namewhat; | ||
1640 | fprintf( stderr, INDENT_BEGIN "FNAME: %s @ %d\n", i, s_indent, ar.short_src, ar.linedefined); // just gives NULL | ||
1641 | } | ||
1642 | #endif // LOG_FUNC_INFO | ||
1643 | { | ||
1644 | size_t sz; | ||
1645 | char const* s = lua_tolstring( L, -1, &sz); // ... b | ||
1646 | ASSERT_L( s && sz); | ||
1647 | STACK_GROW( L2, 2); | ||
1648 | // Note: Line numbers seem to be taken precisely from the | ||
1649 | // original function. 'name' is not used since the chunk | ||
1650 | // is precompiled (it seems...). | ||
1651 | // | ||
1652 | // TBD: Can we get the function's original name through, as well? | ||
1653 | // | 1618 | // |
1654 | if( luaL_loadbuffer( L2, s, sz, name) != 0) // ... {cache} ... p function | 1619 | STACK_GROW( L, 1); |
1655 | { | 1620 | luaL_error( L, "%s", lua_tostring( L2, -1)); |
1656 | // chunk is precompiled so only LUA_ERRMEM can happen | ||
1657 | // "Otherwise, it pushes an error message" | ||
1658 | // | ||
1659 | STACK_GROW( L, 1); | ||
1660 | luaL_error( L, "%s", lua_tostring( L2, -1)); | ||
1661 | } | ||
1662 | // remove the dumped string | ||
1663 | lua_pop( L, 1); // ... | ||
1664 | // now set the cache as soon as we can. | ||
1665 | // this is necessary if one of the function's upvalues references it indirectly | ||
1666 | // we need to find it in the cache even if it isn't fully transfered yet | ||
1667 | lua_insert( L2, -2); // ... {cache} ... function p | ||
1668 | lua_pushvalue( L2, -2); // ... {cache} ... function p function | ||
1669 | // cache[p] = function | ||
1670 | lua_rawset( L2, L2_cache_i); // ... {cache} ... function | ||
1671 | } | 1621 | } |
1672 | STACK_MID( L, 0); | 1622 | // remove the dumped string |
1623 | lua_pop( L, 1); // ... | ||
1624 | // now set the cache as soon as we can. | ||
1625 | // this is necessary if one of the function's upvalues references it indirectly | ||
1626 | // we need to find it in the cache even if it isn't fully transfered yet | ||
1627 | lua_insert( L2, -2); // ... {cache} ... function p | ||
1628 | lua_pushvalue( L2, -2); // ... {cache} ... function p function | ||
1629 | // cache[p] = function | ||
1630 | lua_rawset( L2, L2_cache_i); // ... {cache} ... function | ||
1631 | } | ||
1632 | STACK_MID( L, 0); | ||
1673 | 1633 | ||
1674 | /* push over any upvalues; references to this function will come from | 1634 | /* push over any upvalues; references to this function will come from |
1675 | * cache so we don't end up in eternal loop. | 1635 | * cache so we don't end up in eternal loop. |
1676 | * Lua5.2: one of the upvalues is _ENV, which we don't want to copy! | 1636 | * Lua5.2: one of the upvalues is _ENV, which we don't want to copy! |
1677 | * instead, the function shall have LUA_RIDX_GLOBALS taken in the destination state! | 1637 | * instead, the function shall have LUA_RIDX_GLOBALS taken in the destination state! |
1678 | */ | 1638 | */ |
1679 | { | 1639 | { |
1680 | char const* upname; | 1640 | char const* upname; |
1681 | #if LUA_VERSION_NUM == 502 | 1641 | #if LUA_VERSION_NUM == 502 |
1682 | // With Lua 5.2, each Lua function gets its environment as one of its upvalues (named LUA_ENV, aka "_ENV" by default) | 1642 | // With Lua 5.2, each Lua function gets its environment as one of its upvalues (named LUA_ENV, aka "_ENV" by default) |
1683 | // Generally this is LUA_RIDX_GLOBALS, which we don't want to copy from the source to the destination state... | 1643 | // Generally this is LUA_RIDX_GLOBALS, which we don't want to copy from the source to the destination state... |
1684 | // -> if we encounter an upvalue equal to the global table in the source, bind it to the destination's global table | 1644 | // -> if we encounter an upvalue equal to the global table in the source, bind it to the destination's global table |
1685 | lua_pushglobaltable( L); // ... _G | 1645 | lua_pushglobaltable( L); // ... _G |
1686 | #endif // LUA_VERSION_NUM | 1646 | #endif // LUA_VERSION_NUM |
1687 | for( n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != NULL; ++ n) | 1647 | for( n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != NULL; ++ n) |
1688 | { // ... _G up[n] | 1648 | { // ... _G up[n] |
1689 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "UPNAME[%d]: %s\n" INDENT_END, n, upname)); | 1649 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "UPNAME[%d]: %s\n" INDENT_END, n, upname)); |
1690 | #if LUA_VERSION_NUM == 502 | 1650 | #if LUA_VERSION_NUM == 502 |
1691 | if( lua_rawequal( L, -1, -2)) // is the upvalue equal to the global table? | 1651 | if( lua_rawequal( L, -1, -2)) // is the upvalue equal to the global table? |
1692 | { | 1652 | { |
1693 | lua_pushglobaltable( L2); // ... {cache} ... function <upvalues> | 1653 | lua_pushglobaltable( L2); // ... {cache} ... function <upvalues> |
1694 | } | 1654 | } |
1695 | else | 1655 | else |
1696 | #endif // LUA_VERSION_NUM | 1656 | #endif // LUA_VERSION_NUM |
1657 | { | ||
1658 | if( !inter_copy_one_( L2, L2_cache_i, L, lua_gettop( L), VT_NORMAL, mode_, upname)) // ... {cache} ... function <upvalues> | ||
1697 | { | 1659 | { |
1698 | if( !inter_copy_one_( L2, L2_cache_i, L, lua_gettop( L), VT_NORMAL, upname)) // ... {cache} ... function <upvalues> | 1660 | luaL_error( L, "Cannot copy upvalue type '%s'", luaL_typename( L, -1)); |
1699 | { | ||
1700 | luaL_error( L, "Cannot copy upvalue type '%s'", luaL_typename( L, -1)); | ||
1701 | } | ||
1702 | } | 1661 | } |
1703 | lua_pop( L, 1); // ... _G | ||
1704 | } | 1662 | } |
1663 | lua_pop( L, 1); // ... _G | ||
1664 | } | ||
1705 | #if LUA_VERSION_NUM == 502 | 1665 | #if LUA_VERSION_NUM == 502 |
1706 | lua_pop( L, 1); // ... | 1666 | lua_pop( L, 1); // ... |
1707 | #endif // LUA_VERSION_NUM | 1667 | #endif // LUA_VERSION_NUM |
1708 | } | 1668 | } |
1709 | // L2: function + 'n' upvalues (>=0) | 1669 | // L2: function + 'n' upvalues (>=0) |
1710 | 1670 | ||
1711 | STACK_MID( L, 0); | 1671 | STACK_MID( L, 0); |
1712 | 1672 | ||
1713 | // Set upvalues (originally set to 'nil' by 'lua_load') | 1673 | // Set upvalues (originally set to 'nil' by 'lua_load') |
1674 | { | ||
1675 | int func_index = lua_gettop( L2) - n; | ||
1676 | for( ; n > 0; -- n) | ||
1714 | { | 1677 | { |
1715 | int func_index = lua_gettop( L2) - n; | 1678 | char const* rc = lua_setupvalue( L2, func_index, n); // ... {cache} ... function |
1716 | for( ; n > 0; -- n) | 1679 | // |
1717 | { | 1680 | // "assigns the value at the top of the stack to the upvalue and returns its name. |
1718 | char const* rc = lua_setupvalue( L2, func_index, n); // ... {cache} ... function | 1681 | // It also pops the value from the stack." |
1719 | // | ||
1720 | // "assigns the value at the top of the stack to the upvalue and returns its name. | ||
1721 | // It also pops the value from the stack." | ||
1722 | 1682 | ||
1723 | ASSERT_L( rc); // not having enough slots? | 1683 | ASSERT_L( rc); // not having enough slots? |
1724 | } | ||
1725 | // once all upvalues have been set we are left | ||
1726 | // with the function at the top of the stack // ... {cache} ... function | ||
1727 | } | 1684 | } |
1685 | // once all upvalues have been set we are left | ||
1686 | // with the function at the top of the stack // ... {cache} ... function | ||
1728 | } | 1687 | } |
1729 | } | 1688 | } |
1730 | else // C function OR LuaJIT fast function!!! | 1689 | STACK_END( L, 0); |
1690 | } | ||
1691 | |||
1692 | /* | ||
1693 | * Check if we've already copied the same function from 'L', and reuse the old | ||
1694 | * copy. | ||
1695 | * | ||
1696 | * Always pushes a function to 'L2'. | ||
1697 | */ | ||
1698 | static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) | ||
1699 | { | ||
1700 | FuncSubType funcSubType; | ||
1701 | /*lua_CFunction cfunc =*/ luaG_tocfunction( L, i, &funcSubType); // NULL for LuaJIT-fast && bytecode functions | ||
1702 | if( funcSubType == FST_Bytecode) | ||
1703 | { | ||
1704 | void* const aspointer = (void*)lua_topointer( L, i); | ||
1705 | // TBD: Merge this and same code for tables | ||
1706 | ASSERT_L( L2_cache_i != 0); | ||
1707 | |||
1708 | STACK_GROW( L2, 2); | ||
1709 | |||
1710 | // L2_cache[id_str]= function | ||
1711 | // | ||
1712 | STACK_CHECK( L2); | ||
1713 | |||
1714 | // We don't need to use the from state ('L') in ID since the life span | ||
1715 | // is only for the duration of a copy (both states are locked). | ||
1716 | // | ||
1717 | |||
1718 | // push a light userdata uniquely representing the function | ||
1719 | lua_pushlightuserdata( L2, aspointer); // ... {cache} ... p | ||
1720 | |||
1721 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); | ||
1722 | |||
1723 | lua_pushvalue( L2, -1); // ... {cache} ... p p | ||
1724 | lua_rawget( L2, L2_cache_i); // ... {cache} ... p function|nil|true | ||
1725 | |||
1726 | if( lua_isnil(L2,-1)) // function is unknown | ||
1727 | { | ||
1728 | lua_pop( L2, 1); // ... {cache} ... p | ||
1729 | |||
1730 | // Set to 'true' for the duration of creation; need to find self-references | ||
1731 | // via upvalues | ||
1732 | // | ||
1733 | // pushes a copy of the func, stores a reference in the cache | ||
1734 | inter_copy_func( L2, L2_cache_i, L, i, mode_, upName_); // ... {cache} ... function | ||
1735 | } | ||
1736 | else // found function in the cache | ||
1737 | { | ||
1738 | lua_remove( L2, -2); // ... {cache} ... function | ||
1739 | } | ||
1740 | STACK_END( L2, 1); | ||
1741 | } | ||
1742 | else // function is native/LuaJIT: no need to cache | ||
1731 | { | 1743 | { |
1732 | lua_pop( L2, 1); // ... {cache} ... | 1744 | lookup_native_func( L2, L, i, mode_, upName_); // ... {cache} ... function |
1733 | // No need to transfer upvalues for C/JIT functions since they weren't actually copied, only looked up | ||
1734 | lookup_native_func( L2, L, i, upName_); // ... {cache} ... function | ||
1735 | } | 1745 | } |
1736 | STACK_END( L, 0); | 1746 | |
1747 | // | ||
1748 | // L2 [-1]: function | ||
1749 | ASSERT_L( lua_isfunction( L2, -1)); | ||
1737 | } | 1750 | } |
1738 | 1751 | ||
1739 | /* | 1752 | /* |
@@ -1746,7 +1759,7 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin | |||
1746 | * | 1759 | * |
1747 | * Returns TRUE if value was pushed, FALSE if its type is non-supported. | 1760 | * Returns TRUE if value was pushed, FALSE if its type is non-supported. |
1748 | */ | 1761 | */ |
1749 | static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt, char const* upName_) | 1762 | static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt, enum eLookupMode mode_, char const* upName_) |
1750 | { | 1763 | { |
1751 | bool_t ret = TRUE; | 1764 | bool_t ret = TRUE; |
1752 | 1765 | ||
@@ -1764,6 +1777,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1764 | 1777 | ||
1765 | case LUA_TNUMBER: | 1778 | case LUA_TNUMBER: |
1766 | /* LNUM patch support (keeping integer accuracy) */ | 1779 | /* LNUM patch support (keeping integer accuracy) */ |
1780 | // TODO: support for integer in Lua 5.3 | ||
1767 | #ifdef LUA_LNUM | 1781 | #ifdef LUA_LNUM |
1768 | if( lua_isinteger(L,i)) | 1782 | if( lua_isinteger(L,i)) |
1769 | { | 1783 | { |
@@ -1831,7 +1845,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1831 | { | 1845 | { |
1832 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "FUNCTION\n" INDENT_END)); | 1846 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "FUNCTION\n" INDENT_END)); |
1833 | STACK_CHECK( L2); | 1847 | STACK_CHECK( L2); |
1834 | push_cached_func( L2, L2_cache_i, L, i, upName_); | 1848 | push_cached_func( L2, L2_cache_i, L, i, mode_, upName_); |
1835 | STACK_END( L2, 1); | 1849 | STACK_END( L2, 1); |
1836 | } | 1850 | } |
1837 | break; | 1851 | break; |
@@ -1873,7 +1887,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1873 | 1887 | ||
1874 | /* Only basic key types are copied over; others ignored | 1888 | /* Only basic key types are copied over; others ignored |
1875 | */ | 1889 | */ |
1876 | if( inter_copy_one_( L2, 0 /*key*/, L, key_i, VT_KEY, upName_)) | 1890 | if( inter_copy_one_( L2, 0 /*key*/, L, key_i, VT_KEY, mode_, upName_)) |
1877 | { | 1891 | { |
1878 | char* valPath = (char*) upName_; | 1892 | char* valPath = (char*) upName_; |
1879 | if( GVerboseErrors) | 1893 | if( GVerboseErrors) |
@@ -1894,7 +1908,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1894 | * Contents of metatables are copied with cache checking; | 1908 | * Contents of metatables are copied with cache checking; |
1895 | * important to detect loops. | 1909 | * important to detect loops. |
1896 | */ | 1910 | */ |
1897 | if( inter_copy_one_( L2, L2_cache_i, L, val_i, VT_NORMAL, valPath)) | 1911 | if( inter_copy_one_( L2, L2_cache_i, L, val_i, VT_NORMAL, mode_, valPath)) |
1898 | { | 1912 | { |
1899 | ASSERT_L( lua_istable(L2,-3)); | 1913 | ASSERT_L( lua_istable(L2,-3)); |
1900 | lua_rawset( L2, -3); // add to table (pops key & val) | 1914 | lua_rawset( L2, -3); // add to table (pops key & val) |
@@ -1936,7 +1950,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1936 | lua_pop( L2, 1); | 1950 | lua_pop( L2, 1); |
1937 | STACK_MID( L2, 2); | 1951 | STACK_MID( L2, 2); |
1938 | ASSERT_L( lua_istable(L,-1)); | 1952 | ASSERT_L( lua_istable(L,-1)); |
1939 | if( inter_copy_one_( L2, L2_cache_i /*for function cacheing*/, L, lua_gettop(L) /*[-1]*/, VT_METATABLE, upName_)) | 1953 | if( inter_copy_one_( L2, L2_cache_i /*for function cacheing*/, L, lua_gettop(L) /*[-1]*/, VT_METATABLE, mode_, upName_)) |
1940 | { | 1954 | { |
1941 | // | 1955 | // |
1942 | // L2 ([-3]: copied table) | 1956 | // L2 ([-3]: copied table) |
@@ -1981,8 +1995,8 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1981 | } | 1995 | } |
1982 | STACK_END( L2, 1); | 1996 | STACK_END( L2, 1); |
1983 | STACK_END( L, 0); | 1997 | STACK_END( L, 0); |
1984 | } | 1998 | } |
1985 | break; | 1999 | break; |
1986 | 2000 | ||
1987 | /* The following types cannot be copied */ | 2001 | /* The following types cannot be copied */ |
1988 | 2002 | ||
@@ -2004,7 +2018,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
2004 | * | 2018 | * |
2005 | * Note: Parameters are in this order ('L' = from first) to be same as 'lua_xmove'. | 2019 | * Note: Parameters are in this order ('L' = from first) to be same as 'lua_xmove'. |
2006 | */ | 2020 | */ |
2007 | int luaG_inter_copy( lua_State* L, lua_State* L2, uint_t n) | 2021 | int luaG_inter_copy( lua_State* L, lua_State* L2, uint_t n, enum eLookupMode mode_) |
2008 | { | 2022 | { |
2009 | uint_t top_L = lua_gettop( L); | 2023 | uint_t top_L = lua_gettop( L); |
2010 | uint_t top_L2 = lua_gettop( L2); | 2024 | uint_t top_L2 = lua_gettop( L2); |
@@ -2034,7 +2048,7 @@ int luaG_inter_copy( lua_State* L, lua_State* L2, uint_t n) | |||
2034 | { | 2048 | { |
2035 | sprintf( tmpBuf, "arg_%d", j); | 2049 | sprintf( tmpBuf, "arg_%d", j); |
2036 | } | 2050 | } |
2037 | copyok = inter_copy_one_( L2, top_L2 + 1, L, i, VT_NORMAL, pBuf); | 2051 | copyok = inter_copy_one_( L2, top_L2 + 1, L, i, VT_NORMAL, mode_, pBuf); |
2038 | if( !copyok) | 2052 | if( !copyok) |
2039 | { | 2053 | { |
2040 | break; | 2054 | break; |
@@ -2062,14 +2076,14 @@ int luaG_inter_copy( lua_State* L, lua_State* L2, uint_t n) | |||
2062 | } | 2076 | } |
2063 | 2077 | ||
2064 | 2078 | ||
2065 | int luaG_inter_move( lua_State* L, lua_State* L2, uint_t n) | 2079 | int luaG_inter_move( lua_State* L, lua_State* L2, uint_t n, enum eLookupMode mode_) |
2066 | { | 2080 | { |
2067 | int ret = luaG_inter_copy( L, L2, n); | 2081 | int ret = luaG_inter_copy( L, L2, n, mode_); |
2068 | lua_pop( L, (int) n); | 2082 | lua_pop( L, (int) n); |
2069 | return ret; | 2083 | return ret; |
2070 | } | 2084 | } |
2071 | 2085 | ||
2072 | void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx) | 2086 | void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx, enum eLookupMode mode_) |
2073 | { | 2087 | { |
2074 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_inter_copy_package()\n" INDENT_END)); | 2088 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_inter_copy_package()\n" INDENT_END)); |
2075 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | 2089 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
@@ -2100,7 +2114,7 @@ void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx) | |||
2100 | else | 2114 | else |
2101 | { | 2115 | { |
2102 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | 2116 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
2103 | luaG_inter_move( L, L2, 1); // moves the entry to L2 | 2117 | luaG_inter_move( L, L2, 1, mode_); // moves the entry to L2 |
2104 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | 2118 | DEBUGSPEW_CODE( -- debugspew_indent_depth); |
2105 | lua_setfield( L2, -2, entries[i]); // set package[entries[i]] | 2119 | lua_setfield( L2, -2, entries[i]); // set package[entries[i]] |
2106 | } | 2120 | } |