diff options
-rw-r--r-- | lapi.c | 110 | ||||
-rw-r--r-- | lcode.c | 8 | ||||
-rw-r--r-- | lgc.c | 25 | ||||
-rw-r--r-- | llex.c | 10 | ||||
-rw-r--r-- | lobject.h | 7 | ||||
-rw-r--r-- | lstate.c | 7 | ||||
-rw-r--r-- | ltable.c | 330 | ||||
-rw-r--r-- | ltable.h | 99 | ||||
-rw-r--r-- | ltests.c | 10 | ||||
-rw-r--r-- | ltm.c | 11 | ||||
-rw-r--r-- | lvm.c | 135 | ||||
-rw-r--r-- | lvm.h | 51 |
12 files changed, 529 insertions, 274 deletions
@@ -637,50 +637,44 @@ LUA_API int lua_pushthread (lua_State *L) { | |||
637 | 637 | ||
638 | 638 | ||
639 | l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) { | 639 | l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) { |
640 | const TValue *slot; | 640 | int hres; |
641 | TString *str = luaS_new(L, k); | 641 | TString *str = luaS_new(L, k); |
642 | if (luaV_fastget(L, t, str, slot, luaH_getstr)) { | 642 | luaV_fastget(t, str, s2v(L->top.p), luaH_getstr, hres); |
643 | setobj2s(L, L->top.p, slot); | 643 | if (hres == HOK) { |
644 | api_incr_top(L); | 644 | api_incr_top(L); |
645 | } | 645 | } |
646 | else { | 646 | else { |
647 | setsvalue2s(L, L->top.p, str); | 647 | setsvalue2s(L, L->top.p, str); |
648 | api_incr_top(L); | 648 | api_incr_top(L); |
649 | luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot); | 649 | luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, hres); |
650 | } | 650 | } |
651 | lua_unlock(L); | 651 | lua_unlock(L); |
652 | return ttype(s2v(L->top.p - 1)); | 652 | return ttype(s2v(L->top.p - 1)); |
653 | } | 653 | } |
654 | 654 | ||
655 | 655 | ||
656 | /* | 656 | static void getGlobalTable (lua_State *L, TValue *gt) { |
657 | ** Get the global table in the registry. Since all predefined | 657 | Table *registry = hvalue(&G(L)->l_registry); |
658 | ** indices in the registry were inserted right when the registry | 658 | luaH_getint(registry, LUA_RIDX_GLOBALS, gt); |
659 | ** was created and never removed, they must always be in the array | 659 | } |
660 | ** part of the registry. | ||
661 | */ | ||
662 | #define getGtable(L) \ | ||
663 | (&hvalue(&G(L)->l_registry)->array[LUA_RIDX_GLOBALS - 1]) | ||
664 | 660 | ||
665 | 661 | ||
666 | LUA_API int lua_getglobal (lua_State *L, const char *name) { | 662 | LUA_API int lua_getglobal (lua_State *L, const char *name) { |
667 | const TValue *G; | 663 | TValue gt; |
668 | lua_lock(L); | 664 | lua_lock(L); |
669 | G = getGtable(L); | 665 | getGlobalTable(L, >); |
670 | return auxgetstr(L, G, name); | 666 | return auxgetstr(L, >, name); |
671 | } | 667 | } |
672 | 668 | ||
673 | 669 | ||
674 | LUA_API int lua_gettable (lua_State *L, int idx) { | 670 | LUA_API int lua_gettable (lua_State *L, int idx) { |
675 | const TValue *slot; | 671 | int hres; |
676 | TValue *t; | 672 | TValue *t; |
677 | lua_lock(L); | 673 | lua_lock(L); |
678 | t = index2value(L, idx); | 674 | t = index2value(L, idx); |
679 | if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) { | 675 | luaV_fastget(t, s2v(L->top.p - 1), s2v(L->top.p - 1), luaH_get, hres); |
680 | setobj2s(L, L->top.p - 1, slot); | 676 | if (hres != HOK) |
681 | } | 677 | luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, hres); |
682 | else | ||
683 | luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot); | ||
684 | lua_unlock(L); | 678 | lua_unlock(L); |
685 | return ttype(s2v(L->top.p - 1)); | 679 | return ttype(s2v(L->top.p - 1)); |
686 | } | 680 | } |
@@ -694,16 +688,14 @@ LUA_API int lua_getfield (lua_State *L, int idx, const char *k) { | |||
694 | 688 | ||
695 | LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { | 689 | LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { |
696 | TValue *t; | 690 | TValue *t; |
697 | const TValue *slot; | 691 | int hres; |
698 | lua_lock(L); | 692 | lua_lock(L); |
699 | t = index2value(L, idx); | 693 | t = index2value(L, idx); |
700 | if (luaV_fastgeti(L, t, n, slot)) { | 694 | luaV_fastgeti(t, n, s2v(L->top.p), hres); |
701 | setobj2s(L, L->top.p, slot); | 695 | if (hres != HOK) { |
702 | } | 696 | TValue key; |
703 | else { | 697 | setivalue(&key, n); |
704 | TValue aux; | 698 | luaV_finishget(L, t, &key, L->top.p, hres); |
705 | setivalue(&aux, n); | ||
706 | luaV_finishget(L, t, &aux, L->top.p, slot); | ||
707 | } | 699 | } |
708 | api_incr_top(L); | 700 | api_incr_top(L); |
709 | lua_unlock(L); | 701 | lua_unlock(L); |
@@ -711,11 +703,9 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { | |||
711 | } | 703 | } |
712 | 704 | ||
713 | 705 | ||
714 | l_sinline int finishrawget (lua_State *L, const TValue *val) { | 706 | l_sinline int finishrawget (lua_State *L, int hres) { |
715 | if (isempty(val)) /* avoid copying empty items to the stack */ | 707 | if (hres != HOK) /* avoid copying empty items to the stack */ |
716 | setnilvalue(s2v(L->top.p)); | 708 | setnilvalue(s2v(L->top.p)); |
717 | else | ||
718 | setobj2s(L, L->top.p, val); | ||
719 | api_incr_top(L); | 709 | api_incr_top(L); |
720 | lua_unlock(L); | 710 | lua_unlock(L); |
721 | return ttype(s2v(L->top.p - 1)); | 711 | return ttype(s2v(L->top.p - 1)); |
@@ -731,13 +721,13 @@ static Table *gettable (lua_State *L, int idx) { | |||
731 | 721 | ||
732 | LUA_API int lua_rawget (lua_State *L, int idx) { | 722 | LUA_API int lua_rawget (lua_State *L, int idx) { |
733 | Table *t; | 723 | Table *t; |
734 | const TValue *val; | 724 | int hres; |
735 | lua_lock(L); | 725 | lua_lock(L); |
736 | api_checknelems(L, 1); | 726 | api_checknelems(L, 1); |
737 | t = gettable(L, idx); | 727 | t = gettable(L, idx); |
738 | val = luaH_get(t, s2v(L->top.p - 1)); | 728 | hres = luaH_get(t, s2v(L->top.p - 1), s2v(L->top.p - 1)); |
739 | L->top.p--; /* remove key */ | 729 | L->top.p--; /* remove key */ |
740 | return finishrawget(L, val); | 730 | return finishrawget(L, hres); |
741 | } | 731 | } |
742 | 732 | ||
743 | 733 | ||
@@ -745,7 +735,7 @@ LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) { | |||
745 | Table *t; | 735 | Table *t; |
746 | lua_lock(L); | 736 | lua_lock(L); |
747 | t = gettable(L, idx); | 737 | t = gettable(L, idx); |
748 | return finishrawget(L, luaH_getint(t, n)); | 738 | return finishrawget(L, luaH_getint(t, n, s2v(L->top.p))); |
749 | } | 739 | } |
750 | 740 | ||
751 | 741 | ||
@@ -755,7 +745,7 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) { | |||
755 | lua_lock(L); | 745 | lua_lock(L); |
756 | t = gettable(L, idx); | 746 | t = gettable(L, idx); |
757 | setpvalue(&k, cast_voidp(p)); | 747 | setpvalue(&k, cast_voidp(p)); |
758 | return finishrawget(L, luaH_get(t, &k)); | 748 | return finishrawget(L, luaH_get(t, &k, s2v(L->top.p))); |
759 | } | 749 | } |
760 | 750 | ||
761 | 751 | ||
@@ -827,17 +817,18 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) { | |||
827 | ** t[k] = value at the top of the stack (where 'k' is a string) | 817 | ** t[k] = value at the top of the stack (where 'k' is a string) |
828 | */ | 818 | */ |
829 | static void auxsetstr (lua_State *L, const TValue *t, const char *k) { | 819 | static void auxsetstr (lua_State *L, const TValue *t, const char *k) { |
830 | const TValue *slot; | 820 | int hres; |
831 | TString *str = luaS_new(L, k); | 821 | TString *str = luaS_new(L, k); |
832 | api_checknelems(L, 1); | 822 | api_checknelems(L, 1); |
833 | if (luaV_fastget(L, t, str, slot, luaH_getstr)) { | 823 | luaV_fastset(t, str, s2v(L->top.p - 1), hres, luaH_psetstr); |
834 | luaV_finishfastset(L, t, slot, s2v(L->top.p - 1)); | 824 | if (hres == HOK) { |
825 | luaV_finishfastset(L, t, s2v(L->top.p - 1)); | ||
835 | L->top.p--; /* pop value */ | 826 | L->top.p--; /* pop value */ |
836 | } | 827 | } |
837 | else { | 828 | else { |
838 | setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */ | 829 | setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */ |
839 | api_incr_top(L); | 830 | api_incr_top(L); |
840 | luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot); | 831 | luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), hres); |
841 | L->top.p -= 2; /* pop value and key */ | 832 | L->top.p -= 2; /* pop value and key */ |
842 | } | 833 | } |
843 | lua_unlock(L); /* lock done by caller */ | 834 | lua_unlock(L); /* lock done by caller */ |
@@ -845,24 +836,25 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) { | |||
845 | 836 | ||
846 | 837 | ||
847 | LUA_API void lua_setglobal (lua_State *L, const char *name) { | 838 | LUA_API void lua_setglobal (lua_State *L, const char *name) { |
848 | const TValue *G; | 839 | TValue gt; |
849 | lua_lock(L); /* unlock done in 'auxsetstr' */ | 840 | lua_lock(L); /* unlock done in 'auxsetstr' */ |
850 | G = getGtable(L); | 841 | getGlobalTable(L, >); |
851 | auxsetstr(L, G, name); | 842 | auxsetstr(L, >, name); |
852 | } | 843 | } |
853 | 844 | ||
854 | 845 | ||
855 | LUA_API void lua_settable (lua_State *L, int idx) { | 846 | LUA_API void lua_settable (lua_State *L, int idx) { |
856 | TValue *t; | 847 | TValue *t; |
857 | const TValue *slot; | 848 | int hres; |
858 | lua_lock(L); | 849 | lua_lock(L); |
859 | api_checknelems(L, 2); | 850 | api_checknelems(L, 2); |
860 | t = index2value(L, idx); | 851 | t = index2value(L, idx); |
861 | if (luaV_fastget(L, t, s2v(L->top.p - 2), slot, luaH_get)) { | 852 | luaV_fastset(t, s2v(L->top.p - 2), s2v(L->top.p - 1), hres, luaH_pset); |
862 | luaV_finishfastset(L, t, slot, s2v(L->top.p - 1)); | 853 | if (hres == HOK) { |
854 | luaV_finishfastset(L, t, s2v(L->top.p - 1)); | ||
863 | } | 855 | } |
864 | else | 856 | else |
865 | luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot); | 857 | luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), hres); |
866 | L->top.p -= 2; /* pop index and value */ | 858 | L->top.p -= 2; /* pop index and value */ |
867 | lua_unlock(L); | 859 | lua_unlock(L); |
868 | } | 860 | } |
@@ -876,17 +868,18 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { | |||
876 | 868 | ||
877 | LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { | 869 | LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { |
878 | TValue *t; | 870 | TValue *t; |
879 | const TValue *slot; | 871 | int hres; |
880 | lua_lock(L); | 872 | lua_lock(L); |
881 | api_checknelems(L, 1); | 873 | api_checknelems(L, 1); |
882 | t = index2value(L, idx); | 874 | t = index2value(L, idx); |
883 | if (luaV_fastgeti(L, t, n, slot)) { | 875 | luaV_fastseti(t, n, s2v(L->top.p - 1), hres); |
884 | luaV_finishfastset(L, t, slot, s2v(L->top.p - 1)); | 876 | if (hres == HOK) { |
877 | luaV_finishfastset(L, t, s2v(L->top.p - 1)); | ||
885 | } | 878 | } |
886 | else { | 879 | else { |
887 | TValue aux; | 880 | TValue temp; |
888 | setivalue(&aux, n); | 881 | setivalue(&temp, n); |
889 | luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot); | 882 | luaV_finishset(L, t, &temp, s2v(L->top.p - 1), hres); |
890 | } | 883 | } |
891 | L->top.p--; /* pop value */ | 884 | L->top.p--; /* pop value */ |
892 | lua_unlock(L); | 885 | lua_unlock(L); |
@@ -1096,10 +1089,11 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, | |||
1096 | LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */ | 1089 | LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */ |
1097 | if (f->nupvalues >= 1) { /* does it have an upvalue? */ | 1090 | if (f->nupvalues >= 1) { /* does it have an upvalue? */ |
1098 | /* get global table from registry */ | 1091 | /* get global table from registry */ |
1099 | const TValue *gt = getGtable(L); | 1092 | TValue gt; |
1093 | getGlobalTable(L, >); | ||
1100 | /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ | 1094 | /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ |
1101 | setobj(L, f->upvals[0]->v.p, gt); | 1095 | setobj(L, f->upvals[0]->v.p, >); |
1102 | luaC_barrier(L, f->upvals[0], gt); | 1096 | luaC_barrier(L, f->upvals[0], >); |
1103 | } | 1097 | } |
1104 | } | 1098 | } |
1105 | lua_unlock(L); | 1099 | lua_unlock(L); |
@@ -544,10 +544,10 @@ static int addk (FuncState *fs, TValue *key, TValue *v) { | |||
544 | TValue val; | 544 | TValue val; |
545 | lua_State *L = fs->ls->L; | 545 | lua_State *L = fs->ls->L; |
546 | Proto *f = fs->f; | 546 | Proto *f = fs->f; |
547 | const TValue *idx = luaH_get(fs->ls->h, key); /* query scanner table */ | 547 | int aux = luaH_get(fs->ls->h, key, &val); /* query scanner table */ |
548 | int k, oldsize; | 548 | int k, oldsize; |
549 | if (ttisinteger(idx)) { /* is there an index there? */ | 549 | if (aux == HOK && ttisinteger(&val)) { /* is there an index there? */ |
550 | k = cast_int(ivalue(idx)); | 550 | k = cast_int(ivalue(&val)); |
551 | /* correct value? (warning: must distinguish floats from integers!) */ | 551 | /* correct value? (warning: must distinguish floats from integers!) */ |
552 | if (k < fs->nk && ttypetag(&f->k[k]) == ttypetag(v) && | 552 | if (k < fs->nk && ttypetag(&f->k[k]) == ttypetag(v) && |
553 | luaV_rawequalobj(&f->k[k], v)) | 553 | luaV_rawequalobj(&f->k[k], v)) |
@@ -559,7 +559,7 @@ static int addk (FuncState *fs, TValue *key, TValue *v) { | |||
559 | /* numerical value does not need GC barrier; | 559 | /* numerical value does not need GC barrier; |
560 | table has no metatable, so it does not need to invalidate cache */ | 560 | table has no metatable, so it does not need to invalidate cache */ |
561 | setivalue(&val, k); | 561 | setivalue(&val, k); |
562 | luaH_finishset(L, fs->ls->h, key, idx, &val); | 562 | luaH_set(L, fs->ls->h, key, &val); |
563 | luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); | 563 | luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); |
564 | while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); | 564 | while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); |
565 | setobj(L, &f->k[k], v); | 565 | setobj(L, &f->k[k], v); |
@@ -91,6 +91,13 @@ | |||
91 | #define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL) | 91 | #define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL) |
92 | 92 | ||
93 | 93 | ||
94 | /* | ||
95 | ** Access to collectable objects in array part of tables | ||
96 | */ | ||
97 | #define gcvalarr(t,i) \ | ||
98 | ((*getArrTag(t,i) & BIT_ISCOLLECTABLE) ? getArrVal(t,i)->gc : NULL) | ||
99 | |||
100 | |||
94 | #define markvalue(g,o) { checkliveness(g->mainthread,o); \ | 101 | #define markvalue(g,o) { checkliveness(g->mainthread,o); \ |
95 | if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } | 102 | if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } |
96 | 103 | ||
@@ -486,9 +493,10 @@ static int traverseephemeron (global_State *g, Table *h, int inv) { | |||
486 | unsigned int nsize = sizenode(h); | 493 | unsigned int nsize = sizenode(h); |
487 | /* traverse array part */ | 494 | /* traverse array part */ |
488 | for (i = 0; i < asize; i++) { | 495 | for (i = 0; i < asize; i++) { |
489 | if (valiswhite(&h->array[i])) { | 496 | GCObject *o = gcvalarr(h, i); |
497 | if (o != NULL && iswhite(o)) { | ||
490 | marked = 1; | 498 | marked = 1; |
491 | reallymarkobject(g, gcvalue(&h->array[i])); | 499 | reallymarkobject(g, o); |
492 | } | 500 | } |
493 | } | 501 | } |
494 | /* traverse hash part; if 'inv', traverse descending | 502 | /* traverse hash part; if 'inv', traverse descending |
@@ -524,8 +532,11 @@ static void traversestrongtable (global_State *g, Table *h) { | |||
524 | Node *n, *limit = gnodelast(h); | 532 | Node *n, *limit = gnodelast(h); |
525 | unsigned int i; | 533 | unsigned int i; |
526 | unsigned int asize = luaH_realasize(h); | 534 | unsigned int asize = luaH_realasize(h); |
527 | for (i = 0; i < asize; i++) /* traverse array part */ | 535 | for (i = 0; i < asize; i++) { /* traverse array part */ |
528 | markvalue(g, &h->array[i]); | 536 | GCObject *o = gcvalarr(h, i); |
537 | if (o != NULL && iswhite(o)) | ||
538 | reallymarkobject(g, o); | ||
539 | } | ||
529 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ | 540 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ |
530 | if (isempty(gval(n))) /* entry is empty? */ | 541 | if (isempty(gval(n))) /* entry is empty? */ |
531 | clearkey(n); /* clear its key */ | 542 | clearkey(n); /* clear its key */ |
@@ -748,9 +759,9 @@ static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { | |||
748 | unsigned int i; | 759 | unsigned int i; |
749 | unsigned int asize = luaH_realasize(h); | 760 | unsigned int asize = luaH_realasize(h); |
750 | for (i = 0; i < asize; i++) { | 761 | for (i = 0; i < asize; i++) { |
751 | TValue *o = &h->array[i]; | 762 | GCObject *o = gcvalarr(h, i); |
752 | if (iscleared(g, gcvalueN(o))) /* value was collected? */ | 763 | if (iscleared(g, o)) /* value was collected? */ |
753 | setempty(o); /* remove entry */ | 764 | *getArrTag(h, i) = LUA_VEMPTY; /* remove entry */ |
754 | } | 765 | } |
755 | for (n = gnode(h, 0); n < limit; n++) { | 766 | for (n = gnode(h, 0); n < limit; n++) { |
756 | if (iscleared(g, gcvalueN(gval(n)))) /* unmarked value? */ | 767 | if (iscleared(g, gcvalueN(gval(n)))) /* unmarked value? */ |
@@ -134,13 +134,13 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) { | |||
134 | TString *luaX_newstring (LexState *ls, const char *str, size_t l) { | 134 | TString *luaX_newstring (LexState *ls, const char *str, size_t l) { |
135 | lua_State *L = ls->L; | 135 | lua_State *L = ls->L; |
136 | TString *ts = luaS_newlstr(L, str, l); /* create new string */ | 136 | TString *ts = luaS_newlstr(L, str, l); /* create new string */ |
137 | const TValue *o = luaH_getstr(ls->h, ts); | 137 | TString *oldts = luaH_getstrkey(ls->h, ts); |
138 | if (!ttisnil(o)) /* string already present? */ | 138 | if (oldts != NULL) /* string already present? */ |
139 | ts = keystrval(nodefromval(o)); /* get saved copy */ | 139 | return oldts; /* use it */ |
140 | else { /* not in use yet */ | 140 | else { /* create a new entry */ |
141 | TValue *stv = s2v(L->top.p++); /* reserve stack space for string */ | 141 | TValue *stv = s2v(L->top.p++); /* reserve stack space for string */ |
142 | setsvalue(L, stv, ts); /* temporarily anchor the string */ | 142 | setsvalue(L, stv, ts); /* temporarily anchor the string */ |
143 | luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */ | 143 | luaH_set(L, ls->h, stv, stv); /* t[string] = string */ |
144 | /* table is not a metatable, so it does not need to invalidate cache */ | 144 | /* table is not a metatable, so it does not need to invalidate cache */ |
145 | luaC_checkGC(L); | 145 | luaC_checkGC(L); |
146 | L->top.p--; /* remove string from stack */ | 146 | L->top.p--; /* remove string from stack */ |
@@ -192,6 +192,8 @@ typedef union { | |||
192 | /* macro to test for (any kind of) nil */ | 192 | /* macro to test for (any kind of) nil */ |
193 | #define ttisnil(v) checktype((v), LUA_TNIL) | 193 | #define ttisnil(v) checktype((v), LUA_TNIL) |
194 | 194 | ||
195 | #define tagisempty(tag) (novariant(tag) == LUA_TNIL) | ||
196 | |||
195 | 197 | ||
196 | /* macro to test for a standard nil */ | 198 | /* macro to test for a standard nil */ |
197 | #define ttisstrictnil(o) checktag((o), LUA_VNIL) | 199 | #define ttisstrictnil(o) checktag((o), LUA_VNIL) |
@@ -734,12 +736,15 @@ typedef union Node { | |||
734 | #define setnorealasize(t) ((t)->flags |= BITRAS) | 736 | #define setnorealasize(t) ((t)->flags |= BITRAS) |
735 | 737 | ||
736 | 738 | ||
739 | typedef union ArrayCell ArrayCell; | ||
740 | |||
741 | |||
737 | typedef struct Table { | 742 | typedef struct Table { |
738 | CommonHeader; | 743 | CommonHeader; |
739 | lu_byte flags; /* 1<<p means tagmethod(p) is not present */ | 744 | lu_byte flags; /* 1<<p means tagmethod(p) is not present */ |
740 | lu_byte lsizenode; /* log2 of size of 'node' array */ | 745 | lu_byte lsizenode; /* log2 of size of 'node' array */ |
741 | unsigned int alimit; /* "limit" of 'array' array */ | 746 | unsigned int alimit; /* "limit" of 'array' array */ |
742 | TValue *array; /* array part */ | 747 | ArrayCell *array; /* array part */ |
743 | Node *node; | 748 | Node *node; |
744 | Node *lastfree; /* any free position is before this position */ | 749 | Node *lastfree; /* any free position is before this position */ |
745 | struct Table *metatable; | 750 | struct Table *metatable; |
@@ -215,13 +215,16 @@ static void freestack (lua_State *L) { | |||
215 | */ | 215 | */ |
216 | static void init_registry (lua_State *L, global_State *g) { | 216 | static void init_registry (lua_State *L, global_State *g) { |
217 | /* create registry */ | 217 | /* create registry */ |
218 | TValue aux; | ||
218 | Table *registry = luaH_new(L); | 219 | Table *registry = luaH_new(L); |
219 | sethvalue(L, &g->l_registry, registry); | 220 | sethvalue(L, &g->l_registry, registry); |
220 | luaH_resize(L, registry, LUA_RIDX_LAST, 0); | 221 | luaH_resize(L, registry, LUA_RIDX_LAST, 0); |
221 | /* registry[LUA_RIDX_MAINTHREAD] = L */ | 222 | /* registry[LUA_RIDX_MAINTHREAD] = L */ |
222 | setthvalue(L, ®istry->array[LUA_RIDX_MAINTHREAD - 1], L); | 223 | setthvalue(L, &aux, L); |
224 | luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &aux); | ||
223 | /* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */ | 225 | /* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */ |
224 | sethvalue(L, ®istry->array[LUA_RIDX_GLOBALS - 1], luaH_new(L)); | 226 | sethvalue(L, &aux, luaH_new(L)); |
227 | luaH_setint(L, registry, LUA_RIDX_GLOBALS, &aux); | ||
225 | } | 228 | } |
226 | 229 | ||
227 | 230 | ||
@@ -350,9 +350,10 @@ int luaH_next (lua_State *L, Table *t, StkId key) { | |||
350 | unsigned int asize = luaH_realasize(t); | 350 | unsigned int asize = luaH_realasize(t); |
351 | unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */ | 351 | unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */ |
352 | for (; i < asize; i++) { /* try first array part */ | 352 | for (; i < asize; i++) { /* try first array part */ |
353 | if (!isempty(&t->array[i])) { /* a non-empty entry? */ | 353 | int tag = *getArrTag(t, i); |
354 | if (!tagisempty(tag)) { /* a non-empty entry? */ | ||
354 | setivalue(s2v(key), i + 1); | 355 | setivalue(s2v(key), i + 1); |
355 | setobj2s(L, key + 1, &t->array[i]); | 356 | farr2val(t, i + 1, tag, s2v(key + 1)); |
356 | return 1; | 357 | return 1; |
357 | } | 358 | } |
358 | } | 359 | } |
@@ -375,6 +376,41 @@ static void freehash (lua_State *L, Table *t) { | |||
375 | 376 | ||
376 | 377 | ||
377 | /* | 378 | /* |
379 | ** Check whether an integer key is in the array part. If 'alimit' is | ||
380 | ** not the real size of the array, the key still can be in the array | ||
381 | ** part. In this case, do the "Xmilia trick" to check whether 'key-1' | ||
382 | ** is smaller than the real size. | ||
383 | ** The trick works as follow: let 'p' be an integer such that | ||
384 | ** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'. | ||
385 | ** That is, 2^(p+1) is the real size of the array, and 'p' is the highest | ||
386 | ** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'. | ||
387 | ** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will | ||
388 | ** have the 'p' bit cleared. If the key is outside the array, that is, | ||
389 | ** 'key-1 >= 2^(p+1)', then 'res' will have some 1-bit higher than 'p', | ||
390 | ** therefore it will be larger or equal to 'alimit', and the check | ||
391 | ** will fail. If 'key-1 < 2^(p+1)', then 'res' has no 1-bit higher than | ||
392 | ** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller | ||
393 | ** than 2^p, therefore smaller than 'alimit', and the check succeeds. | ||
394 | ** As special cases, when 'alimit' is 0 the condition is trivially false, | ||
395 | ** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'. | ||
396 | ** If key is 0 or negative, 'res' will have its higher bit on, so that | ||
397 | ** if cannot be smaller than alimit. | ||
398 | */ | ||
399 | static int keyinarray (Table *t, lua_Integer key) { | ||
400 | lua_Unsigned alimit = t->alimit; | ||
401 | if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */ | ||
402 | return 1; | ||
403 | else if (!isrealasize(t) && /* key still may be in the array part? */ | ||
404 | (((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) { | ||
405 | t->alimit = cast_uint(key); /* probably '#t' is here now */ | ||
406 | return 1; | ||
407 | } | ||
408 | else | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | |||
413 | /* | ||
378 | ** {============================================================= | 414 | ** {============================================================= |
379 | ** Rehash | 415 | ** Rehash |
380 | ** ============================================================== | 416 | ** ============================================================== |
@@ -421,6 +457,12 @@ static int countint (lua_Integer key, unsigned int *nums) { | |||
421 | } | 457 | } |
422 | 458 | ||
423 | 459 | ||
460 | l_sinline int arraykeyisempty (const Table *t, lua_Integer key) { | ||
461 | int tag = *getArrTag(t, key - 1); | ||
462 | return tagisempty(tag); | ||
463 | } | ||
464 | |||
465 | |||
424 | /* | 466 | /* |
425 | ** Count keys in array part of table 't': Fill 'nums[i]' with | 467 | ** Count keys in array part of table 't': Fill 'nums[i]' with |
426 | ** number of keys that will go into corresponding slice and return | 468 | ** number of keys that will go into corresponding slice and return |
@@ -443,7 +485,7 @@ static unsigned int numusearray (const Table *t, unsigned int *nums) { | |||
443 | } | 485 | } |
444 | /* count elements in range (2^(lg - 1), 2^lg] */ | 486 | /* count elements in range (2^(lg - 1), 2^lg] */ |
445 | for (; i <= lim; i++) { | 487 | for (; i <= lim; i++) { |
446 | if (!isempty(&t->array[i-1])) | 488 | if (!arraykeyisempty(t, i)) |
447 | lc++; | 489 | lc++; |
448 | } | 490 | } |
449 | nums[lg] += lc; | 491 | nums[lg] += lc; |
@@ -471,6 +513,33 @@ static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { | |||
471 | 513 | ||
472 | 514 | ||
473 | /* | 515 | /* |
516 | ** Convert an "abstract size" (number of values in an array) to | ||
517 | ** "concrete size" (number of cell elements in the array). Cells | ||
518 | ** do not need to be full; we only must make sure it has the values | ||
519 | ** needed and its 'tag' element. So, we compute the concrete tag index | ||
520 | ** and the concrete value index of the last element, get their maximum | ||
521 | ** and adds 1. | ||
522 | */ | ||
523 | static unsigned int concretesize (unsigned int size) { | ||
524 | if (size == 0) return 0; | ||
525 | else { | ||
526 | unsigned int ts = TagIndex(size - 1); | ||
527 | unsigned int vs = ValueIndex(size - 1); | ||
528 | return ((ts >= vs) ? ts : vs) + 1; | ||
529 | } | ||
530 | } | ||
531 | |||
532 | |||
533 | static ArrayCell *resizearray (lua_State *L , Table *t, | ||
534 | unsigned int oldasize, | ||
535 | unsigned int newasize) { | ||
536 | oldasize = concretesize(oldasize); | ||
537 | newasize = concretesize(newasize); | ||
538 | return luaM_reallocvector(L, t->array, oldasize, newasize, ArrayCell); | ||
539 | } | ||
540 | |||
541 | |||
542 | /* | ||
474 | ** Creates an array for the hash part of a table with the given | 543 | ** Creates an array for the hash part of a table with the given |
475 | ** size, or reuses the dummy node if size is zero. | 544 | ** size, or reuses the dummy node if size is zero. |
476 | ** The computation for size overflow is in two steps: the first | 545 | ** The computation for size overflow is in two steps: the first |
@@ -555,7 +624,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
555 | unsigned int i; | 624 | unsigned int i; |
556 | Table newt; /* to keep the new hash part */ | 625 | Table newt; /* to keep the new hash part */ |
557 | unsigned int oldasize = setlimittosize(t); | 626 | unsigned int oldasize = setlimittosize(t); |
558 | TValue *newarray; | 627 | ArrayCell *newarray; |
559 | /* create new hash part with appropriate size into 'newt' */ | 628 | /* create new hash part with appropriate size into 'newt' */ |
560 | setnodevector(L, &newt, nhsize); | 629 | setnodevector(L, &newt, nhsize); |
561 | if (newasize < oldasize) { /* will array shrink? */ | 630 | if (newasize < oldasize) { /* will array shrink? */ |
@@ -563,14 +632,18 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
563 | exchangehashpart(t, &newt); /* and new hash */ | 632 | exchangehashpart(t, &newt); /* and new hash */ |
564 | /* re-insert into the new hash the elements from vanishing slice */ | 633 | /* re-insert into the new hash the elements from vanishing slice */ |
565 | for (i = newasize; i < oldasize; i++) { | 634 | for (i = newasize; i < oldasize; i++) { |
566 | if (!isempty(&t->array[i])) | 635 | int tag = *getArrTag(t, i); |
567 | luaH_setint(L, t, i + 1, &t->array[i]); | 636 | if (!tagisempty(tag)) { /* a non-empty entry? */ |
637 | TValue aux; | ||
638 | farr2val(t, i + 1, tag, &aux); | ||
639 | luaH_setint(L, t, i + 1, &aux); | ||
640 | } | ||
568 | } | 641 | } |
569 | t->alimit = oldasize; /* restore current size... */ | 642 | t->alimit = oldasize; /* restore current size... */ |
570 | exchangehashpart(t, &newt); /* and hash (in case of errors) */ | 643 | exchangehashpart(t, &newt); /* and hash (in case of errors) */ |
571 | } | 644 | } |
572 | /* allocate new array */ | 645 | /* allocate new array */ |
573 | newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue); | 646 | newarray = resizearray(L, t, oldasize, newasize); |
574 | if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ | 647 | if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ |
575 | freehash(L, &newt); /* release new hash part */ | 648 | freehash(L, &newt); /* release new hash part */ |
576 | luaM_error(L); /* raise error (with array unchanged) */ | 649 | luaM_error(L); /* raise error (with array unchanged) */ |
@@ -580,7 +653,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
580 | t->array = newarray; /* set new array part */ | 653 | t->array = newarray; /* set new array part */ |
581 | t->alimit = newasize; | 654 | t->alimit = newasize; |
582 | for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ | 655 | for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ |
583 | setempty(&t->array[i]); | 656 | *getArrTag(t, i) = LUA_VEMPTY; |
584 | /* re-insert elements from old hash part into new parts */ | 657 | /* re-insert elements from old hash part into new parts */ |
585 | reinsert(L, &newt, t); /* 'newt' now has the old hash */ | 658 | reinsert(L, &newt, t); /* 'newt' now has the old hash */ |
586 | freehash(L, &newt); /* free old hash part */ | 659 | freehash(L, &newt); /* free old hash part */ |
@@ -636,8 +709,9 @@ Table *luaH_new (lua_State *L) { | |||
636 | 709 | ||
637 | 710 | ||
638 | void luaH_free (lua_State *L, Table *t) { | 711 | void luaH_free (lua_State *L, Table *t) { |
712 | unsigned ps = concretesize(luaH_realasize(t)); | ||
639 | freehash(L, t); | 713 | freehash(L, t); |
640 | luaM_freearray(L, t->array, luaH_realasize(t)); | 714 | luaM_freearray(L, t->array, ps); |
641 | luaM_free(L, t); | 715 | luaM_free(L, t); |
642 | } | 716 | } |
643 | 717 | ||
@@ -720,57 +794,57 @@ static void luaH_newkey (lua_State *L, Table *t, const TValue *key, | |||
720 | } | 794 | } |
721 | 795 | ||
722 | 796 | ||
723 | /* | 797 | static const TValue *getintfromhash (Table *t, lua_Integer key) { |
724 | ** Search function for integers. If integer is inside 'alimit', get it | 798 | Node *n = hashint(t, key); |
725 | ** directly from the array part. Otherwise, if 'alimit' is not | 799 | lua_assert(l_castS2U(key) - 1u >= luaH_realasize(t)); |
726 | ** the real size of the array, the key still can be in the array part. | 800 | for (;;) { /* check whether 'key' is somewhere in the chain */ |
727 | ** In this case, do the "Xmilia trick" to check whether 'key-1' is | 801 | if (keyisinteger(n) && keyival(n) == key) |
728 | ** smaller than the real size. | 802 | return gval(n); /* that's it */ |
729 | ** The trick works as follow: let 'p' be an integer such that | 803 | else { |
730 | ** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'. | 804 | int nx = gnext(n); |
731 | ** That is, 2^(p+1) is the real size of the array, and 'p' is the highest | 805 | if (nx == 0) break; |
732 | ** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'. | 806 | n += nx; |
733 | ** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will | ||
734 | ** have the 'p' bit cleared. If the key is outside the array, that is, | ||
735 | ** 'key-1 >= 2^(p+1)', then 'res' will have some bit on higher than 'p', | ||
736 | ** therefore it will be larger or equal to 'alimit', and the check | ||
737 | ** will fail. If 'key-1 < 2^(p+1)', then 'res' has no bit on higher than | ||
738 | ** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller | ||
739 | ** than 2^p, therefore smaller than 'alimit', and the check succeeds. | ||
740 | ** As special cases, when 'alimit' is 0 the condition is trivially false, | ||
741 | ** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'. | ||
742 | ** If key is 0 or negative, 'res' will have its higher bit on, so that | ||
743 | ** if cannot be smaller than alimit. | ||
744 | */ | ||
745 | const TValue *luaH_getint (Table *t, lua_Integer key) { | ||
746 | lua_Unsigned alimit = t->alimit; | ||
747 | if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */ | ||
748 | return &t->array[key - 1]; | ||
749 | else if (!isrealasize(t) && /* key still may be in the array part? */ | ||
750 | (((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) { | ||
751 | t->alimit = cast_uint(key); /* probably '#t' is here now */ | ||
752 | return &t->array[key - 1]; | ||
753 | } | ||
754 | else { /* key is not in the array part; check the hash */ | ||
755 | Node *n = hashint(t, key); | ||
756 | for (;;) { /* check whether 'key' is somewhere in the chain */ | ||
757 | if (keyisinteger(n) && keyival(n) == key) | ||
758 | return gval(n); /* that's it */ | ||
759 | else { | ||
760 | int nx = gnext(n); | ||
761 | if (nx == 0) break; | ||
762 | n += nx; | ||
763 | } | ||
764 | } | 807 | } |
765 | return &absentkey; | ||
766 | } | 808 | } |
809 | return &absentkey; | ||
810 | } | ||
811 | |||
812 | |||
813 | static int hashkeyisempty (Table *t, lua_Integer key) { | ||
814 | const TValue *val = getintfromhash(t, key); | ||
815 | return isempty(val); | ||
816 | } | ||
817 | |||
818 | |||
819 | static int finishnodeget (const TValue *val, TValue *res) { | ||
820 | if (!ttisnil(val)) { | ||
821 | setobj(((lua_State*)NULL), res, val); | ||
822 | return HOK; /* success */ | ||
823 | } | ||
824 | else | ||
825 | return HNOTFOUND; /* could not get value */ | ||
826 | } | ||
827 | |||
828 | |||
829 | int luaH_getint (Table *t, lua_Integer key, TValue *res) { | ||
830 | if (keyinarray(t, key)) { | ||
831 | int tag = *getArrTag(t, key - 1); | ||
832 | if (!tagisempty(tag)) { | ||
833 | farr2val(t, key, tag, res); | ||
834 | return HOK; /* success */ | ||
835 | } | ||
836 | else | ||
837 | return ~cast_int(key); /* empty slot in the array part */ | ||
838 | } | ||
839 | else | ||
840 | return finishnodeget(getintfromhash(t, key), res); | ||
767 | } | 841 | } |
768 | 842 | ||
769 | 843 | ||
770 | /* | 844 | /* |
771 | ** search function for short strings | 845 | ** search function for short strings |
772 | */ | 846 | */ |
773 | const TValue *luaH_getshortstr (Table *t, TString *key) { | 847 | const TValue *luaH_Hgetshortstr (Table *t, TString *key) { |
774 | Node *n = hashstr(t, key); | 848 | Node *n = hashstr(t, key); |
775 | lua_assert(key->tt == LUA_VSHRSTR); | 849 | lua_assert(key->tt == LUA_VSHRSTR); |
776 | for (;;) { /* check whether 'key' is somewhere in the chain */ | 850 | for (;;) { /* check whether 'key' is somewhere in the chain */ |
@@ -786,9 +860,14 @@ const TValue *luaH_getshortstr (Table *t, TString *key) { | |||
786 | } | 860 | } |
787 | 861 | ||
788 | 862 | ||
789 | const TValue *luaH_getstr (Table *t, TString *key) { | 863 | int luaH_getshortstr (Table *t, TString *key, TValue *res) { |
864 | return finishnodeget(luaH_Hgetshortstr(t, key), res); | ||
865 | } | ||
866 | |||
867 | |||
868 | static const TValue *Hgetstr (Table *t, TString *key) { | ||
790 | if (key->tt == LUA_VSHRSTR) | 869 | if (key->tt == LUA_VSHRSTR) |
791 | return luaH_getshortstr(t, key); | 870 | return luaH_Hgetshortstr(t, key); |
792 | else { /* for long strings, use generic case */ | 871 | else { /* for long strings, use generic case */ |
793 | TValue ko; | 872 | TValue ko; |
794 | setsvalue(cast(lua_State *, NULL), &ko, key); | 873 | setsvalue(cast(lua_State *, NULL), &ko, key); |
@@ -797,38 +876,121 @@ const TValue *luaH_getstr (Table *t, TString *key) { | |||
797 | } | 876 | } |
798 | 877 | ||
799 | 878 | ||
879 | int luaH_getstr (Table *t, TString *key, TValue *res) { | ||
880 | return finishnodeget(Hgetstr(t, key), res); | ||
881 | } | ||
882 | |||
883 | |||
884 | TString *luaH_getstrkey (Table *t, TString *key) { | ||
885 | const TValue *o = Hgetstr(t, key); | ||
886 | if (!isabstkey(o)) /* string already present? */ | ||
887 | return keystrval(nodefromval(o)); /* get saved copy */ | ||
888 | else | ||
889 | return NULL; | ||
890 | } | ||
891 | |||
892 | |||
800 | /* | 893 | /* |
801 | ** main search function | 894 | ** main search function |
802 | */ | 895 | */ |
803 | const TValue *luaH_get (Table *t, const TValue *key) { | 896 | int luaH_get (Table *t, const TValue *key, TValue *res) { |
897 | const TValue *slot; | ||
804 | switch (ttypetag(key)) { | 898 | switch (ttypetag(key)) { |
805 | case LUA_VSHRSTR: return luaH_getshortstr(t, tsvalue(key)); | 899 | case LUA_VSHRSTR: |
806 | case LUA_VNUMINT: return luaH_getint(t, ivalue(key)); | 900 | slot = luaH_Hgetshortstr(t, tsvalue(key)); |
807 | case LUA_VNIL: return &absentkey; | 901 | break; |
902 | case LUA_VNUMINT: | ||
903 | return luaH_getint(t, ivalue(key), res); | ||
904 | case LUA_VNIL: | ||
905 | slot = &absentkey; | ||
906 | break; | ||
808 | case LUA_VNUMFLT: { | 907 | case LUA_VNUMFLT: { |
809 | lua_Integer k; | 908 | lua_Integer k; |
810 | if (luaV_flttointeger(fltvalue(key), &k, F2Ieq)) /* integral index? */ | 909 | if (luaV_flttointeger(fltvalue(key), &k, F2Ieq)) /* integral index? */ |
811 | return luaH_getint(t, k); /* use specialized version */ | 910 | return luaH_getint(t, k, res); /* use specialized version */ |
812 | /* else... */ | 911 | /* else... */ |
813 | } /* FALLTHROUGH */ | 912 | } /* FALLTHROUGH */ |
814 | default: | 913 | default: |
815 | return getgeneric(t, key, 0); | 914 | slot = getgeneric(t, key, 0); |
915 | break; | ||
916 | } | ||
917 | return finishnodeget(slot, res); | ||
918 | } | ||
919 | |||
920 | |||
921 | static int finishnodeset (Table *t, const TValue *slot, TValue *val) { | ||
922 | if (!ttisnil(slot)) { | ||
923 | setobj(((lua_State*)NULL), cast(TValue*, slot), val); | ||
924 | return HOK; /* success */ | ||
925 | } | ||
926 | else if (isabstkey(slot)) | ||
927 | return HNOTFOUND; /* no slot with that key */ | ||
928 | else return (cast(Node*, slot) - t->node) + HFIRSTNODE; /* node encoded */ | ||
929 | } | ||
930 | |||
931 | |||
932 | int luaH_psetint (Table *t, lua_Integer key, TValue *val) { | ||
933 | if (keyinarray(t, key)) { | ||
934 | lu_byte *tag = getArrTag(t, key - 1); | ||
935 | if (!tagisempty(*tag)) { | ||
936 | fval2arr(t, key, tag, val); | ||
937 | return HOK; /* success */ | ||
938 | } | ||
939 | else | ||
940 | return ~cast_int(key); /* empty slot in the array part */ | ||
816 | } | 941 | } |
942 | else | ||
943 | return finishnodeset(t, getintfromhash(t, key), val); | ||
817 | } | 944 | } |
818 | 945 | ||
819 | 946 | ||
947 | int luaH_psetshortstr (Table *t, TString *key, TValue *val) { | ||
948 | return finishnodeset(t, luaH_Hgetshortstr(t, key), val); | ||
949 | } | ||
950 | |||
951 | |||
952 | int luaH_psetstr (Table *t, TString *key, TValue *val) { | ||
953 | return finishnodeset(t, Hgetstr(t, key), val); | ||
954 | } | ||
955 | |||
956 | |||
957 | int luaH_pset (Table *t, const TValue *key, TValue *val) { | ||
958 | switch (ttypetag(key)) { | ||
959 | case LUA_VSHRSTR: return luaH_psetshortstr(t, tsvalue(key), val); | ||
960 | case LUA_VNUMINT: return luaH_psetint(t, ivalue(key), val); | ||
961 | case LUA_VNIL: return HNOTFOUND; | ||
962 | case LUA_VNUMFLT: { | ||
963 | lua_Integer k; | ||
964 | if (luaV_flttointeger(fltvalue(key), &k, F2Ieq)) /* integral index? */ | ||
965 | return luaH_psetint(t, k, val); /* use specialized version */ | ||
966 | /* else... */ | ||
967 | } /* FALLTHROUGH */ | ||
968 | default: | ||
969 | return finishnodeset(t, getgeneric(t, key, 0), val); | ||
970 | } | ||
971 | } | ||
972 | |||
820 | /* | 973 | /* |
821 | ** Finish a raw "set table" operation, where 'slot' is where the value | 974 | ** Finish a raw "set table" operation, where 'slot' is where the value |
822 | ** should have been (the result of a previous "get table"). | 975 | ** should have been (the result of a previous "get table"). |
823 | ** Beware: when using this function you probably need to check a GC | 976 | ** Beware: when using this function you probably need to check a GC |
824 | ** barrier and invalidate the TM cache. | 977 | ** barrier and invalidate the TM cache. |
825 | */ | 978 | */ |
979 | |||
980 | |||
826 | void luaH_finishset (lua_State *L, Table *t, const TValue *key, | 981 | void luaH_finishset (lua_State *L, Table *t, const TValue *key, |
827 | const TValue *slot, TValue *value) { | 982 | TValue *value, int hres) { |
828 | if (isabstkey(slot)) | 983 | lua_assert(hres != HOK); |
984 | if (hres == HNOTFOUND) { | ||
829 | luaH_newkey(L, t, key, value); | 985 | luaH_newkey(L, t, key, value); |
830 | else | 986 | } |
831 | setobj2t(L, cast(TValue *, slot), value); | 987 | else if (hres > 0) { /* regular Node? */ |
988 | setobj2t(L, gval(gnode(t, hres - HFIRSTNODE)), value); | ||
989 | } | ||
990 | else { /* array entry */ | ||
991 | hres = ~hres; /* real index */ | ||
992 | obj2arr(t, hres, value); | ||
993 | } | ||
832 | } | 994 | } |
833 | 995 | ||
834 | 996 | ||
@@ -837,20 +999,19 @@ void luaH_finishset (lua_State *L, Table *t, const TValue *key, | |||
837 | ** barrier and invalidate the TM cache. | 999 | ** barrier and invalidate the TM cache. |
838 | */ | 1000 | */ |
839 | void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) { | 1001 | void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) { |
840 | const TValue *slot = luaH_get(t, key); | 1002 | int hres = luaH_pset(t, key, value); |
841 | luaH_finishset(L, t, key, slot, value); | 1003 | if (hres != HOK) |
1004 | luaH_finishset(L, t, key, value, hres); | ||
842 | } | 1005 | } |
843 | 1006 | ||
844 | 1007 | ||
845 | void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { | 1008 | void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { |
846 | const TValue *p = luaH_getint(t, key); | 1009 | int hres = luaH_psetint(t, key, value); |
847 | if (isabstkey(p)) { | 1010 | if (hres != HOK) { |
848 | TValue k; | 1011 | TValue k; |
849 | setivalue(&k, key); | 1012 | setivalue(&k, key); |
850 | luaH_newkey(L, t, &k, value); | 1013 | luaH_finishset(L, t, &k, value, hres); |
851 | } | 1014 | } |
852 | else | ||
853 | setobj2t(L, cast(TValue *, p), value); | ||
854 | } | 1015 | } |
855 | 1016 | ||
856 | 1017 | ||
@@ -876,27 +1037,26 @@ static lua_Unsigned hash_search (Table *t, lua_Unsigned j) { | |||
876 | j *= 2; | 1037 | j *= 2; |
877 | else { | 1038 | else { |
878 | j = LUA_MAXINTEGER; | 1039 | j = LUA_MAXINTEGER; |
879 | if (isempty(luaH_getint(t, j))) /* t[j] not present? */ | 1040 | if (hashkeyisempty(t, j)) /* t[j] not present? */ |
880 | break; /* 'j' now is an absent index */ | 1041 | break; /* 'j' now is an absent index */ |
881 | else /* weird case */ | 1042 | else /* weird case */ |
882 | return j; /* well, max integer is a boundary... */ | 1043 | return j; /* well, max integer is a boundary... */ |
883 | } | 1044 | } |
884 | } while (!isempty(luaH_getint(t, j))); /* repeat until an absent t[j] */ | 1045 | } while (!hashkeyisempty(t, j)); /* repeat until an absent t[j] */ |
885 | /* i < j && t[i] present && t[j] absent */ | 1046 | /* i < j && t[i] present && t[j] absent */ |
886 | while (j - i > 1u) { /* do a binary search between them */ | 1047 | while (j - i > 1u) { /* do a binary search between them */ |
887 | lua_Unsigned m = (i + j) / 2; | 1048 | lua_Unsigned m = (i + j) / 2; |
888 | if (isempty(luaH_getint(t, m))) j = m; | 1049 | if (hashkeyisempty(t, m)) j = m; |
889 | else i = m; | 1050 | else i = m; |
890 | } | 1051 | } |
891 | return i; | 1052 | return i; |
892 | } | 1053 | } |
893 | 1054 | ||
894 | 1055 | ||
895 | static unsigned int binsearch (const TValue *array, unsigned int i, | 1056 | static unsigned int binsearch (Table *array, unsigned int i, unsigned int j) { |
896 | unsigned int j) { | ||
897 | while (j - i > 1u) { /* binary search */ | 1057 | while (j - i > 1u) { /* binary search */ |
898 | unsigned int m = (i + j) / 2; | 1058 | unsigned int m = (i + j) / 2; |
899 | if (isempty(&array[m - 1])) j = m; | 1059 | if (arraykeyisempty(array, m)) j = m; |
900 | else i = m; | 1060 | else i = m; |
901 | } | 1061 | } |
902 | return i; | 1062 | return i; |
@@ -937,9 +1097,9 @@ static unsigned int binsearch (const TValue *array, unsigned int i, | |||
937 | */ | 1097 | */ |
938 | lua_Unsigned luaH_getn (Table *t) { | 1098 | lua_Unsigned luaH_getn (Table *t) { |
939 | unsigned int limit = t->alimit; | 1099 | unsigned int limit = t->alimit; |
940 | if (limit > 0 && isempty(&t->array[limit - 1])) { /* (1)? */ | 1100 | if (limit > 0 && arraykeyisempty(t, limit)) { /* (1)? */ |
941 | /* there must be a boundary before 'limit' */ | 1101 | /* there must be a boundary before 'limit' */ |
942 | if (limit >= 2 && !isempty(&t->array[limit - 2])) { | 1102 | if (limit >= 2 && !arraykeyisempty(t, limit - 1)) { |
943 | /* 'limit - 1' is a boundary; can it be a new limit? */ | 1103 | /* 'limit - 1' is a boundary; can it be a new limit? */ |
944 | if (ispow2realasize(t) && !ispow2(limit - 1)) { | 1104 | if (ispow2realasize(t) && !ispow2(limit - 1)) { |
945 | t->alimit = limit - 1; | 1105 | t->alimit = limit - 1; |
@@ -948,7 +1108,7 @@ lua_Unsigned luaH_getn (Table *t) { | |||
948 | return limit - 1; | 1108 | return limit - 1; |
949 | } | 1109 | } |
950 | else { /* must search for a boundary in [0, limit] */ | 1110 | else { /* must search for a boundary in [0, limit] */ |
951 | unsigned int boundary = binsearch(t->array, 0, limit); | 1111 | unsigned int boundary = binsearch(t, 0, limit); |
952 | /* can this boundary represent the real size of the array? */ | 1112 | /* can this boundary represent the real size of the array? */ |
953 | if (ispow2realasize(t) && boundary > luaH_realasize(t) / 2) { | 1113 | if (ispow2realasize(t) && boundary > luaH_realasize(t) / 2) { |
954 | t->alimit = boundary; /* use it as the new limit */ | 1114 | t->alimit = boundary; /* use it as the new limit */ |
@@ -960,14 +1120,14 @@ lua_Unsigned luaH_getn (Table *t) { | |||
960 | /* 'limit' is zero or present in table */ | 1120 | /* 'limit' is zero or present in table */ |
961 | if (!limitequalsasize(t)) { /* (2)? */ | 1121 | if (!limitequalsasize(t)) { /* (2)? */ |
962 | /* 'limit' > 0 and array has more elements after 'limit' */ | 1122 | /* 'limit' > 0 and array has more elements after 'limit' */ |
963 | if (isempty(&t->array[limit])) /* 'limit + 1' is empty? */ | 1123 | if (arraykeyisempty(t, limit + 1)) /* 'limit + 1' is empty? */ |
964 | return limit; /* this is the boundary */ | 1124 | return limit; /* this is the boundary */ |
965 | /* else, try last element in the array */ | 1125 | /* else, try last element in the array */ |
966 | limit = luaH_realasize(t); | 1126 | limit = luaH_realasize(t); |
967 | if (isempty(&t->array[limit - 1])) { /* empty? */ | 1127 | if (arraykeyisempty(t, limit)) { /* empty? */ |
968 | /* there must be a boundary in the array after old limit, | 1128 | /* there must be a boundary in the array after old limit, |
969 | and it must be a valid new limit */ | 1129 | and it must be a valid new limit */ |
970 | unsigned int boundary = binsearch(t->array, t->alimit, limit); | 1130 | unsigned int boundary = binsearch(t, t->alimit, limit); |
971 | t->alimit = boundary; | 1131 | t->alimit = boundary; |
972 | return boundary; | 1132 | return boundary; |
973 | } | 1133 | } |
@@ -975,8 +1135,8 @@ lua_Unsigned luaH_getn (Table *t) { | |||
975 | } | 1135 | } |
976 | /* (3) 'limit' is the last element and either is zero or present in table */ | 1136 | /* (3) 'limit' is the last element and either is zero or present in table */ |
977 | lua_assert(limit == luaH_realasize(t) && | 1137 | lua_assert(limit == luaH_realasize(t) && |
978 | (limit == 0 || !isempty(&t->array[limit - 1]))); | 1138 | (limit == 0 || !arraykeyisempty(t, limit))); |
979 | if (isdummy(t) || isempty(luaH_getint(t, cast(lua_Integer, limit + 1)))) | 1139 | if (isdummy(t) || hashkeyisempty(t, cast(lua_Integer, limit + 1))) |
980 | return limit; /* 'limit + 1' is absent */ | 1140 | return limit; /* 'limit + 1' is absent */ |
981 | else /* 'limit + 1' is also present */ | 1141 | else /* 'limit + 1' is also present */ |
982 | return hash_search(t, limit); | 1142 | return hash_search(t, limit); |
@@ -35,16 +35,105 @@ | |||
35 | #define nodefromval(v) cast(Node *, (v)) | 35 | #define nodefromval(v) cast(Node *, (v)) |
36 | 36 | ||
37 | 37 | ||
38 | LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); | 38 | /* results from get/pset */ |
39 | #define HOK 0 | ||
40 | #define HNOTFOUND 1 | ||
41 | #define HNOTATABLE 2 | ||
42 | #define HFIRSTNODE 3 | ||
43 | |||
44 | /* | ||
45 | ** Besides these values, pset (pre-set) operations may also return an | ||
46 | ** encoding of where the value should go (usually called 'hres'). That | ||
47 | ** means that there is a slot with that key but with no value. (pset | ||
48 | ** cannot set that value because there might be a metamethod.) If the | ||
49 | ** slot is in the hash part, the encoding is (HFIRSTNODE + hash index); | ||
50 | ** if the slot is in the array part, the encoding is (~array index). | ||
51 | */ | ||
52 | |||
53 | |||
54 | /* | ||
55 | ** The array part of a table is represented by an array of cells. | ||
56 | ** Each cell is composed of (NM + 1) elements, and each element has the | ||
57 | ** type 'ArrayCell'. In each cell, only one element has the variant | ||
58 | ** 'tag', while the other NM elements have the variant 'value'. The | ||
59 | ** array in the 'tag' element holds the tags of the other elements in | ||
60 | ** that cell. | ||
61 | */ | ||
62 | #define NM ((unsigned int)sizeof(Value)) | ||
63 | |||
64 | union ArrayCell { | ||
65 | unsigned char tag[NM]; | ||
66 | Value value; | ||
67 | }; | ||
68 | |||
69 | |||
70 | /* | ||
71 | ** 'NMTag' defines which cell element has the tags; that could be any | ||
72 | ** value between 0 (tags come before all values) and NM (tags come after | ||
73 | ** all values). | ||
74 | */ | ||
75 | #define NMTag 0 | ||
76 | |||
77 | |||
78 | /* | ||
79 | ** Computes the concrete index that holds the tag of abstract index 'i' | ||
80 | */ | ||
81 | #define TagIndex(i) (((i)/NM * (NM + 1u)) + NMTag) | ||
82 | |||
83 | /* | ||
84 | ** Computes the concrete index that holds the value of abstract index 'i' | ||
85 | */ | ||
86 | #define ValueIndex(i) ((i) + (((i) + (NM - NMTag))/NM)) | ||
87 | |||
88 | |||
89 | /* Computes the address of the tag for the abstract index 'k' */ | ||
90 | #define getArrTag(t,k) (&(t)->array[TagIndex(k)].tag[(k)%NM]) | ||
91 | |||
92 | /* Computes the address of the value for the abstract index 'k' */ | ||
93 | #define getArrVal(t,k) (&(t)->array[ValueIndex(k)].value) | ||
94 | |||
95 | |||
96 | /* | ||
97 | ** Move TValues to/from arrays, using Lua indices | ||
98 | */ | ||
99 | #define arr2obj(h,k,val) \ | ||
100 | ((val)->tt_ = *getArrTag(h,(k)-1u), (val)->value_ = *getArrVal(h,(k)-1u)) | ||
101 | |||
102 | #define obj2arr(h,k,val) \ | ||
103 | (*getArrTag(h,(k)-1u) = (val)->tt_, *getArrVal(h,(k)-1u) = (val)->value_) | ||
104 | |||
105 | |||
106 | /* | ||
107 | ** Often, we need to check the tag of a value before moving it. These | ||
108 | ** macros also move TValues to/from arrays, but receive the precomputed | ||
109 | ** tag value or address as an extra argument. | ||
110 | */ | ||
111 | #define farr2val(h,k,tag,res) \ | ||
112 | ((res)->tt_ = tag, (res)->value_ = *getArrVal(h,(k)-1u)) | ||
113 | |||
114 | #define fval2arr(h,k,tag,val) \ | ||
115 | (*tag = (val)->tt_, *getArrVal(h,(k)-1u) = (val)->value_) | ||
116 | |||
117 | |||
118 | LUAI_FUNC int luaH_getshortstr (Table *t, TString *key, TValue *res); | ||
119 | LUAI_FUNC int luaH_getstr (Table *t, TString *key, TValue *res); | ||
120 | LUAI_FUNC int luaH_get (Table *t, const TValue *key, TValue *res); | ||
121 | LUAI_FUNC int luaH_getint (Table *t, lua_Integer key, TValue *res); | ||
122 | |||
123 | LUAI_FUNC TString *luaH_getstrkey (Table *t, TString *key); | ||
124 | |||
125 | LUAI_FUNC int luaH_psetint (Table *t, lua_Integer key, TValue *val); | ||
126 | LUAI_FUNC int luaH_psetshortstr (Table *t, TString *key, TValue *val); | ||
127 | LUAI_FUNC int luaH_psetstr (Table *t, TString *key, TValue *val); | ||
128 | LUAI_FUNC int luaH_pset (Table *t, const TValue *key, TValue *val); | ||
129 | |||
39 | LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, | 130 | LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, |
40 | TValue *value); | 131 | TValue *value); |
41 | LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); | 132 | LUAI_FUNC const TValue *luaH_Hgetshortstr (Table *t, TString *key); |
42 | LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); | ||
43 | LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); | ||
44 | LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key, | 133 | LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key, |
45 | TValue *value); | 134 | TValue *value); |
46 | LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key, | 135 | LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key, |
47 | const TValue *slot, TValue *value); | 136 | TValue *value, int aux); |
48 | LUAI_FUNC Table *luaH_new (lua_State *L); | 137 | LUAI_FUNC Table *luaH_new (lua_State *L); |
49 | LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, | 138 | LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, |
50 | unsigned int nhsize); | 139 | unsigned int nhsize); |
@@ -362,8 +362,11 @@ static void checktable (global_State *g, Table *h) { | |||
362 | Node *n, *limit = gnode(h, sizenode(h)); | 362 | Node *n, *limit = gnode(h, sizenode(h)); |
363 | GCObject *hgc = obj2gco(h); | 363 | GCObject *hgc = obj2gco(h); |
364 | checkobjrefN(g, hgc, h->metatable); | 364 | checkobjrefN(g, hgc, h->metatable); |
365 | for (i = 0; i < asize; i++) | 365 | for (i = 0; i < asize; i++) { |
366 | checkvalref(g, hgc, &h->array[i]); | 366 | TValue aux; |
367 | arr2obj(h, i + 1, &aux); | ||
368 | checkvalref(g, hgc, &aux); | ||
369 | } | ||
367 | for (n = gnode(h, 0); n < limit; n++) { | 370 | for (n = gnode(h, 0); n < limit; n++) { |
368 | if (!isempty(gval(n))) { | 371 | if (!isempty(gval(n))) { |
369 | TValue k; | 372 | TValue k; |
@@ -1005,7 +1008,8 @@ static int table_query (lua_State *L) { | |||
1005 | } | 1008 | } |
1006 | else if ((unsigned int)i < asize) { | 1009 | else if ((unsigned int)i < asize) { |
1007 | lua_pushinteger(L, i); | 1010 | lua_pushinteger(L, i); |
1008 | pushobject(L, &t->array[i]); | 1011 | arr2obj(t, i + 1, s2v(L->top.p)); |
1012 | api_incr_top(L); | ||
1009 | lua_pushnil(L); | 1013 | lua_pushnil(L); |
1010 | } | 1014 | } |
1011 | else if ((i -= asize) < sizenode(t)) { | 1015 | else if ((i -= asize) < sizenode(t)) { |
@@ -58,7 +58,7 @@ void luaT_init (lua_State *L) { | |||
58 | ** tag methods | 58 | ** tag methods |
59 | */ | 59 | */ |
60 | const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { | 60 | const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { |
61 | const TValue *tm = luaH_getshortstr(events, ename); | 61 | const TValue *tm = luaH_Hgetshortstr(events, ename); |
62 | lua_assert(event <= TM_EQ); | 62 | lua_assert(event <= TM_EQ); |
63 | if (notm(tm)) { /* no tag method? */ | 63 | if (notm(tm)) { /* no tag method? */ |
64 | events->flags |= cast_byte(1u<<event); /* cache this fact */ | 64 | events->flags |= cast_byte(1u<<event); /* cache this fact */ |
@@ -80,7 +80,7 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { | |||
80 | default: | 80 | default: |
81 | mt = G(L)->mt[ttype(o)]; | 81 | mt = G(L)->mt[ttype(o)]; |
82 | } | 82 | } |
83 | return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : &G(L)->nilvalue); | 83 | return (mt ? luaH_Hgetshortstr(mt, G(L)->tmname[event]) : &G(L)->nilvalue); |
84 | } | 84 | } |
85 | 85 | ||
86 | 86 | ||
@@ -92,9 +92,10 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) { | |||
92 | Table *mt; | 92 | Table *mt; |
93 | if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) || | 93 | if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) || |
94 | (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) { | 94 | (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) { |
95 | const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name")); | 95 | TValue name; |
96 | if (ttisstring(name)) /* is '__name' a string? */ | 96 | int hres = luaH_getshortstr(mt, luaS_new(L, "__name"), &name); |
97 | return getstr(tsvalue(name)); /* use it as type name */ | 97 | if (hres == HOK && ttisstring(&name)) /* is '__name' a string? */ |
98 | return getstr(tsvalue(&name)); /* use it as type name */ | ||
98 | } | 99 | } |
99 | return ttypename(ttype(o)); /* else use standard type name */ | 100 | return ttypename(ttype(o)); /* else use standard type name */ |
100 | } | 101 | } |
@@ -283,15 +283,13 @@ static int floatforloop (StkId ra) { | |||
283 | 283 | ||
284 | /* | 284 | /* |
285 | ** Finish the table access 'val = t[key]'. | 285 | ** Finish the table access 'val = t[key]'. |
286 | ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to | ||
287 | ** t[k] entry (which must be empty). | ||
288 | */ | 286 | */ |
289 | void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | 287 | void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, |
290 | const TValue *slot) { | 288 | int hres) { |
291 | int loop; /* counter to avoid infinite loops */ | 289 | int loop; /* counter to avoid infinite loops */ |
292 | const TValue *tm; /* metamethod */ | 290 | const TValue *tm; /* metamethod */ |
293 | for (loop = 0; loop < MAXTAGLOOP; loop++) { | 291 | for (loop = 0; loop < MAXTAGLOOP; loop++) { |
294 | if (slot == NULL) { /* 't' is not a table? */ | 292 | if (hres == HNOTATABLE) { /* 't' is not a table? */ |
295 | lua_assert(!ttistable(t)); | 293 | lua_assert(!ttistable(t)); |
296 | tm = luaT_gettmbyobj(L, t, TM_INDEX); | 294 | tm = luaT_gettmbyobj(L, t, TM_INDEX); |
297 | if (l_unlikely(notm(tm))) | 295 | if (l_unlikely(notm(tm))) |
@@ -299,7 +297,6 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | |||
299 | /* else will try the metamethod */ | 297 | /* else will try the metamethod */ |
300 | } | 298 | } |
301 | else { /* 't' is a table */ | 299 | else { /* 't' is a table */ |
302 | lua_assert(isempty(slot)); | ||
303 | tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ | 300 | tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ |
304 | if (tm == NULL) { /* no metamethod? */ | 301 | if (tm == NULL) { /* no metamethod? */ |
305 | setnilvalue(s2v(val)); /* result is nil */ | 302 | setnilvalue(s2v(val)); /* result is nil */ |
@@ -312,10 +309,9 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | |||
312 | return; | 309 | return; |
313 | } | 310 | } |
314 | t = tm; /* else try to access 'tm[key]' */ | 311 | t = tm; /* else try to access 'tm[key]' */ |
315 | if (luaV_fastget(L, t, key, slot, luaH_get)) { /* fast track? */ | 312 | luaV_fastget(t, key, s2v(val), luaH_get, hres); |
316 | setobj2s(L, val, slot); /* done */ | 313 | if (hres == HOK) |
317 | return; | 314 | return; /* done */ |
318 | } | ||
319 | /* else repeat (tail call 'luaV_finishget') */ | 315 | /* else repeat (tail call 'luaV_finishget') */ |
320 | } | 316 | } |
321 | luaG_runerror(L, "'__index' chain too long; possible loop"); | 317 | luaG_runerror(L, "'__index' chain too long; possible loop"); |
@@ -324,22 +320,17 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | |||
324 | 320 | ||
325 | /* | 321 | /* |
326 | ** Finish a table assignment 't[key] = val'. | 322 | ** Finish a table assignment 't[key] = val'. |
327 | ** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points | ||
328 | ** to the entry 't[key]', or to a value with an absent key if there | ||
329 | ** is no such entry. (The value at 'slot' must be empty, otherwise | ||
330 | ** 'luaV_fastget' would have done the job.) | ||
331 | */ | 323 | */ |
332 | void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | 324 | void luaV_finishset (lua_State *L, const TValue *t, TValue *key, |
333 | TValue *val, const TValue *slot) { | 325 | TValue *val, int hres) { |
334 | int loop; /* counter to avoid infinite loops */ | 326 | int loop; /* counter to avoid infinite loops */ |
335 | for (loop = 0; loop < MAXTAGLOOP; loop++) { | 327 | for (loop = 0; loop < MAXTAGLOOP; loop++) { |
336 | const TValue *tm; /* '__newindex' metamethod */ | 328 | const TValue *tm; /* '__newindex' metamethod */ |
337 | if (slot != NULL) { /* is 't' a table? */ | 329 | if (hres != HNOTATABLE) { /* is 't' a table? */ |
338 | Table *h = hvalue(t); /* save 't' table */ | 330 | Table *h = hvalue(t); /* save 't' table */ |
339 | lua_assert(isempty(slot)); /* slot must be empty */ | ||
340 | tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ | 331 | tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ |
341 | if (tm == NULL) { /* no metamethod? */ | 332 | if (tm == NULL) { /* no metamethod? */ |
342 | luaH_finishset(L, h, key, slot, val); /* set new value */ | 333 | luaH_finishset(L, h, key, val, hres); /* set new value */ |
343 | invalidateTMcache(h); | 334 | invalidateTMcache(h); |
344 | luaC_barrierback(L, obj2gco(h), val); | 335 | luaC_barrierback(L, obj2gco(h), val); |
345 | return; | 336 | return; |
@@ -357,10 +348,9 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | |||
357 | return; | 348 | return; |
358 | } | 349 | } |
359 | t = tm; /* else repeat assignment over 'tm' */ | 350 | t = tm; /* else repeat assignment over 'tm' */ |
360 | if (luaV_fastget(L, t, key, slot, luaH_get)) { | 351 | luaV_fastset(t, key, val, hres, luaH_pset); |
361 | luaV_finishfastset(L, t, slot, val); | 352 | if (hres == HOK) |
362 | return; /* done */ | 353 | return; /* done */ |
363 | } | ||
364 | /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ | 354 | /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ |
365 | } | 355 | } |
366 | luaG_runerror(L, "'__newindex' chain too long; possible loop"); | 356 | luaG_runerror(L, "'__newindex' chain too long; possible loop"); |
@@ -1248,114 +1238,109 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1248 | } | 1238 | } |
1249 | vmcase(OP_GETTABUP) { | 1239 | vmcase(OP_GETTABUP) { |
1250 | StkId ra = RA(i); | 1240 | StkId ra = RA(i); |
1251 | const TValue *slot; | ||
1252 | TValue *upval = cl->upvals[GETARG_B(i)]->v.p; | 1241 | TValue *upval = cl->upvals[GETARG_B(i)]->v.p; |
1253 | TValue *rc = KC(i); | 1242 | TValue *rc = KC(i); |
1254 | TString *key = tsvalue(rc); /* key must be a short string */ | 1243 | TString *key = tsvalue(rc); /* key must be a short string */ |
1255 | if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { | 1244 | int hres; |
1256 | setobj2s(L, ra, slot); | 1245 | luaV_fastget(upval, key, s2v(ra), luaH_getshortstr, hres); |
1257 | } | 1246 | if (hres != HOK) |
1258 | else | 1247 | Protect(luaV_finishget(L, upval, rc, ra, hres)); |
1259 | Protect(luaV_finishget(L, upval, rc, ra, slot)); | ||
1260 | vmbreak; | 1248 | vmbreak; |
1261 | } | 1249 | } |
1262 | vmcase(OP_GETTABLE) { | 1250 | vmcase(OP_GETTABLE) { |
1263 | StkId ra = RA(i); | 1251 | StkId ra = RA(i); |
1264 | const TValue *slot; | ||
1265 | TValue *rb = vRB(i); | 1252 | TValue *rb = vRB(i); |
1266 | TValue *rc = vRC(i); | 1253 | TValue *rc = vRC(i); |
1267 | lua_Unsigned n; | 1254 | int hres; |
1268 | if (ttisinteger(rc) /* fast track for integers? */ | 1255 | if (ttisinteger(rc)) { /* fast track for integers? */ |
1269 | ? (cast_void(n = ivalue(rc)), luaV_fastgeti(L, rb, n, slot)) | 1256 | luaV_fastgeti(rb, ivalue(rc), s2v(ra), hres); |
1270 | : luaV_fastget(L, rb, rc, slot, luaH_get)) { | ||
1271 | setobj2s(L, ra, slot); | ||
1272 | } | 1257 | } |
1273 | else | 1258 | else |
1274 | Protect(luaV_finishget(L, rb, rc, ra, slot)); | 1259 | luaV_fastget(rb, rc, s2v(ra), luaH_get, hres); |
1260 | if (hres != HOK) /* fast track for integers? */ | ||
1261 | Protect(luaV_finishget(L, rb, rc, ra, hres)); | ||
1275 | vmbreak; | 1262 | vmbreak; |
1276 | } | 1263 | } |
1277 | vmcase(OP_GETI) { | 1264 | vmcase(OP_GETI) { |
1278 | StkId ra = RA(i); | 1265 | StkId ra = RA(i); |
1279 | const TValue *slot; | ||
1280 | TValue *rb = vRB(i); | 1266 | TValue *rb = vRB(i); |
1281 | int c = GETARG_C(i); | 1267 | int c = GETARG_C(i); |
1282 | if (luaV_fastgeti(L, rb, c, slot)) { | 1268 | int hres; |
1283 | setobj2s(L, ra, slot); | 1269 | luaV_fastgeti(rb, c, s2v(ra), hres); |
1284 | } | 1270 | if (hres != HOK) { |
1285 | else { | ||
1286 | TValue key; | 1271 | TValue key; |
1287 | setivalue(&key, c); | 1272 | setivalue(&key, c); |
1288 | Protect(luaV_finishget(L, rb, &key, ra, slot)); | 1273 | Protect(luaV_finishget(L, rb, &key, ra, hres)); |
1289 | } | 1274 | } |
1290 | vmbreak; | 1275 | vmbreak; |
1291 | } | 1276 | } |
1292 | vmcase(OP_GETFIELD) { | 1277 | vmcase(OP_GETFIELD) { |
1293 | StkId ra = RA(i); | 1278 | StkId ra = RA(i); |
1294 | const TValue *slot; | ||
1295 | TValue *rb = vRB(i); | 1279 | TValue *rb = vRB(i); |
1296 | TValue *rc = KC(i); | 1280 | TValue *rc = KC(i); |
1297 | TString *key = tsvalue(rc); /* key must be a short string */ | 1281 | TString *key = tsvalue(rc); /* key must be a short string */ |
1298 | if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) { | 1282 | int hres; |
1299 | setobj2s(L, ra, slot); | 1283 | luaV_fastget(rb, key, s2v(ra), luaH_getshortstr, hres); |
1300 | } | 1284 | if (hres != HOK) |
1301 | else | 1285 | Protect(luaV_finishget(L, rb, rc, ra, hres)); |
1302 | Protect(luaV_finishget(L, rb, rc, ra, slot)); | ||
1303 | vmbreak; | 1286 | vmbreak; |
1304 | } | 1287 | } |
1305 | vmcase(OP_SETTABUP) { | 1288 | vmcase(OP_SETTABUP) { |
1306 | const TValue *slot; | 1289 | int hres; |
1307 | TValue *upval = cl->upvals[GETARG_A(i)]->v.p; | 1290 | TValue *upval = cl->upvals[GETARG_A(i)]->v.p; |
1308 | TValue *rb = KB(i); | 1291 | TValue *rb = KB(i); |
1309 | TValue *rc = RKC(i); | 1292 | TValue *rc = RKC(i); |
1310 | TString *key = tsvalue(rb); /* key must be a short string */ | 1293 | TString *key = tsvalue(rb); /* key must be a short string */ |
1311 | if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { | 1294 | luaV_fastset(upval, key, rc, hres, luaH_psetshortstr); |
1312 | luaV_finishfastset(L, upval, slot, rc); | 1295 | if (hres == HOK) |
1313 | } | 1296 | luaV_finishfastset(L, upval, rc); |
1314 | else | 1297 | else |
1315 | Protect(luaV_finishset(L, upval, rb, rc, slot)); | 1298 | Protect(luaV_finishset(L, upval, rb, rc, hres)); |
1316 | vmbreak; | 1299 | vmbreak; |
1317 | } | 1300 | } |
1318 | vmcase(OP_SETTABLE) { | 1301 | vmcase(OP_SETTABLE) { |
1319 | StkId ra = RA(i); | 1302 | StkId ra = RA(i); |
1320 | const TValue *slot; | 1303 | int hres; |
1321 | TValue *rb = vRB(i); /* key (table is in 'ra') */ | 1304 | TValue *rb = vRB(i); /* key (table is in 'ra') */ |
1322 | TValue *rc = RKC(i); /* value */ | 1305 | TValue *rc = RKC(i); /* value */ |
1323 | lua_Unsigned n; | 1306 | if (ttisinteger(rb)) { /* fast track for integers? */ |
1324 | if (ttisinteger(rb) /* fast track for integers? */ | 1307 | luaV_fastseti(s2v(ra), ivalue(rb), rc, hres); |
1325 | ? (cast_void(n = ivalue(rb)), luaV_fastgeti(L, s2v(ra), n, slot)) | 1308 | } |
1326 | : luaV_fastget(L, s2v(ra), rb, slot, luaH_get)) { | 1309 | else { |
1327 | luaV_finishfastset(L, s2v(ra), slot, rc); | 1310 | luaV_fastset(s2v(ra), rb, rc, hres, luaH_pset); |
1328 | } | 1311 | } |
1312 | if (hres == HOK) | ||
1313 | luaV_finishfastset(L, s2v(ra), rc); | ||
1329 | else | 1314 | else |
1330 | Protect(luaV_finishset(L, s2v(ra), rb, rc, slot)); | 1315 | Protect(luaV_finishset(L, s2v(ra), rb, rc, hres)); |
1331 | vmbreak; | 1316 | vmbreak; |
1332 | } | 1317 | } |
1333 | vmcase(OP_SETI) { | 1318 | vmcase(OP_SETI) { |
1334 | StkId ra = RA(i); | 1319 | StkId ra = RA(i); |
1335 | const TValue *slot; | 1320 | int hres; |
1336 | int c = GETARG_B(i); | 1321 | int b = GETARG_B(i); |
1337 | TValue *rc = RKC(i); | 1322 | TValue *rc = RKC(i); |
1338 | if (luaV_fastgeti(L, s2v(ra), c, slot)) { | 1323 | luaV_fastseti(s2v(ra), b, rc, hres); |
1339 | luaV_finishfastset(L, s2v(ra), slot, rc); | 1324 | if (hres == HOK) |
1340 | } | 1325 | luaV_finishfastset(L, s2v(ra), rc); |
1341 | else { | 1326 | else { |
1342 | TValue key; | 1327 | TValue key; |
1343 | setivalue(&key, c); | 1328 | setivalue(&key, b); |
1344 | Protect(luaV_finishset(L, s2v(ra), &key, rc, slot)); | 1329 | Protect(luaV_finishset(L, s2v(ra), &key, rc, hres)); |
1345 | } | 1330 | } |
1346 | vmbreak; | 1331 | vmbreak; |
1347 | } | 1332 | } |
1348 | vmcase(OP_SETFIELD) { | 1333 | vmcase(OP_SETFIELD) { |
1349 | StkId ra = RA(i); | 1334 | StkId ra = RA(i); |
1350 | const TValue *slot; | 1335 | int hres; |
1351 | TValue *rb = KB(i); | 1336 | TValue *rb = KB(i); |
1352 | TValue *rc = RKC(i); | 1337 | TValue *rc = RKC(i); |
1353 | TString *key = tsvalue(rb); /* key must be a short string */ | 1338 | TString *key = tsvalue(rb); /* key must be a short string */ |
1354 | if (luaV_fastget(L, s2v(ra), key, slot, luaH_getshortstr)) { | 1339 | luaV_fastset(s2v(ra), key, rc, hres, luaH_psetshortstr); |
1355 | luaV_finishfastset(L, s2v(ra), slot, rc); | 1340 | if (hres == HOK) |
1356 | } | 1341 | luaV_finishfastset(L, s2v(ra), rc); |
1357 | else | 1342 | else |
1358 | Protect(luaV_finishset(L, s2v(ra), rb, rc, slot)); | 1343 | Protect(luaV_finishset(L, s2v(ra), rb, rc, hres)); |
1359 | vmbreak; | 1344 | vmbreak; |
1360 | } | 1345 | } |
1361 | vmcase(OP_NEWTABLE) { | 1346 | vmcase(OP_NEWTABLE) { |
@@ -1379,16 +1364,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1379 | } | 1364 | } |
1380 | vmcase(OP_SELF) { | 1365 | vmcase(OP_SELF) { |
1381 | StkId ra = RA(i); | 1366 | StkId ra = RA(i); |
1382 | const TValue *slot; | 1367 | int hres; |
1383 | TValue *rb = vRB(i); | 1368 | TValue *rb = vRB(i); |
1384 | TValue *rc = RKC(i); | 1369 | TValue *rc = RKC(i); |
1385 | TString *key = tsvalue(rc); /* key must be a string */ | 1370 | TString *key = tsvalue(rc); /* key must be a string */ |
1386 | setobj2s(L, ra + 1, rb); | 1371 | setobj2s(L, ra + 1, rb); |
1387 | if (luaV_fastget(L, rb, key, slot, luaH_getstr)) { | 1372 | luaV_fastget(rb, key, s2v(ra), luaH_getstr, hres); |
1388 | setobj2s(L, ra, slot); | 1373 | if (hres != HOK) |
1389 | } | 1374 | Protect(luaV_finishget(L, rb, rc, ra, hres)); |
1390 | else | ||
1391 | Protect(luaV_finishget(L, rb, rc, ra, slot)); | ||
1392 | vmbreak; | 1375 | vmbreak; |
1393 | } | 1376 | } |
1394 | vmcase(OP_ADDI) { | 1377 | vmcase(OP_ADDI) { |
@@ -1860,7 +1843,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1860 | luaH_resizearray(L, h, last); /* preallocate it at once */ | 1843 | luaH_resizearray(L, h, last); /* preallocate it at once */ |
1861 | for (; n > 0; n--) { | 1844 | for (; n > 0; n--) { |
1862 | TValue *val = s2v(ra + n); | 1845 | TValue *val = s2v(ra + n); |
1863 | setobj2t(L, &h->array[last - 1], val); | 1846 | obj2arr(h, last, val); |
1864 | last--; | 1847 | last--; |
1865 | luaC_barrierback(L, obj2gco(h), val); | 1848 | luaC_barrierback(L, obj2gco(h), val); |
1866 | } | 1849 | } |
@@ -76,38 +76,43 @@ typedef enum { | |||
76 | 76 | ||
77 | 77 | ||
78 | /* | 78 | /* |
79 | ** fast track for 'gettable': if 't' is a table and 't[k]' is present, | 79 | ** fast track for 'gettable' |
80 | ** return 1 with 'slot' pointing to 't[k]' (position of final result). | ||
81 | ** Otherwise, return 0 (meaning it will have to check metamethod) | ||
82 | ** with 'slot' pointing to an empty 't[k]' (if 't' is a table) or NULL | ||
83 | ** (otherwise). 'f' is the raw get function to use. | ||
84 | */ | 80 | */ |
85 | #define luaV_fastget(L,t,k,slot,f) \ | 81 | #define luaV_fastget(t,k,res,f, aux) \ |
86 | (!ttistable(t) \ | 82 | (aux = (!ttistable(t) ? HNOTATABLE : f(hvalue(t), k, res))) |
87 | ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ | ||
88 | : (slot = f(hvalue(t), k), /* else, do raw access */ \ | ||
89 | !isempty(slot))) /* result not empty? */ | ||
90 | 83 | ||
91 | 84 | ||
92 | /* | 85 | /* |
93 | ** Special case of 'luaV_fastget' for integers, inlining the fast case | 86 | ** Special case of 'luaV_fastget' for integers, inlining the fast case |
94 | ** of 'luaH_getint'. | 87 | ** of 'luaH_getint'. |
95 | */ | 88 | */ |
96 | #define luaV_fastgeti(L,t,k,slot) \ | 89 | #define luaV_fastgeti(t,k,res,aux) \ |
97 | (!ttistable(t) \ | 90 | if (!ttistable(t)) aux = HNOTATABLE; \ |
98 | ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ | 91 | else { Table *h = hvalue(t); lua_Unsigned u = l_castS2U(k); \ |
99 | : (slot = (l_castS2U(k) - 1u < hvalue(t)->alimit) \ | 92 | if ((u - 1u < h->alimit)) { \ |
100 | ? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \ | 93 | int tag = *getArrTag(h,(u)-1u); \ |
101 | !isempty(slot))) /* result not empty? */ | 94 | if (tagisempty(tag)) aux = HNOTFOUND; \ |
95 | else { farr2val(h, u, tag, res); aux = HOK; }} \ | ||
96 | else { aux = luaH_getint(h, u, res); }} | ||
97 | |||
98 | |||
99 | #define luaV_fastset(t,k,val,aux,f) \ | ||
100 | (aux = (!ttistable(t) ? HNOTATABLE : f(hvalue(t), k, val))) | ||
101 | |||
102 | #define luaV_fastseti(t,k,val,aux) \ | ||
103 | if (!ttistable(t)) aux = HNOTATABLE; \ | ||
104 | else { Table *h = hvalue(t); lua_Unsigned u = l_castS2U(k); \ | ||
105 | if ((u - 1u < h->alimit)) { \ | ||
106 | lu_byte *tag = getArrTag(h,(u)-1u); \ | ||
107 | if (tagisempty(*tag)) aux = ~cast_int(u); \ | ||
108 | else { fval2arr(h, u, tag, val); aux = HOK; }} \ | ||
109 | else { aux = luaH_psetint(h, u, val); }} | ||
102 | 110 | ||
103 | 111 | ||
104 | /* | 112 | /* |
105 | ** Finish a fast set operation (when fast get succeeds). In that case, | 113 | ** Finish a fast set operation (when fast set succeeds). |
106 | ** 'slot' points to the place to put the value. | ||
107 | */ | 114 | */ |
108 | #define luaV_finishfastset(L,t,slot,v) \ | 115 | #define luaV_finishfastset(L,t,v) luaC_barrierback(L, gcvalue(t), v) |
109 | { setobj2t(L, cast(TValue *,slot), v); \ | ||
110 | luaC_barrierback(L, gcvalue(t), v); } | ||
111 | 116 | ||
112 | 117 | ||
113 | /* | 118 | /* |
@@ -126,9 +131,9 @@ LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p, | |||
126 | F2Imod mode); | 131 | F2Imod mode); |
127 | LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode); | 132 | LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode); |
128 | LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, | 133 | LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, |
129 | StkId val, const TValue *slot); | 134 | StkId val, int aux); |
130 | LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | 135 | LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, |
131 | TValue *val, const TValue *slot); | 136 | TValue *val, int aux); |
132 | LUAI_FUNC void luaV_finishOp (lua_State *L); | 137 | LUAI_FUNC void luaV_finishOp (lua_State *L); |
133 | LUAI_FUNC void luaV_execute (lua_State *L, CallInfo *ci); | 138 | LUAI_FUNC void luaV_execute (lua_State *L, CallInfo *ci); |
134 | LUAI_FUNC void luaV_concat (lua_State *L, int total); | 139 | LUAI_FUNC void luaV_concat (lua_State *L, int total); |