diff options
author | Benoit Germain <bnt period germain arrobase gmail period com> | 2014-02-17 11:05:19 +0100 |
---|---|---|
committer | Benoit Germain <bnt period germain arrobase gmail period com> | 2014-02-17 11:05:19 +0100 |
commit | 47eb3f94373a13ac9f204ca65dfde602f53bdc1a (patch) | |
tree | 95d7d7a52ca92e6527d46d97207d3f079611a355 /src/tools.c | |
parent | 32ad991eb8c590472607d61e9a831d2ca9db05c5 (diff) | |
download | lanes-47eb3f94373a13ac9f204ca65dfde602f53bdc1a.tar.gz lanes-47eb3f94373a13ac9f204ca65dfde602f53bdc1a.tar.bz2 lanes-47eb3f94373a13ac9f204ca65dfde602f53bdc1a.zip |
Deep userdata support improvements
* bumped version to 3.9.0
* keepers now require "package", receive package.path & package.cpath,
and call on_state_create() if it is a C function
* changed the deep public API (improved deep idfunc signature, renamed
luaG_deep_userdata to luaG_newdeepuserdata)
* if an error occurs while copying a deep userdata, don't raise inside
the keeper state
* fixed situations where raised errors could lead to memory leaks (deep
gc)
Diffstat (limited to 'src/tools.c')
-rw-r--r-- | src/tools.c | 791 |
1 files changed, 372 insertions, 419 deletions
diff --git a/src/tools.c b/src/tools.c index fc3e7e0..2aa9b82 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -195,14 +195,14 @@ int initialize_on_state_create( lua_State* L) | |||
195 | } | 195 | } |
196 | 196 | ||
197 | // just like lua_xmove, args are (from, to) | 197 | // just like lua_xmove, args are (from, to) |
198 | void luaG_copy_one_time_settings( lua_State* L, lua_State* L2, char const* name_) | 198 | void luaG_copy_one_time_settings( lua_State* L, lua_State* L2) |
199 | { | 199 | { |
200 | STACK_GROW( L, 1); | 200 | STACK_GROW( L, 1); |
201 | // copy settings from from source to destination registry | 201 | // copy settings from from source to destination registry |
202 | lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); | 202 | lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); |
203 | if( luaG_inter_move( L, L2, 1, eLM_LaneBody) < 0) // error? | 203 | if( luaG_inter_move( L, L2, 1, eLM_LaneBody) < 0) // error? |
204 | { | 204 | { |
205 | (void) luaL_error( L, "failed to copy settings when loading %s", name_); | 205 | (void) luaL_error( L, "failed to copy settings when loading lanes.core"); |
206 | } | 206 | } |
207 | lua_setfield( L2, LUA_REGISTRYINDEX, CONFIG_REGKEY); | 207 | lua_setfield( L2, LUA_REGISTRYINDEX, CONFIG_REGKEY); |
208 | } | 208 | } |
@@ -258,7 +258,7 @@ static void open1lib( lua_State* L, char const* name_, size_t len_, lua_State* f | |||
258 | if( isLanesCore == TRUE) | 258 | if( isLanesCore == TRUE) |
259 | { | 259 | { |
260 | // copy settings from from source to destination registry | 260 | // copy settings from from source to destination registry |
261 | luaG_copy_one_time_settings( from_, L, name_); | 261 | luaG_copy_one_time_settings( from_, L); |
262 | } | 262 | } |
263 | // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) | 263 | // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) |
264 | luaL_requiref( L, name_, libfunc, !isLanesCore); | 264 | luaL_requiref( L, name_, libfunc, !isLanesCore); |
@@ -591,28 +591,61 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) | |||
591 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | 591 | DEBUGSPEW_CODE( -- debugspew_indent_depth); |
592 | } | 592 | } |
593 | 593 | ||
594 | void call_on_state_create( lua_State* L, lua_State* from_, enum eLookupMode mode_) | ||
595 | { | ||
596 | if( s_on_state_create_func != NULL) | ||
597 | { | ||
598 | STACK_CHECK( L); | ||
599 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END)); | ||
600 | if( s_on_state_create_func != initialize_on_state_create) | ||
601 | { | ||
602 | // C function: recreate a closure in the new state, bypassing the lookup scheme | ||
603 | lua_pushcfunction( L, s_on_state_create_func); | ||
604 | } | ||
605 | else // Lua function located in the config table, copied when we opened "lanes.core" | ||
606 | { | ||
607 | if( mode_ != eLM_LaneBody) | ||
608 | { | ||
609 | // if attempting to call in a keeper state, do nothing because the function doesn't exist there | ||
610 | return; | ||
611 | } | ||
612 | lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); | ||
613 | lua_getfield( L, -1, "on_state_create"); | ||
614 | lua_remove( L, -2); | ||
615 | } | ||
616 | // capture error and forward it to main state | ||
617 | if( lua_pcall( L, 0, 0, 0) != LUA_OK) | ||
618 | { | ||
619 | (void) luaL_error( from_, "on_state_create failed: \"%s\"", lua_isstring( L, -1) ? lua_tostring( L, -1) : lua_typename( L, lua_type( L, -1))); | ||
620 | } | ||
621 | STACK_END( L, 0); | ||
622 | } | ||
623 | } | ||
624 | |||
594 | /* | 625 | /* |
595 | * Like 'luaL_openlibs()' but allows the set of libraries be selected | 626 | * Like 'luaL_openlibs()' but allows the set of libraries be selected |
596 | * | 627 | * |
597 | * NULL no libraries, not even base | 628 | * NULL no libraries, not even base |
598 | * "" base library only | 629 | * "" base library only |
599 | * "io,string" named libraries | 630 | * "io,string" named libraries |
600 | * "*" all libraries | 631 | * "*" all libraries |
601 | * | 632 | * |
602 | * Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL. | 633 | * Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL. |
603 | * | 634 | * |
604 | */ | 635 | * *NOT* called for keeper states! |
605 | lua_State* luaG_newstate( lua_State* _from, char const* libs) | 636 | * |
637 | */ | ||
638 | lua_State* luaG_newstate( lua_State* from_, char const* libs_) | ||
606 | { | 639 | { |
607 | // reuse alloc function from the originating state | 640 | // reuse alloc function from the originating state |
608 | #if PROPAGATE_ALLOCF | 641 | #if PROPAGATE_ALLOCF |
609 | PROPAGATE_ALLOCF_PREP( _from); | 642 | PROPAGATE_ALLOCF_PREP( from_); |
610 | #endif // PROPAGATE_ALLOCF | 643 | #endif // PROPAGATE_ALLOCF |
611 | lua_State* L = PROPAGATE_ALLOCF_ALLOC(); | 644 | lua_State* L = PROPAGATE_ALLOCF_ALLOC(); |
612 | 645 | ||
613 | if( L == NULL) | 646 | if( L == NULL) |
614 | { | 647 | { |
615 | (void) luaL_error( _from, "luaG_newstate() failed while creating state; out of memory"); | 648 | (void) luaL_error( from_, "luaG_newstate() failed while creating state; out of memory"); |
616 | } | 649 | } |
617 | 650 | ||
618 | // we'll need this everytime we transfer some C function from/to this state | 651 | // we'll need this everytime we transfer some C function from/to this state |
@@ -620,7 +653,7 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
620 | lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); | 653 | lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); |
621 | 654 | ||
622 | // neither libs (not even 'base') nor special init func: we are done | 655 | // neither libs (not even 'base') nor special init func: we are done |
623 | if( libs == NULL && s_on_state_create_func == NULL) | 656 | if( libs_ == NULL && s_on_state_create_func == NULL) |
624 | { | 657 | { |
625 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate(NULL)\n" INDENT_END)); | 658 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate(NULL)\n" INDENT_END)); |
626 | return L; | 659 | return L; |
@@ -636,17 +669,17 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
636 | 669 | ||
637 | // Anything causes 'base' to be taken in | 670 | // Anything causes 'base' to be taken in |
638 | // | 671 | // |
639 | if( libs != NULL) | 672 | if( libs_ != NULL) |
640 | { | 673 | { |
641 | // special "*" case (mainly to help with LuaJIT compatibility) | 674 | // special "*" case (mainly to help with LuaJIT compatibility) |
642 | // as we are called from luaopen_lanes_core() already, and that would deadlock | 675 | // as we are called from luaopen_lanes_core() already, and that would deadlock |
643 | if( libs[0] == '*' && libs[1] == 0) | 676 | if( libs_[0] == '*' && libs_[1] == 0) |
644 | { | 677 | { |
645 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); | 678 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); |
646 | luaL_openlibs( L); | 679 | luaL_openlibs( L); |
647 | // don't forget lanes.core for regular lane states | 680 | // don't forget lanes.core for regular lane states |
648 | open1lib( L, "lanes.core", 10, _from); | 681 | open1lib( L, "lanes.core", 10, from_); |
649 | libs = NULL; // done with libs | 682 | libs_ = NULL; // done with libs |
650 | } | 683 | } |
651 | else | 684 | else |
652 | { | 685 | { |
@@ -665,11 +698,11 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
665 | STACK_END( L, 0); | 698 | STACK_END( L, 0); |
666 | 699 | ||
667 | // scan all libraries, open them one by one | 700 | // scan all libraries, open them one by one |
668 | if( libs) | 701 | if( libs_) |
669 | { | 702 | { |
670 | char const* p; | 703 | char const* p; |
671 | unsigned int len = 0; | 704 | unsigned int len = 0; |
672 | for( p = libs; *p; p += len) | 705 | for( p = libs_; *p; p += len) |
673 | { | 706 | { |
674 | // skip delimiters ('.' can be part of name for "lanes.core") | 707 | // skip delimiters ('.' can be part of name for "lanes.core") |
675 | while( *p && !isalnum( *p) && *p != '.') | 708 | while( *p && !isalnum( *p) && *p != '.') |
@@ -679,37 +712,17 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
679 | while( isalnum( p[len]) || p[len] == '.') | 712 | while( isalnum( p[len]) || p[len] == '.') |
680 | ++ len; | 713 | ++ len; |
681 | // open library | 714 | // open library |
682 | open1lib( L, p, len, _from); | 715 | open1lib( L, p, len, from_); |
683 | } | 716 | } |
684 | serialize_require( L); | 717 | serialize_require( L); |
685 | } | 718 | } |
686 | 719 | ||
687 | lua_gc( L, LUA_GCRESTART, 0); | 720 | lua_gc( L, LUA_GCRESTART, 0); |
688 | 721 | ||
689 | STACK_CHECK( L); | ||
690 | // call this after the base libraries are loaded and GC is restarted | 722 | // call this after the base libraries are loaded and GC is restarted |
691 | if( s_on_state_create_func != NULL) | 723 | call_on_state_create( L, from_, eLM_LaneBody); |
692 | { | ||
693 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END)); | ||
694 | if( s_on_state_create_func != initialize_on_state_create) | ||
695 | { | ||
696 | // C function: recreate a closure in the new state, bypassing the lookup scheme | ||
697 | lua_pushcfunction( L, s_on_state_create_func); | ||
698 | } | ||
699 | else // Lua function located in the config table | ||
700 | { | ||
701 | lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); | ||
702 | lua_getfield( L, -1, "on_state_create"); | ||
703 | lua_remove( L, -2); | ||
704 | } | ||
705 | // capture error and forward it to main state | ||
706 | if( lua_pcall( L, 0, 0, 0) != LUA_OK) | ||
707 | { | ||
708 | (void) luaL_error( _from, "on_state_create failed: \"%s\"", lua_isstring( L, -1) ? lua_tostring( L, -1) : lua_typename( L, lua_type( L, -1))); | ||
709 | } | ||
710 | STACK_MID( L, 0); | ||
711 | } | ||
712 | 724 | ||
725 | STACK_CHECK( L); | ||
713 | // after all this, register everything we find in our name<->function database | 726 | // after all this, register everything we find in our name<->function database |
714 | lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack | 727 | lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack |
715 | populate_func_lookup_table( L, -1, NULL); | 728 | populate_func_lookup_table( L, -1, NULL); |
@@ -743,7 +756,7 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
743 | /* | 756 | /* |
744 | * The deep proxy cache is a weak valued table listing all deep UD proxies indexed by the deep UD that they are proxying | 757 | * The deep proxy cache is a weak valued table listing all deep UD proxies indexed by the deep UD that they are proxying |
745 | */ | 758 | */ |
746 | #define DEEP_PROXY_CACHE_KEY ((void*)luaG_push_proxy) | 759 | #define DEEP_PROXY_CACHE_KEY ((void*)push_deep_proxy) |
747 | 760 | ||
748 | static void push_registry_subtable_mode( lua_State *L, void *token, const char* mode ); | 761 | static void push_registry_subtable_mode( lua_State *L, void *token, const char* mode ); |
749 | static void push_registry_subtable( lua_State *L, void *token ); | 762 | static void push_registry_subtable( lua_State *L, void *token ); |
@@ -752,107 +765,76 @@ static void push_registry_subtable( lua_State *L, void *token ); | |||
752 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. | 765 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. |
753 | * Pops the both values off the stack. | 766 | * Pops the both values off the stack. |
754 | */ | 767 | */ |
755 | void set_deep_lookup( lua_State *L ) { | 768 | static void set_deep_lookup( lua_State* L) |
756 | 769 | { | |
757 | STACK_GROW(L,3); | 770 | STACK_GROW( L, 3); |
758 | 771 | STACK_CHECK( L); // a b | |
759 | STACK_CHECK( L); | 772 | push_registry_subtable( L, DEEP_LOOKUP_KEY); // a b {} |
760 | #if 1 | 773 | STACK_MID( L, 1); |
761 | push_registry_subtable( L, DEEP_LOOKUP_KEY ); | 774 | lua_insert( L, -3); // {} a b |
762 | #else | 775 | lua_pushvalue( L, -1); // {} a b b |
763 | /* ..to be removed.. */ | 776 | lua_pushvalue( L,-3); // {} a b b a |
764 | lua_pushlightuserdata( L, DEEP_LOOKUP_KEY ); | 777 | lua_rawset( L, -5); // {} a b |
765 | lua_rawget( L, LUA_REGISTRYINDEX ); | 778 | lua_rawset( L, -3); // {} |
766 | 779 | lua_pop( L, 1); // | |
767 | if (lua_isnil(L,-1)) { | 780 | STACK_END( L, -2); |
768 | // First time here; let's make the lookup | ||
769 | // | ||
770 | lua_pop(L,1); | ||
771 | |||
772 | lua_newtable(L); | ||
773 | lua_pushlightuserdata( L, DEEP_LOOKUP_KEY ); | ||
774 | lua_pushvalue(L,-2); | ||
775 | // | ||
776 | // [-3]: {} (2nd ref) | ||
777 | // [-2]: DEEP_LOOKUP_KEY | ||
778 | // [-1]: {} | ||
779 | |||
780 | lua_rawset( L, LUA_REGISTRYINDEX ); | ||
781 | // | ||
782 | // [-1]: lookup table (empty) | ||
783 | } | ||
784 | #endif | ||
785 | STACK_MID( L, 1); | ||
786 | |||
787 | lua_insert(L,-3); | ||
788 | |||
789 | // [-3]: lookup table | ||
790 | // [-2]: A | ||
791 | // [-1]: B | ||
792 | |||
793 | lua_pushvalue( L,-1 ); // B | ||
794 | lua_pushvalue( L,-3 ); // A | ||
795 | lua_rawset( L, -5 ); // B->A | ||
796 | lua_rawset( L, -3 ); // A->B | ||
797 | lua_pop( L,1 ); | ||
798 | |||
799 | STACK_END( L, -2); | ||
800 | } | 781 | } |
801 | 782 | ||
802 | /* | 783 | /* |
803 | * Pops the key (metatable or idfunc) off the stack, and replaces with the | 784 | * Pops the key (metatable or idfunc) off the stack, and replaces with the |
804 | * deep lookup value (idfunc/metatable/nil). | 785 | * deep lookup value (idfunc/metatable/nil). |
805 | */ | 786 | */ |
806 | void get_deep_lookup( lua_State *L ) { | 787 | static void get_deep_lookup( lua_State* L) |
807 | 788 | { | |
808 | STACK_GROW(L,1); | 789 | STACK_GROW( L, 1); |
790 | STACK_CHECK( L); // a | ||
791 | lua_pushlightuserdata( L, DEEP_LOOKUP_KEY); // a DLK | ||
792 | lua_rawget( L, LUA_REGISTRYINDEX); // a {} | ||
809 | 793 | ||
810 | STACK_CHECK( L); | 794 | if( !lua_isnil( L, -1)) |
811 | lua_pushlightuserdata( L, DEEP_LOOKUP_KEY ); | 795 | { |
812 | lua_rawget( L, LUA_REGISTRYINDEX ); | 796 | lua_insert( L, -2); // {} a |
813 | 797 | lua_rawget( L, -2); // {} b | |
814 | if (!lua_isnil(L,-1)) { | 798 | } |
815 | // [-2]: key (metatable or idfunc) | 799 | lua_remove( L, -2); // a|b |
816 | // [-1]: lookup table | 800 | STACK_END( L, 0); |
817 | |||
818 | lua_insert( L, -2 ); | ||
819 | lua_rawget( L, -2 ); | ||
820 | |||
821 | // [-2]: lookup table | ||
822 | // [-1]: value (metatable / idfunc / nil) | ||
823 | } | ||
824 | lua_remove(L,-2); | ||
825 | // remove lookup, or unused key | ||
826 | STACK_END( L, 0); | ||
827 | } | 801 | } |
828 | 802 | ||
829 | /* | 803 | /* |
830 | * Return the registered ID function for 'index' (deep userdata proxy), | 804 | * Return the registered ID function for 'index' (deep userdata proxy), |
831 | * or NULL if 'index' is not a deep userdata proxy. | 805 | * or NULL if 'index' is not a deep userdata proxy. |
832 | */ | 806 | */ |
833 | static | 807 | static inline luaG_IdFunction get_idfunc( lua_State* L, int index, enum eLookupMode mode_) |
834 | luaG_IdFunction get_idfunc( lua_State *L, int index ) | ||
835 | { | 808 | { |
836 | luaG_IdFunction ret; | 809 | // when looking inside a keeper, we are 100% sure the object is a deep userdata |
837 | 810 | if( mode_ == eLM_FromKeeper) | |
838 | index = lua_absindex( L, index); | 811 | { |
839 | 812 | DEEP_PRELUDE** proxy = (DEEP_PRELUDE**) lua_touserdata( L, index); | |
840 | STACK_GROW(L,1); | 813 | // we can (and must) cast and fetch the internally stored idfunc |
841 | 814 | return (*proxy)->idfunc; | |
842 | STACK_CHECK( L); | 815 | } |
843 | if (!lua_getmetatable( L, index )) | 816 | else |
844 | return NULL; // no metatable | 817 | { |
845 | 818 | // essentially we are making sure that the metatable of the object we want to copy is stored in our metatable/idfunc database | |
846 | // [-1]: metatable of [index] | 819 | // it is the only way to ensure that the userdata is indeed a deep userdata! |
820 | // of course, we could just trust the caller, but we won't | ||
821 | luaG_IdFunction ret; | ||
822 | STACK_GROW( L, 1); | ||
823 | STACK_CHECK( L); | ||
824 | |||
825 | if( !lua_getmetatable( L, index)) // deep ... metatable? | ||
826 | { | ||
827 | return NULL; // no metatable: can't be a deep userdata object! | ||
828 | } | ||
847 | 829 | ||
848 | get_deep_lookup(L); | 830 | // replace metatable with the idfunc pointer, if it is actually a deep userdata |
849 | // | 831 | get_deep_lookup( L); // deep ... idfunc|nil |
850 | // [-1]: idfunc/nil | ||
851 | 832 | ||
852 | ret= (luaG_IdFunction)lua_touserdata(L,-1); | 833 | ret = (luaG_IdFunction) lua_touserdata( L, -1); // NULL if not a userdata |
853 | lua_pop(L,1); | 834 | lua_pop( L, 1); |
854 | STACK_END( L, 0); | 835 | STACK_END( L, 0); |
855 | return ret; | 836 | return ret; |
837 | } | ||
856 | } | 838 | } |
857 | 839 | ||
858 | 840 | ||
@@ -862,205 +844,190 @@ luaG_IdFunction get_idfunc( lua_State *L, int index ) | |||
862 | * End of life for a proxy object; reduce the deep reference count and clean | 844 | * End of life for a proxy object; reduce the deep reference count and clean |
863 | * it up if reaches 0. | 845 | * it up if reaches 0. |
864 | */ | 846 | */ |
865 | static | 847 | static int deep_userdata_gc( lua_State* L) |
866 | int deep_userdata_gc( lua_State *L ) | ||
867 | { | 848 | { |
868 | DEEP_PRELUDE **proxy= (DEEP_PRELUDE**)lua_touserdata( L, 1 ); | 849 | DEEP_PRELUDE** proxy = (DEEP_PRELUDE**) lua_touserdata( L, 1); |
869 | DEEP_PRELUDE *p= *proxy; | 850 | DEEP_PRELUDE* p = *proxy; |
870 | int v; | 851 | int v; |
871 | 852 | ||
872 | *proxy= 0; // make sure we don't use it any more | 853 | *proxy = 0; // make sure we don't use it any more |
873 | 854 | ||
874 | MUTEX_LOCK( &deep_lock ); | 855 | MUTEX_LOCK( &deep_lock); |
875 | v= --(p->refcount); | 856 | v = -- (p->refcount); |
876 | MUTEX_UNLOCK( &deep_lock ); | 857 | MUTEX_UNLOCK( &deep_lock); |
877 | |||
878 | if (v==0) | ||
879 | { | ||
880 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup | ||
881 | // | ||
882 | luaG_IdFunction idfunc = get_idfunc(L,1); | ||
883 | ASSERT_L(idfunc); | ||
884 | |||
885 | lua_settop( L, 0); // clean stack so we can call 'idfunc' directly | ||
886 | 858 | ||
887 | // void= idfunc( "delete", lightuserdata ) | 859 | if( v == 0) |
888 | // | 860 | { |
889 | lua_pushlightuserdata( L, p->deep ); | 861 | // clean stack so we can call 'idfunc' directly |
890 | idfunc( L, "delete"); | 862 | lua_settop( L, 0); |
891 | 863 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup | |
892 | // top was set to 0, then userdata was pushed. "delete" might want to pop the userdata (we don't care), but should not push anything! | 864 | lua_pushlightuserdata( L, p->deep); |
893 | if ( lua_gettop( L) > 1) | 865 | ASSERT_L( p->idfunc); |
894 | luaL_error( L, "Bad idfunc on \"delete\": returned something"); | 866 | p->idfunc( L, eDO_delete); |
895 | 867 | DEEP_FREE( (void*) p); | |
896 | DEEP_FREE( (void*)p ); | 868 | |
897 | } | 869 | // top was set to 0, then userdata was pushed. "delete" might want to pop the userdata (we don't care), but should not push anything! |
898 | return 0; | 870 | if ( lua_gettop( L) > 1) |
871 | { | ||
872 | luaL_error( L, "Bad idfunc(eDO_delete): should not push anything"); | ||
873 | } | ||
874 | } | ||
875 | return 0; | ||
899 | } | 876 | } |
900 | 877 | ||
901 | 878 | ||
902 | /* | 879 | /* |
903 | * Push a proxy userdata on the stack. | 880 | * Push a proxy userdata on the stack. |
904 | * | 881 | * returns NULL if ok, else some error string related to bad idfunc behavior or module require problem |
905 | * Initializes necessary structures if it's the first time 'idfunc' is being | 882 | * (error cannot happen with mode_ == eLM_ToKeeper) |
906 | * used in this Lua state (metatable, registring it). Otherwise, increments the | 883 | * |
907 | * reference count. | 884 | * Initializes necessary structures if it's the first time 'idfunc' is being |
908 | */ | 885 | * used in this Lua state (metatable, registring it). Otherwise, increments the |
909 | void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelude ) | 886 | * reference count. |
887 | */ | ||
888 | char const* push_deep_proxy( lua_State* L, DEEP_PRELUDE* prelude, enum eLookupMode mode_) | ||
910 | { | 889 | { |
911 | DEEP_PRELUDE **proxy; | 890 | DEEP_PRELUDE** proxy; |
912 | |||
913 | // Check if a proxy already exists | ||
914 | push_registry_subtable_mode(L, DEEP_PROXY_CACHE_KEY, "v"); | ||
915 | lua_pushlightuserdata(L, prelude->deep); | ||
916 | lua_rawget(L, -2); | ||
917 | if (!lua_isnil(L, -1)) | ||
918 | { | ||
919 | lua_remove(L, -2); // deep proxy cache table | ||
920 | return; | ||
921 | } | ||
922 | else | ||
923 | { | ||
924 | lua_pop(L, 2); // Pop the nil and proxy cache table | ||
925 | } | ||
926 | |||
927 | MUTEX_LOCK( &deep_lock ); | ||
928 | ++(prelude->refcount); // one more proxy pointing to this deep data | ||
929 | MUTEX_UNLOCK( &deep_lock ); | ||
930 | |||
931 | STACK_GROW(L,4); | ||
932 | |||
933 | STACK_CHECK( L); | ||
934 | |||
935 | proxy= lua_newuserdata( L, sizeof( DEEP_PRELUDE* ) ); | ||
936 | ASSERT_L(proxy); | ||
937 | *proxy= prelude; | ||
938 | 891 | ||
939 | // Get/create metatable for 'idfunc' (in this state) | 892 | // Check if a proxy already exists |
940 | // | 893 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC |
941 | lua_pushlightuserdata( L, idfunc ); // key | 894 | lua_pushlightuserdata( L, prelude->deep); // DPC deep |
942 | get_deep_lookup(L); | 895 | lua_rawget( L, -2); // DPC proxy |
943 | // | 896 | if ( !lua_isnil( L, -1)) |
944 | // [-2]: proxy | 897 | { |
945 | // [-1]: metatable / nil | 898 | lua_remove( L, -2); // proxy |
946 | 899 | return NULL; | |
947 | if (lua_isnil(L,-1)) | 900 | } |
948 | { | 901 | else |
949 | // No metatable yet. We have two things to do: | 902 | { |
950 | // 1 - make one and register it | 903 | lua_pop( L, 1); // DPC |
951 | { | 904 | } |
952 | int oldtop; | ||
953 | 905 | ||
954 | lua_pop( L, 1); | 906 | MUTEX_LOCK( &deep_lock); |
907 | ++ (prelude->refcount); // one more proxy pointing to this deep data | ||
908 | MUTEX_UNLOCK( &deep_lock); | ||
955 | 909 | ||
956 | // tbl= idfunc( "metatable" ) | 910 | STACK_GROW( L, 7); |
957 | // | 911 | STACK_CHECK( L); |
958 | oldtop = lua_gettop( L); | ||
959 | idfunc( L, "metatable"); | ||
960 | // | ||
961 | // [-2]: proxy | ||
962 | // [-1]: metatable (returned by 'idfunc') | ||
963 | 912 | ||
964 | if (lua_gettop( L) - oldtop != 1 || !lua_istable(L, -1)) | 913 | proxy = lua_newuserdata( L, sizeof( DEEP_PRELUDE*)); // DPC proxy |
965 | { | 914 | ASSERT_L( proxy); |
966 | luaL_error( L, "Bad idfunc on \"metatable\": did not return one" ); | 915 | *proxy = prelude; |
967 | } | ||
968 | 916 | ||
969 | // Add '__gc' method | 917 | // Get/create metatable for 'idfunc' (in this state) |
970 | // | 918 | lua_pushlightuserdata( L, prelude->idfunc); // DPC proxy idfunc |
971 | lua_pushcfunction( L, deep_userdata_gc ); | 919 | get_deep_lookup( L); // DPC proxy metatable? |
972 | lua_setfield( L, -2, "__gc" ); | ||
973 | 920 | ||
974 | // Memorize for later rounds | 921 | if( lua_isnil( L, -1)) // // No metatable yet. |
975 | // | 922 | { |
976 | lua_pushvalue( L,-1 ); | 923 | char const* modname; |
977 | lua_pushlightuserdata( L, idfunc ); | 924 | int oldtop = lua_gettop( L); // DPC proxy nil |
978 | // | 925 | lua_pop( L, 1); // DPC proxy |
979 | // [-4]: proxy | 926 | // 1 - make one and register it |
980 | // [-3]: metatable (2nd ref) | 927 | if( mode_ != eLM_ToKeeper) |
981 | // [-2]: metatable | 928 | { |
982 | // [-1]: idfunc | 929 | prelude->idfunc( L, eDO_metatable); // DPC proxy metatable |
983 | 930 | if( lua_gettop( L) - oldtop != 0 || !lua_istable( L, -1)) | |
984 | set_deep_lookup(L); | 931 | { |
985 | } | 932 | lua_pop( L, 3); // |
986 | 933 | return "Bad idfunc(eOP_metatable): unexpected pushed value"; | |
987 | // 2 - cause the target state to require the module that exported the idfunc | 934 | } |
988 | // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc | 935 | // make sure the idfunc didn't export __gc, as we will store our own |
989 | STACK_CHECK( L); | 936 | lua_getfield( L, -1, "__gc"); // DPC proxy metatable __gc |
990 | { | 937 | if( !lua_isnil( L, -1)) |
991 | char const * modname; | 938 | { |
992 | // make sure the function pushed a single value on the stack! | 939 | lua_pop( L, 4); // |
993 | { | 940 | return "idfunc-created metatable shouldn't contain __gc"; |
994 | int oldtop = lua_gettop( L); | 941 | } |
995 | idfunc( L, "module"); // ... "module"/nil | 942 | lua_pop( L, 1); // DPC proxy metatable |
996 | if( lua_gettop( L) - oldtop != 1) | 943 | } |
997 | { | 944 | else |
998 | luaL_error( L, "Bad idfunc on \"module\": should return a single value"); | 945 | { |
999 | } | 946 | // keepers need a minimal metatable that only contains __gc |
1000 | } | 947 | lua_newtable( L); // DPC proxy metatable |
1001 | modname = luaL_optstring( L, -1, NULL); // raises an error if not a string or nil | 948 | } |
1002 | if( modname) // we actually got a module name | 949 | // Add our own '__gc' method |
1003 | { | 950 | lua_pushcfunction( L, deep_userdata_gc); // DPC proxy metatable __gc |
1004 | // somehow, L.registry._LOADED can exist without having registered the 'package' library. | 951 | lua_setfield( L, -2, "__gc"); // DPC proxy metatable |
1005 | lua_getglobal( L, "require"); // ... "module" require() | ||
1006 | // check that the module is already loaded (or being loaded, we are happy either way) | ||
1007 | if( lua_isfunction( L, -1)) | ||
1008 | { | ||
1009 | lua_insert( L, -2); // ... require() "module" | ||
1010 | lua_getfield( L, LUA_REGISTRYINDEX, "_LOADED"); // ... require() "module" L.registry._LOADED | ||
1011 | if( lua_istable( L, -1)) | ||
1012 | { | ||
1013 | bool_t alreadyloaded; | ||
1014 | lua_pushvalue( L, -2); // ... require() "module" L.registry._LOADED "module" | ||
1015 | lua_rawget( L, -2); // ... require() "module" L.registry._LOADED module | ||
1016 | alreadyloaded = lua_toboolean( L, -1); | ||
1017 | if( !alreadyloaded) // not loaded | ||
1018 | { | ||
1019 | lua_pop( L, 2); // ... require() "module" | ||
1020 | lua_call( L, 1, 0); // call require "modname" // ... | ||
1021 | } | ||
1022 | else // already loaded, we are happy | ||
1023 | { | ||
1024 | lua_pop( L, 4); // ... | ||
1025 | } | ||
1026 | } | ||
1027 | else // no L.registry._LOADED; can this ever happen? | ||
1028 | { | ||
1029 | luaL_error( L, "unexpected error while requiring a module"); | ||
1030 | lua_pop( L, 3); // ... | ||
1031 | } | ||
1032 | } | ||
1033 | else // a module name, but no require() function :-( | ||
1034 | { | ||
1035 | luaL_error( L, "lanes receiving deep userdata should register the 'package' library"); | ||
1036 | lua_pop( L, 2); // ... | ||
1037 | } | ||
1038 | } | ||
1039 | else // no module name | ||
1040 | { | ||
1041 | lua_pop( L, 1); // ... | ||
1042 | } | ||
1043 | } | ||
1044 | STACK_END( L, 0); | ||
1045 | } | ||
1046 | STACK_MID( L, 2); | ||
1047 | ASSERT_L( lua_isuserdata(L,-2) ); | ||
1048 | ASSERT_L( lua_istable(L,-1) ); | ||
1049 | 952 | ||
1050 | // [-2]: proxy userdata | 953 | // Memorize for later rounds |
1051 | // [-1]: metatable to use | 954 | lua_pushvalue( L, -1); // DPC proxy metatable metatable |
955 | lua_pushlightuserdata( L, prelude->idfunc); // DPC proxy metatable metatable idfunc | ||
956 | set_deep_lookup( L); // DPC proxy metatable | ||
1052 | 957 | ||
1053 | lua_setmetatable( L, -2 ); | 958 | // 2 - cause the target state to require the module that exported the idfunc |
1054 | 959 | // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc | |
1055 | // If we're here, we obviously had to create a new proxy, so cache it. | 960 | { |
1056 | push_registry_subtable_mode(L, DEEP_PROXY_CACHE_KEY, "v"); | 961 | int oldtop = lua_gettop( L); |
1057 | lua_pushlightuserdata(L, (*proxy)->deep); | 962 | modname = (char const*) prelude->idfunc( L, eDO_module); // DPC proxy metatable |
1058 | lua_pushvalue(L, -3); // Copy of the proxy | 963 | // make sure the function pushed nothing on the stack! |
1059 | lua_rawset(L, -3); | 964 | if( lua_gettop( L) - oldtop != 0) |
1060 | lua_pop(L, 1); // Remove the cache proxy table | 965 | { |
1061 | 966 | lua_pop( L, 3); // | |
1062 | STACK_END( L, 1); | 967 | return "Bad idfunc(eOP_module): should not push anything"; |
1063 | // [-1]: proxy userdata | 968 | } |
969 | } | ||
970 | if( modname) // we actually got a module name | ||
971 | { | ||
972 | // somehow, L.registry._LOADED can exist without having registered the 'package' library. | ||
973 | lua_getglobal( L, "require"); // DPC proxy metatable require() | ||
974 | // check that the module is already loaded (or being loaded, we are happy either way) | ||
975 | if( lua_isfunction( L, -1)) | ||
976 | { | ||
977 | lua_pushstring( L, modname); // DPC proxy metatable require() "module" | ||
978 | lua_getfield( L, LUA_REGISTRYINDEX, "_LOADED"); // DPC proxy metatable require() "module" _R._LOADED | ||
979 | if( lua_istable( L, -1)) | ||
980 | { | ||
981 | bool_t alreadyloaded; | ||
982 | lua_pushvalue( L, -2); // DPC proxy metatable require() "module" _R._LOADED "module" | ||
983 | lua_rawget( L, -2); // DPC proxy metatable require() "module" _R._LOADED module | ||
984 | alreadyloaded = lua_toboolean( L, -1); | ||
985 | if( !alreadyloaded) // not loaded | ||
986 | { | ||
987 | int require_result; | ||
988 | lua_pop( L, 2); // DPC proxy metatable require() "module" | ||
989 | // require "modname" | ||
990 | require_result = lua_pcall( L, 1, 0, 0); // DPC proxy metatable error? | ||
991 | if( require_result != LUA_OK) | ||
992 | { | ||
993 | // failed, return the error message | ||
994 | lua_pushfstring( L, "error while requiring '%s' identified by idfunc(eOP_module): ", modname); | ||
995 | lua_insert( L, -2); // DPC proxy metatable prefix error | ||
996 | lua_concat( L, 2); // DPC proxy metatable error | ||
997 | return lua_tostring( L, -1); | ||
998 | } | ||
999 | } | ||
1000 | else // already loaded, we are happy | ||
1001 | { | ||
1002 | lua_pop( L, 4); // DPC proxy metatable | ||
1003 | } | ||
1004 | } | ||
1005 | else // no L.registry._LOADED; can this ever happen? | ||
1006 | { | ||
1007 | lua_pop( L, 6); // | ||
1008 | return "unexpected error while requiring a module identified by idfunc(eOP_module)"; | ||
1009 | } | ||
1010 | } | ||
1011 | else // a module name, but no require() function :-( | ||
1012 | { | ||
1013 | lua_pop( L, 4); // | ||
1014 | return "lanes receiving deep userdata should register the 'package' library"; | ||
1015 | } | ||
1016 | } | ||
1017 | } | ||
1018 | STACK_MID( L, 2); // DPC proxy metatable | ||
1019 | ASSERT_L( lua_isuserdata( L, -2)); | ||
1020 | ASSERT_L( lua_istable( L, -1)); | ||
1021 | lua_setmetatable( L, -2); // DPC proxy | ||
1022 | |||
1023 | // If we're here, we obviously had to create a new proxy, so cache it. | ||
1024 | lua_pushlightuserdata( L, (*proxy)->deep); // DPC proxy deep | ||
1025 | lua_pushvalue( L, -2); // DPC proxy deep proxy | ||
1026 | lua_rawset( L, -4); // DPC proxy | ||
1027 | lua_remove( L, -2); // proxy | ||
1028 | ASSERT_L( lua_isuserdata( L, -1)); | ||
1029 | STACK_END( L, 0); | ||
1030 | return NULL; | ||
1064 | } | 1031 | } |
1065 | 1032 | ||
1066 | 1033 | ||
@@ -1086,39 +1053,34 @@ void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelud | |||
1086 | * | 1053 | * |
1087 | * Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' | 1054 | * Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' |
1088 | */ | 1055 | */ |
1089 | int luaG_deep_userdata( lua_State *L, luaG_IdFunction idfunc) | 1056 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) |
1090 | { | 1057 | { |
1091 | int oldtop; | 1058 | char const* errmsg; |
1092 | 1059 | DEEP_PRELUDE* prelude = DEEP_MALLOC( sizeof(DEEP_PRELUDE)); | |
1093 | DEEP_PRELUDE *prelude= DEEP_MALLOC( sizeof(DEEP_PRELUDE) ); | 1060 | ASSERT_L( prelude); |
1094 | ASSERT_L(prelude); | ||
1095 | |||
1096 | prelude->refcount= 0; // 'luaG_push_proxy' will lift it to 1 | ||
1097 | |||
1098 | STACK_GROW(L,1); | ||
1099 | STACK_CHECK( L); | ||
1100 | |||
1101 | // lightuserdata= idfunc( "new" [, ...] ) | ||
1102 | // | ||
1103 | oldtop = lua_gettop( L); | ||
1104 | idfunc(L, "new"); | ||
1105 | |||
1106 | if( lua_gettop( L) - oldtop != 1 || lua_type( L, -1) != LUA_TLIGHTUSERDATA) | ||
1107 | { | ||
1108 | luaL_error( L, "Bad idfunc on \"new\": did not return light userdata"); | ||
1109 | } | ||
1110 | 1061 | ||
1111 | prelude->deep= lua_touserdata(L,-1); | 1062 | prelude->refcount = 0; // 'push_deep_proxy' will lift it to 1 |
1112 | ASSERT_L(prelude->deep); | 1063 | prelude->idfunc = idfunc; |
1113 | 1064 | ||
1114 | lua_pop(L,1); // pop deep data | 1065 | STACK_GROW( L, 1); |
1115 | 1066 | STACK_CHECK( L); | |
1116 | luaG_push_proxy( L, idfunc, prelude ); | 1067 | { |
1117 | // | 1068 | int oldtop = lua_gettop( L); |
1118 | // [-1]: proxy userdata | 1069 | prelude->deep = idfunc( L, eDO_new); |
1070 | ASSERT_L( prelude->deep); | ||
1119 | 1071 | ||
1120 | STACK_END( L, 1); | 1072 | if( lua_gettop( L) - oldtop != 0) |
1121 | return 1; | 1073 | { |
1074 | luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); | ||
1075 | } | ||
1076 | } | ||
1077 | errmsg = push_deep_proxy( L, prelude, eLM_LaneBody); // proxy | ||
1078 | if( errmsg != NULL) | ||
1079 | { | ||
1080 | luaL_error( L, errmsg); | ||
1081 | } | ||
1082 | STACK_END( L, 1); | ||
1083 | return 1; | ||
1122 | } | 1084 | } |
1123 | 1085 | ||
1124 | 1086 | ||
@@ -1128,52 +1090,51 @@ int luaG_deep_userdata( lua_State *L, luaG_IdFunction idfunc) | |||
1128 | * Reference count is not changed, and access to the deep userdata is not | 1090 | * Reference count is not changed, and access to the deep userdata is not |
1129 | * serialized. It is the module's responsibility to prevent conflicting usage. | 1091 | * serialized. It is the module's responsibility to prevent conflicting usage. |
1130 | */ | 1092 | */ |
1131 | void *luaG_todeep( lua_State *L, luaG_IdFunction idfunc, int index ) | 1093 | void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) |
1132 | { | 1094 | { |
1133 | DEEP_PRELUDE **proxy; | 1095 | DEEP_PRELUDE** proxy; |
1134 | 1096 | ||
1135 | STACK_CHECK( L); | 1097 | STACK_CHECK( L); |
1136 | if( get_idfunc(L,index) != idfunc) | 1098 | // ensure it is actually a deep userdata |
1137 | return NULL; // no metatable, or wrong kind | 1099 | if( get_idfunc( L, index, eLM_LaneBody) != idfunc) |
1100 | { | ||
1101 | return NULL; // no metatable, or wrong kind | ||
1102 | } | ||
1138 | 1103 | ||
1139 | proxy= (DEEP_PRELUDE**)lua_touserdata( L, index ); | 1104 | proxy = (DEEP_PRELUDE**) lua_touserdata( L, index); |
1140 | STACK_END( L, 0); | 1105 | STACK_END( L, 0); |
1141 | 1106 | ||
1142 | return (*proxy)->deep; | 1107 | return (*proxy)->deep; |
1143 | } | 1108 | } |
1144 | 1109 | ||
1145 | 1110 | ||
1146 | /* | 1111 | /* |
1147 | * Copy deep userdata between two separate Lua states. | 1112 | * Copy deep userdata between two separate Lua states (from L to L2) |
1148 | * | 1113 | * |
1149 | * Returns: | 1114 | * Returns: |
1150 | * the id function of the copied value, or NULL for non-deep userdata | 1115 | * the id function of the copied value, or NULL for non-deep userdata |
1151 | * (not copied) | 1116 | * (not copied) |
1152 | */ | 1117 | */ |
1153 | static | 1118 | static luaG_IdFunction copydeep( lua_State* L, lua_State* L2, int index, enum eLookupMode mode_) |
1154 | luaG_IdFunction luaG_copydeep( lua_State *L, lua_State *L2, int index ) | ||
1155 | { | 1119 | { |
1156 | DEEP_PRELUDE **proxy; | 1120 | char const* errmsg; |
1157 | DEEP_PRELUDE *p; | 1121 | luaG_IdFunction idfunc = get_idfunc( L, index, mode_); |
1158 | 1122 | if( idfunc == NULL) | |
1159 | luaG_IdFunction idfunc = get_idfunc( L, index); | 1123 | { |
1160 | if (!idfunc) | 1124 | return NULL; // not a deep userdata |
1161 | return NULL; // not a deep userdata | 1125 | } |
1162 | |||
1163 | // Increment reference count | ||
1164 | // | ||
1165 | proxy= (DEEP_PRELUDE**)lua_touserdata( L, index ); | ||
1166 | p= *proxy; | ||
1167 | |||
1168 | luaG_push_proxy( L2, idfunc, p ); | ||
1169 | // | ||
1170 | // L2 [-1]: proxy userdata | ||
1171 | 1126 | ||
1172 | return idfunc; | 1127 | errmsg = push_deep_proxy( L2, *(DEEP_PRELUDE**) lua_touserdata( L, index), mode_); |
1128 | if( errmsg != NULL) | ||
1129 | { | ||
1130 | // raise the error in the proper state (not the keeper) | ||
1131 | lua_State* errL = (mode_ == eLM_FromKeeper) ? L2 : L; | ||
1132 | luaL_error( errL, errmsg); | ||
1133 | } | ||
1134 | return idfunc; | ||
1173 | } | 1135 | } |
1174 | 1136 | ||
1175 | 1137 | ||
1176 | |||
1177 | /*---=== Inter-state copying ===---*/ | 1138 | /*---=== Inter-state copying ===---*/ |
1178 | 1139 | ||
1179 | /*-- Metatable copying --*/ | 1140 | /*-- Metatable copying --*/ |
@@ -1190,51 +1151,45 @@ luaG_IdFunction luaG_copydeep( lua_State *L, lua_State *L2, int index ) | |||
1190 | /* | 1151 | /* |
1191 | * Does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it | 1152 | * Does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it |
1192 | */ | 1153 | */ |
1193 | static | 1154 | static void push_registry_subtable_mode( lua_State* L, void* key_, const char* mode_) |
1194 | void push_registry_subtable_mode( lua_State *L, void *token, const char* mode ) { | 1155 | { |
1156 | STACK_GROW( L, 3); | ||
1157 | STACK_CHECK( L); | ||
1195 | 1158 | ||
1196 | STACK_GROW(L,3); | 1159 | lua_pushlightuserdata( L, key_); // key |
1160 | lua_rawget( L, LUA_REGISTRYINDEX); // {}|nil | ||
1197 | 1161 | ||
1198 | STACK_CHECK( L); | 1162 | if( lua_isnil( L, -1)) |
1199 | 1163 | { | |
1200 | lua_pushlightuserdata( L, token ); | 1164 | lua_pop( L, 1); // |
1201 | lua_rawget( L, LUA_REGISTRYINDEX ); | 1165 | lua_newtable( L); // {} |
1202 | // | 1166 | lua_pushlightuserdata( L, key_); // {} key |
1203 | // [-1]: nil/subtable | 1167 | lua_pushvalue( L, -2); // {} key {} |
1204 | 1168 | ||
1205 | if (lua_isnil(L,-1)) { | 1169 | // _R[key_] = {} |
1206 | lua_pop(L,1); | 1170 | lua_rawset( L, LUA_REGISTRYINDEX); // {} |
1207 | lua_newtable(L); // value | ||
1208 | lua_pushlightuserdata( L, token ); // key | ||
1209 | lua_pushvalue(L,-2); | ||
1210 | // | ||
1211 | // [-3]: value (2nd ref) | ||
1212 | // [-2]: key | ||
1213 | // [-1]: value | ||
1214 | |||
1215 | lua_rawset( L, LUA_REGISTRYINDEX ); | ||
1216 | |||
1217 | // Set it's metatable if requested | ||
1218 | if (mode) { | ||
1219 | lua_newtable(L); | ||
1220 | lua_pushliteral(L, "__mode"); | ||
1221 | lua_pushstring(L, mode); | ||
1222 | lua_rawset(L, -3); | ||
1223 | lua_setmetatable(L, -2); | ||
1224 | } | ||
1225 | } | ||
1226 | STACK_END( L, 1); | ||
1227 | 1171 | ||
1228 | ASSERT_L( lua_istable(L,-1) ); | 1172 | // Set its metatable if requested |
1173 | if( mode_) | ||
1174 | { | ||
1175 | lua_newtable( L); // {} mt | ||
1176 | lua_pushliteral( L, "__mode"); // {} mt "__mode" | ||
1177 | lua_pushstring( L, mode_); // {} mt "__mode" mode | ||
1178 | lua_rawset( L, -3); // {} mt | ||
1179 | lua_setmetatable( L, -2); // {} | ||
1180 | } | ||
1181 | } | ||
1182 | STACK_END( L, 1); | ||
1183 | ASSERT_L( lua_istable( L, -1)); | ||
1229 | } | 1184 | } |
1230 | 1185 | ||
1231 | /* | 1186 | /* |
1232 | * Push a registry subtable (keyed by unique 'token') onto the stack. | 1187 | * Push a registry subtable (keyed by unique 'key_') onto the stack. |
1233 | * If the subtable does not exist, it is created and chained. | 1188 | * If the subtable does not exist, it is created and chained. |
1234 | */ | 1189 | */ |
1235 | static | 1190 | static inline void push_registry_subtable( lua_State* L, void* key_) |
1236 | void push_registry_subtable( lua_State *L, void *token ) { | 1191 | { |
1237 | push_registry_subtable_mode(L, token, NULL); | 1192 | push_registry_subtable_mode( L, key_, NULL); |
1238 | } | 1193 | } |
1239 | 1194 | ||
1240 | #define REG_MTID ( (void*) get_mt_id ) | 1195 | #define REG_MTID ( (void*) get_mt_id ) |
@@ -1864,12 +1819,10 @@ static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, ui | |||
1864 | 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_) | 1819 | 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_) |
1865 | { | 1820 | { |
1866 | bool_t ret = TRUE; | 1821 | bool_t ret = TRUE; |
1867 | |||
1868 | STACK_GROW( L2, 1); | 1822 | STACK_GROW( L2, 1); |
1869 | |||
1870 | STACK_CHECK( L2); | 1823 | STACK_CHECK( L2); |
1871 | 1824 | ||
1872 | switch ( lua_type( L, i)) | 1825 | switch( lua_type( L, i)) |
1873 | { | 1826 | { |
1874 | /* Basic types allowed both as values, and as table keys */ | 1827 | /* Basic types allowed both as values, and as table keys */ |
1875 | 1828 | ||
@@ -1921,7 +1874,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1921 | /* Allow only deep userdata entities to be copied across | 1874 | /* Allow only deep userdata entities to be copied across |
1922 | */ | 1875 | */ |
1923 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "USERDATA\n" INDENT_END)); | 1876 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "USERDATA\n" INDENT_END)); |
1924 | if( !luaG_copydeep( L, L2, i)) | 1877 | if( !copydeep( L, L2, i, mode_)) |
1925 | { | 1878 | { |
1926 | // Not a deep full userdata | 1879 | // Not a deep full userdata |
1927 | bool_t demote = FALSE; | 1880 | bool_t demote = FALSE; |
@@ -2129,7 +2082,6 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
2129 | } | 2082 | } |
2130 | 2083 | ||
2131 | STACK_END( L2, ret ? 1 : 0); | 2084 | STACK_END( L2, ret ? 1 : 0); |
2132 | |||
2133 | return ret; | 2085 | return ret; |
2134 | } | 2086 | } |
2135 | 2087 | ||
@@ -2225,7 +2177,8 @@ void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx, enum eLooku | |||
2225 | // package.loaders is renamed package.searchers in Lua 5.2 | 2177 | // package.loaders is renamed package.searchers in Lua 5.2 |
2226 | // but don't copy it anyway, as the function names change depending on the slot index! | 2178 | // but don't copy it anyway, as the function names change depending on the slot index! |
2227 | // users should provide an on_state_create function to setup custom loaders instead | 2179 | // users should provide an on_state_create function to setup custom loaders instead |
2228 | char const* entries[] = { "path", "cpath", "preload"/*, (LUA_VERSION_NUM == 501) ? "loaders" : "searchers"*/, NULL}; | 2180 | // don't copy package.preload in keeper states (they don't know how to translate functions) |
2181 | char const* entries[] = { "path", "cpath", (mode_ == eLM_LaneBody) ? "preload" : NULL/*, (LUA_VERSION_NUM == 501) ? "loaders" : "searchers"*/, NULL}; | ||
2229 | for( i = 0; entries[i]; ++ i) | 2182 | for( i = 0; entries[i]; ++ i) |
2230 | { | 2183 | { |
2231 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s\n" INDENT_END, entries[i])); | 2184 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s\n" INDENT_END, entries[i])); |