diff options
Diffstat (limited to 'src/tools.c')
-rw-r--r-- | src/tools.c | 260 |
1 files changed, 108 insertions, 152 deletions
diff --git a/src/tools.c b/src/tools.c index a2ec517..2f3140d 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * TOOLS.C Copyright (c) 2002-08, Asko Kauppi | 2 | * TOOLS.C Copyright (c) 2002-10, Asko Kauppi |
3 | * | 3 | * |
4 | * Lua tools to support Lanes. | 4 | * Lua tools to support Lanes. |
5 | */ | 5 | */ |
@@ -7,7 +7,7 @@ | |||
7 | /* | 7 | /* |
8 | =============================================================================== | 8 | =============================================================================== |
9 | 9 | ||
10 | Copyright (C) 2002-08 Asko Kauppi <akauppi@gmail.com> | 10 | Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com> |
11 | 11 | ||
12 | Permission is hereby granted, free of charge, to any person obtaining a copy | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy |
13 | of this software and associated documentation files (the "Software"), to deal | 13 | of this software and associated documentation files (the "Software"), to deal |
@@ -40,8 +40,6 @@ THE SOFTWARE. | |||
40 | #include <ctype.h> | 40 | #include <ctype.h> |
41 | #include <stdlib.h> | 41 | #include <stdlib.h> |
42 | 42 | ||
43 | static volatile lua_CFunction hijacked_tostring; // = NULL | ||
44 | |||
45 | MUTEX_T deep_lock; | 43 | MUTEX_T deep_lock; |
46 | MUTEX_T mtid_lock; | 44 | MUTEX_T mtid_lock; |
47 | 45 | ||
@@ -600,7 +598,7 @@ uint_t get_mt_id( lua_State *L, int i ) { | |||
600 | // [-2]: reg[REG_MTID] | 598 | // [-2]: reg[REG_MTID] |
601 | // [-1]: nil/uint | 599 | // [-1]: nil/uint |
602 | 600 | ||
603 | id= lua_tointeger(L,-1); // 0 for nil | 601 | id= (uint_t)lua_tointeger(L,-1); // 0 for nil |
604 | lua_pop(L,1); | 602 | lua_pop(L,1); |
605 | STACK_MID(L,1) | 603 | STACK_MID(L,1) |
606 | 604 | ||
@@ -644,73 +642,60 @@ static int buf_writer( lua_State *L, const void* b, size_t n, void* B ) { | |||
644 | * Returns TRUE if the table was cached (no need to fill it!); FALSE if | 642 | * Returns TRUE if the table was cached (no need to fill it!); FALSE if |
645 | * it's a virgin. | 643 | * it's a virgin. |
646 | */ | 644 | */ |
647 | static | 645 | static bool_t push_cached_table( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) |
648 | bool_t push_cached_table( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) { | 646 | { |
649 | bool_t ret; | 647 | bool_t ret; |
650 | |||
651 | ASSERT_L( hijacked_tostring ); | ||
652 | ASSERT_L( L2_cache_i != 0 ); | ||
653 | |||
654 | STACK_GROW(L,2); | ||
655 | STACK_GROW(L2,3); | ||
656 | 648 | ||
657 | // Create an identity string for table at [i]; it should stay unique at | 649 | ASSERT_L( L2_cache_i != 0 ); |
658 | // least during copying of the data (then we can clear the caches). | ||
659 | // | ||
660 | STACK_CHECK(L) | ||
661 | lua_pushcfunction( L, hijacked_tostring ); | ||
662 | lua_pushvalue( L, i ); | ||
663 | lua_call( L, 1 /*args*/, 1 /*retvals*/ ); | ||
664 | // | ||
665 | // [-1]: "table: 0x...." | ||
666 | 650 | ||
667 | STACK_END(L,1) | 651 | STACK_GROW(L2,3); |
668 | ASSERT_L( lua_type(L,-1) == LUA_TSTRING ); | ||
669 | 652 | ||
670 | // L2_cache[id_str]= [{...}] | 653 | // L2_cache[id_str]= [{...}] |
671 | // | 654 | // |
672 | STACK_CHECK(L2) | 655 | STACK_CHECK(L2) |
673 | 656 | ||
674 | // We don't need to use the from state ('L') in ID since the life span | 657 | // We don't need to use the from state ('L') in ID since the life span |
675 | // is only for the duration of a copy (both states are locked). | 658 | // is only for the duration of a copy (both states are locked). |
676 | // | 659 | // |
677 | lua_pushstring( L2, lua_tostring(L,-1) ); | 660 | lua_pushlightuserdata( L2, (void*)lua_topointer( L, i )); // push a light userdata uniquely representing the table |
678 | lua_pop(L,1); // remove the 'tostring(tbl)' value (in L!) | ||
679 | 661 | ||
680 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); | 662 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); |
681 | 663 | ||
682 | lua_pushvalue( L2, -1 ); | 664 | lua_pushvalue( L2, -1 ); |
683 | lua_rawget( L2, L2_cache_i ); | 665 | lua_rawget( L2, L2_cache_i ); |
684 | // | 666 | // |
685 | // [-2]: identity string ("table: 0x...") | 667 | // [-2]: identity table pointer lightuserdata |
686 | // [-1]: table|nil | 668 | // [-1]: table|nil |
687 | |||
688 | if (lua_isnil(L2,-1)) { | ||
689 | lua_pop(L2,1); | ||
690 | lua_newtable(L2); | ||
691 | lua_pushvalue(L2,-1); | ||
692 | lua_insert(L2,-3); | ||
693 | // | ||
694 | // [-3]: new table (2nd ref) | ||
695 | // [-2]: identity string | ||
696 | // [-1]: new table | ||
697 | 669 | ||
698 | lua_rawset(L2, L2_cache_i); | 670 | if (lua_isnil(L2,-1)) |
699 | // | 671 | { |
700 | // [-1]: new table (tied to 'L2_cache' table') | 672 | lua_pop(L2,1); |
701 | 673 | lua_newtable(L2); | |
702 | ret= FALSE; // brand new | 674 | lua_pushvalue(L2,-1); |
703 | 675 | lua_insert(L2,-3); | |
704 | } else { | 676 | // |
705 | lua_remove(L2,-2); | 677 | // [-3]: new table (2nd ref) |
706 | ret= TRUE; // from cache | 678 | // [-2]: identity table pointer lightuserdata |
707 | } | 679 | // [-1]: new table |
708 | STACK_END(L2,1) | ||
709 | // | ||
710 | // L2 [-1]: table to use as destination | ||
711 | 680 | ||
712 | ASSERT_L( lua_istable(L2,-1) ); | 681 | lua_rawset(L2, L2_cache_i); |
713 | return ret; | 682 | // |
683 | // [-1]: new table (tied to 'L2_cache' table') | ||
684 | |||
685 | ret= FALSE; // brand new | ||
686 | |||
687 | } | ||
688 | else | ||
689 | { | ||
690 | lua_remove(L2,-2); | ||
691 | ret= TRUE; // from cache | ||
692 | } | ||
693 | STACK_END(L2,1) | ||
694 | // | ||
695 | // L2 [-1]: table to use as destination | ||
696 | |||
697 | ASSERT_L( lua_istable(L2,-1) ); | ||
698 | return ret; | ||
714 | } | 699 | } |
715 | 700 | ||
716 | 701 | ||
@@ -722,82 +707,76 @@ bool_t push_cached_table( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t | |||
722 | */ | 707 | */ |
723 | static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ); | 708 | static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ); |
724 | 709 | ||
725 | static | 710 | static void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) |
726 | void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) { | 711 | { |
727 | // TBD: Merge this and same code for tables | 712 | // TBD: Merge this and same code for tables |
728 | 713 | ||
729 | ASSERT_L( hijacked_tostring ); | 714 | ASSERT_L( L2_cache_i != 0 ); |
730 | ASSERT_L( L2_cache_i != 0 ); | ||
731 | 715 | ||
732 | STACK_GROW(L,2); | 716 | STACK_GROW(L2,3); |
733 | STACK_GROW(L2,3); | ||
734 | 717 | ||
735 | STACK_CHECK(L) | 718 | // L2_cache[id_str]= function |
736 | lua_pushcfunction( L, hijacked_tostring ); | 719 | // |
737 | lua_pushvalue( L, i ); | 720 | STACK_CHECK(L2) |
738 | lua_call( L, 1 /*args*/, 1 /*retvals*/ ); | ||
739 | // | ||
740 | // [-1]: "function: 0x...." | ||
741 | 721 | ||
742 | STACK_END(L,1) | 722 | // We don't need to use the from state ('L') in ID since the life span |
743 | ASSERT_L( lua_type(L,-1) == LUA_TSTRING ); | 723 | // is only for the duration of a copy (both states are locked). |
744 | 724 | // | |
745 | // L2_cache[id_str]= function | 725 | lua_pushlightuserdata( L2, (void*)lua_topointer( L, i )); // push a light userdata uniquely representing the function |
746 | // | ||
747 | STACK_CHECK(L2) | ||
748 | 726 | ||
749 | // We don't need to use the from state ('L') in ID since the life span | 727 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); |
750 | // is only for the duration of a copy (both states are locked). | ||
751 | // | ||
752 | lua_pushstring( L2, lua_tostring(L,-1) ); | ||
753 | lua_pop(L,1); // remove the 'tostring(tbl)' value (in L!) | ||
754 | 728 | ||
755 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); | 729 | lua_pushvalue( L2, -1 ); |
730 | lua_rawget( L2, L2_cache_i ); | ||
731 | // | ||
732 | // [-2]: identity lightuserdata function pointer | ||
733 | // [-1]: function|nil|true (true means: we're working on it; recursive) | ||
756 | 734 | ||
757 | lua_pushvalue( L2, -1 ); | 735 | if (lua_isnil(L2,-1)) |
758 | lua_rawget( L2, L2_cache_i ); | 736 | { |
759 | // | 737 | lua_pop(L2,1); |
760 | // [-2]: identity string ("function: 0x...") | ||
761 | // [-1]: function|nil|true (true means: we're working on it; recursive) | ||
762 | 738 | ||
763 | if (lua_isnil(L2,-1)) { | 739 | // Set to 'true' for the duration of creation; need to find self-references |
764 | lua_pop(L2,1); | 740 | // via upvalues |
765 | 741 | // | |
766 | // Set to 'true' for the duration of creation; need to find self-references | 742 | lua_pushvalue( L2, -1); |
767 | // via upvalues | 743 | lua_pushboolean(L2,TRUE); |
768 | // | 744 | lua_rawset( L2, L2_cache_i); |
769 | lua_pushboolean(L2,TRUE); | ||
770 | lua_setfield( L2, L2_cache_i, lua_tostring(L2,-2) ); | ||
771 | |||
772 | inter_copy_func( L2, L2_cache_i, L, i ); // pushes a copy of the func | ||
773 | 745 | ||
774 | lua_pushvalue(L2,-1); | 746 | inter_copy_func( L2, L2_cache_i, L, i ); // pushes a copy of the func |
775 | lua_insert(L2,-3); | ||
776 | // | ||
777 | // [-3]: function (2nd ref) | ||
778 | // [-2]: identity string | ||
779 | // [-1]: function | ||
780 | 747 | ||
781 | lua_rawset(L2,L2_cache_i); | 748 | lua_pushvalue(L2,-1); |
782 | // | 749 | lua_insert(L2,-3); |
783 | // [-1]: function (tied to 'L2_cache' table') | 750 | // |
784 | 751 | // [-3]: function (2nd ref) | |
785 | } else if (lua_isboolean(L2,-1)) { | 752 | // [-2]: identity lightuserdata function pointer |
786 | // Loop in preparing upvalues; either direct or via a table | 753 | // [-1]: function |
787 | // | ||
788 | // Note: This excludes the case where a function directly addresses | ||
789 | // itself as an upvalue (recursive lane creation). | ||
790 | // | ||
791 | luaL_error( L, "Recursive use of upvalues; cannot copy the function" ); | ||
792 | |||
793 | } else { | ||
794 | lua_remove(L2,-2); | ||
795 | } | ||
796 | STACK_END(L2,1) | ||
797 | // | ||
798 | // L2 [-1]: function | ||
799 | 754 | ||
800 | ASSERT_L( lua_isfunction(L2,-1) ); | 755 | lua_rawset(L2,L2_cache_i); |
756 | // | ||
757 | // [-1]: function (tied to 'L2_cache' table') | ||
758 | |||
759 | } | ||
760 | else if (lua_isboolean(L2,-1)) | ||
761 | { | ||
762 | // Loop in preparing upvalues; either direct or via a table | ||
763 | // | ||
764 | // Note: This excludes the case where a function directly addresses | ||
765 | // itself as an upvalue (recursive lane creation). | ||
766 | // | ||
767 | STACK_GROW(L,1); | ||
768 | luaL_error( L, "Recursive use of upvalues; cannot copy the function" ); | ||
769 | |||
770 | } | ||
771 | else | ||
772 | { | ||
773 | lua_remove(L2,-2); | ||
774 | } | ||
775 | STACK_END(L2,1) | ||
776 | // | ||
777 | // L2 [-1]: function | ||
778 | |||
779 | ASSERT_L( lua_isfunction(L2,-1) ); | ||
801 | } | 780 | } |
802 | 781 | ||
803 | 782 | ||
@@ -1137,29 +1116,6 @@ void luaG_inter_copy( lua_State* L, lua_State *L2, uint_t n ) | |||
1137 | uint_t top_L2= lua_gettop(L2); | 1116 | uint_t top_L2= lua_gettop(L2); |
1138 | uint_t i; | 1117 | uint_t i; |
1139 | 1118 | ||
1140 | /* steal Lua library's 'luaB_tostring()' from the first call. Other calls | ||
1141 | * don't have to have access to it. | ||
1142 | * | ||
1143 | * Note: multiple threads won't come here at once; this function will | ||
1144 | * be called before there can be multiple threads (no locking needed). | ||
1145 | */ | ||
1146 | if (!hijacked_tostring) { | ||
1147 | STACK_GROW( L,1 ); | ||
1148 | |||
1149 | STACK_CHECK(L) | ||
1150 | lua_getglobal( L, "tostring" ); | ||
1151 | // | ||
1152 | // [-1]: function|nil | ||
1153 | |||
1154 | hijacked_tostring= lua_tocfunction( L, -1 ); | ||
1155 | lua_pop(L,1); | ||
1156 | STACK_END(L,0) | ||
1157 | |||
1158 | if (!hijacked_tostring) { | ||
1159 | luaL_error( L, "Need to see 'tostring()' once" ); | ||
1160 | } | ||
1161 | } | ||
1162 | |||
1163 | if (n > top_L) | 1119 | if (n > top_L) |
1164 | luaL_error( L, "Not enough values: %d < %d", top_L, n ); | 1120 | luaL_error( L, "Not enough values: %d < %d", top_L, n ); |
1165 | 1121 | ||