diff options
Diffstat (limited to '')
-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 | 328 | ||||
-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, 528 insertions, 273 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); |
@@ -73,6 +73,13 @@ | |||
73 | #define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL) | 73 | #define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL) |
74 | 74 | ||
75 | 75 | ||
76 | /* | ||
77 | ** Access to collectable objects in array part of tables | ||
78 | */ | ||
79 | #define gcvalarr(t,i) \ | ||
80 | ((*getArrTag(t,i) & BIT_ISCOLLECTABLE) ? getArrVal(t,i)->gc : NULL) | ||
81 | |||
82 | |||
76 | #define markvalue(g,o) { checkliveness(g->mainthread,o); \ | 83 | #define markvalue(g,o) { checkliveness(g->mainthread,o); \ |
77 | if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } | 84 | if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } |
78 | 85 | ||
@@ -477,9 +484,10 @@ static int traverseephemeron (global_State *g, Table *h, int inv) { | |||
477 | unsigned int nsize = sizenode(h); | 484 | unsigned int nsize = sizenode(h); |
478 | /* traverse array part */ | 485 | /* traverse array part */ |
479 | for (i = 0; i < asize; i++) { | 486 | for (i = 0; i < asize; i++) { |
480 | if (valiswhite(&h->array[i])) { | 487 | GCObject *o = gcvalarr(h, i); |
488 | if (o != NULL && iswhite(o)) { | ||
481 | marked = 1; | 489 | marked = 1; |
482 | reallymarkobject(g, gcvalue(&h->array[i])); | 490 | reallymarkobject(g, o); |
483 | } | 491 | } |
484 | } | 492 | } |
485 | /* traverse hash part; if 'inv', traverse descending | 493 | /* traverse hash part; if 'inv', traverse descending |
@@ -515,8 +523,11 @@ static void traversestrongtable (global_State *g, Table *h) { | |||
515 | Node *n, *limit = gnodelast(h); | 523 | Node *n, *limit = gnodelast(h); |
516 | unsigned int i; | 524 | unsigned int i; |
517 | unsigned int asize = luaH_realasize(h); | 525 | unsigned int asize = luaH_realasize(h); |
518 | for (i = 0; i < asize; i++) /* traverse array part */ | 526 | for (i = 0; i < asize; i++) { /* traverse array part */ |
519 | markvalue(g, &h->array[i]); | 527 | GCObject *o = gcvalarr(h, i); |
528 | if (o != NULL && iswhite(o)) | ||
529 | reallymarkobject(g, o); | ||
530 | } | ||
520 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ | 531 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ |
521 | if (isempty(gval(n))) /* entry is empty? */ | 532 | if (isempty(gval(n))) /* entry is empty? */ |
522 | clearkey(n); /* clear its key */ | 533 | clearkey(n); /* clear its key */ |
@@ -741,9 +752,9 @@ static l_obj clearbyvalues (global_State *g, GCObject *l, GCObject *f) { | |||
741 | unsigned int i; | 752 | unsigned int i; |
742 | unsigned int asize = luaH_realasize(h); | 753 | unsigned int asize = luaH_realasize(h); |
743 | for (i = 0; i < asize; i++) { | 754 | for (i = 0; i < asize; i++) { |
744 | TValue *o = &h->array[i]; | 755 | GCObject *o = gcvalarr(h, i); |
745 | if (iscleared(g, gcvalueN(o))) /* value was collected? */ | 756 | if (iscleared(g, o)) /* value was collected? */ |
746 | setempty(o); /* remove entry */ | 757 | *getArrTag(h, i) = LUA_VEMPTY; /* remove entry */ |
747 | } | 758 | } |
748 | for (n = gnode(h, 0); n < limit; n++) { | 759 | for (n = gnode(h, 0); n < limit; n++) { |
749 | if (iscleared(g, gcvalueN(gval(n)))) /* unmarked value? */ | 760 | 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) |
@@ -749,12 +751,15 @@ typedef union Node { | |||
749 | #define setnorealasize(t) ((t)->flags |= BITRAS) | 751 | #define setnorealasize(t) ((t)->flags |= BITRAS) |
750 | 752 | ||
751 | 753 | ||
754 | typedef union ArrayCell ArrayCell; | ||
755 | |||
756 | |||
752 | typedef struct Table { | 757 | typedef struct Table { |
753 | CommonHeader; | 758 | CommonHeader; |
754 | lu_byte flags; /* 1<<p means tagmethod(p) is not present */ | 759 | lu_byte flags; /* 1<<p means tagmethod(p) is not present */ |
755 | lu_byte lsizenode; /* log2 of size of 'node' array */ | 760 | lu_byte lsizenode; /* log2 of size of 'node' array */ |
756 | unsigned int alimit; /* "limit" of 'array' array */ | 761 | unsigned int alimit; /* "limit" of 'array' array */ |
757 | TValue *array; /* array part */ | 762 | ArrayCell *array; /* array part */ |
758 | Node *node; | 763 | Node *node; |
759 | struct Table *metatable; | 764 | struct Table *metatable; |
760 | GCObject *gclist; | 765 | GCObject *gclist; |
@@ -184,13 +184,16 @@ static void freestack (lua_State *L) { | |||
184 | */ | 184 | */ |
185 | static void init_registry (lua_State *L, global_State *g) { | 185 | static void init_registry (lua_State *L, global_State *g) { |
186 | /* create registry */ | 186 | /* create registry */ |
187 | TValue aux; | ||
187 | Table *registry = luaH_new(L); | 188 | Table *registry = luaH_new(L); |
188 | sethvalue(L, &g->l_registry, registry); | 189 | sethvalue(L, &g->l_registry, registry); |
189 | luaH_resize(L, registry, LUA_RIDX_LAST, 0); | 190 | luaH_resize(L, registry, LUA_RIDX_LAST, 0); |
190 | /* registry[LUA_RIDX_MAINTHREAD] = L */ | 191 | /* registry[LUA_RIDX_MAINTHREAD] = L */ |
191 | setthvalue(L, ®istry->array[LUA_RIDX_MAINTHREAD - 1], L); | 192 | setthvalue(L, &aux, L); |
193 | luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &aux); | ||
192 | /* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */ | 194 | /* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */ |
193 | sethvalue(L, ®istry->array[LUA_RIDX_GLOBALS - 1], luaH_new(L)); | 195 | sethvalue(L, &aux, luaH_new(L)); |
196 | luaH_setint(L, registry, LUA_RIDX_GLOBALS, &aux); | ||
194 | } | 197 | } |
195 | 198 | ||
196 | 199 | ||
@@ -371,9 +371,10 @@ int luaH_next (lua_State *L, Table *t, StkId key) { | |||
371 | unsigned int asize = luaH_realasize(t); | 371 | unsigned int asize = luaH_realasize(t); |
372 | unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */ | 372 | unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */ |
373 | for (; i < asize; i++) { /* try first array part */ | 373 | for (; i < asize; i++) { /* try first array part */ |
374 | if (!isempty(&t->array[i])) { /* a non-empty entry? */ | 374 | int tag = *getArrTag(t, i); |
375 | if (!tagisempty(tag)) { /* a non-empty entry? */ | ||
375 | setivalue(s2v(key), i + 1); | 376 | setivalue(s2v(key), i + 1); |
376 | setobj2s(L, key + 1, &t->array[i]); | 377 | farr2val(t, i + 1, tag, s2v(key + 1)); |
377 | return 1; | 378 | return 1; |
378 | } | 379 | } |
379 | } | 380 | } |
@@ -403,6 +404,41 @@ static void freehash (lua_State *L, Table *t) { | |||
403 | 404 | ||
404 | 405 | ||
405 | /* | 406 | /* |
407 | ** Check whether an integer key is in the array part. If 'alimit' is | ||
408 | ** not the real size of the array, the key still can be in the array | ||
409 | ** part. In this case, do the "Xmilia trick" to check whether 'key-1' | ||
410 | ** is smaller than the real size. | ||
411 | ** The trick works as follow: let 'p' be an integer such that | ||
412 | ** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'. | ||
413 | ** That is, 2^(p+1) is the real size of the array, and 'p' is the highest | ||
414 | ** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'. | ||
415 | ** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will | ||
416 | ** have the 'p' bit cleared. If the key is outside the array, that is, | ||
417 | ** 'key-1 >= 2^(p+1)', then 'res' will have some 1-bit higher than 'p', | ||
418 | ** therefore it will be larger or equal to 'alimit', and the check | ||
419 | ** will fail. If 'key-1 < 2^(p+1)', then 'res' has no 1-bit higher than | ||
420 | ** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller | ||
421 | ** than 2^p, therefore smaller than 'alimit', and the check succeeds. | ||
422 | ** As special cases, when 'alimit' is 0 the condition is trivially false, | ||
423 | ** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'. | ||
424 | ** If key is 0 or negative, 'res' will have its higher bit on, so that | ||
425 | ** if cannot be smaller than alimit. | ||
426 | */ | ||
427 | static int keyinarray (Table *t, lua_Integer key) { | ||
428 | lua_Unsigned alimit = t->alimit; | ||
429 | if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */ | ||
430 | return 1; | ||
431 | else if (!isrealasize(t) && /* key still may be in the array part? */ | ||
432 | (((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) { | ||
433 | t->alimit = cast_uint(key); /* probably '#t' is here now */ | ||
434 | return 1; | ||
435 | } | ||
436 | else | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | |||
441 | /* | ||
406 | ** {============================================================= | 442 | ** {============================================================= |
407 | ** Rehash | 443 | ** Rehash |
408 | ** ============================================================== | 444 | ** ============================================================== |
@@ -449,6 +485,12 @@ static int countint (lua_Integer key, unsigned int *nums) { | |||
449 | } | 485 | } |
450 | 486 | ||
451 | 487 | ||
488 | l_sinline int arraykeyisempty (const Table *t, lua_Integer key) { | ||
489 | int tag = *getArrTag(t, key - 1); | ||
490 | return tagisempty(tag); | ||
491 | } | ||
492 | |||
493 | |||
452 | /* | 494 | /* |
453 | ** Count keys in array part of table 't': Fill 'nums[i]' with | 495 | ** Count keys in array part of table 't': Fill 'nums[i]' with |
454 | ** number of keys that will go into corresponding slice and return | 496 | ** number of keys that will go into corresponding slice and return |
@@ -471,7 +513,7 @@ static unsigned int numusearray (const Table *t, unsigned int *nums) { | |||
471 | } | 513 | } |
472 | /* count elements in range (2^(lg - 1), 2^lg] */ | 514 | /* count elements in range (2^(lg - 1), 2^lg] */ |
473 | for (; i <= lim; i++) { | 515 | for (; i <= lim; i++) { |
474 | if (!isempty(&t->array[i-1])) | 516 | if (!arraykeyisempty(t, i)) |
475 | lc++; | 517 | lc++; |
476 | } | 518 | } |
477 | nums[lg] += lc; | 519 | nums[lg] += lc; |
@@ -499,6 +541,33 @@ static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { | |||
499 | 541 | ||
500 | 542 | ||
501 | /* | 543 | /* |
544 | ** Convert an "abstract size" (number of values in an array) to | ||
545 | ** "concrete size" (number of cell elements in the array). Cells | ||
546 | ** do not need to be full; we only must make sure it has the values | ||
547 | ** needed and its 'tag' element. So, we compute the concrete tag index | ||
548 | ** and the concrete value index of the last element, get their maximum | ||
549 | ** and adds 1. | ||
550 | */ | ||
551 | static unsigned int concretesize (unsigned int size) { | ||
552 | if (size == 0) return 0; | ||
553 | else { | ||
554 | unsigned int ts = TagIndex(size - 1); | ||
555 | unsigned int vs = ValueIndex(size - 1); | ||
556 | return ((ts >= vs) ? ts : vs) + 1; | ||
557 | } | ||
558 | } | ||
559 | |||
560 | |||
561 | static ArrayCell *resizearray (lua_State *L , Table *t, | ||
562 | unsigned int oldasize, | ||
563 | unsigned int newasize) { | ||
564 | oldasize = concretesize(oldasize); | ||
565 | newasize = concretesize(newasize); | ||
566 | return luaM_reallocvector(L, t->array, oldasize, newasize, ArrayCell); | ||
567 | } | ||
568 | |||
569 | |||
570 | /* | ||
502 | ** Creates an array for the hash part of a table with the given | 571 | ** Creates an array for the hash part of a table with the given |
503 | ** size, or reuses the dummy node if size is zero. | 572 | ** size, or reuses the dummy node if size is zero. |
504 | ** The computation for size overflow is in two steps: the first | 573 | ** The computation for size overflow is in two steps: the first |
@@ -593,7 +662,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
593 | unsigned int i; | 662 | unsigned int i; |
594 | Table newt; /* to keep the new hash part */ | 663 | Table newt; /* to keep the new hash part */ |
595 | unsigned int oldasize = setlimittosize(t); | 664 | unsigned int oldasize = setlimittosize(t); |
596 | TValue *newarray; | 665 | ArrayCell *newarray; |
597 | /* create new hash part with appropriate size into 'newt' */ | 666 | /* create new hash part with appropriate size into 'newt' */ |
598 | newt.flags = 0; | 667 | newt.flags = 0; |
599 | setnodevector(L, &newt, nhsize); | 668 | setnodevector(L, &newt, nhsize); |
@@ -602,14 +671,18 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
602 | exchangehashpart(t, &newt); /* and new hash */ | 671 | exchangehashpart(t, &newt); /* and new hash */ |
603 | /* re-insert into the new hash the elements from vanishing slice */ | 672 | /* re-insert into the new hash the elements from vanishing slice */ |
604 | for (i = newasize; i < oldasize; i++) { | 673 | for (i = newasize; i < oldasize; i++) { |
605 | if (!isempty(&t->array[i])) | 674 | int tag = *getArrTag(t, i); |
606 | luaH_setint(L, t, i + 1, &t->array[i]); | 675 | if (!tagisempty(tag)) { /* a non-empty entry? */ |
676 | TValue aux; | ||
677 | farr2val(t, i + 1, tag, &aux); | ||
678 | luaH_setint(L, t, i + 1, &aux); | ||
679 | } | ||
607 | } | 680 | } |
608 | t->alimit = oldasize; /* restore current size... */ | 681 | t->alimit = oldasize; /* restore current size... */ |
609 | exchangehashpart(t, &newt); /* and hash (in case of errors) */ | 682 | exchangehashpart(t, &newt); /* and hash (in case of errors) */ |
610 | } | 683 | } |
611 | /* allocate new array */ | 684 | /* allocate new array */ |
612 | newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue); | 685 | newarray = resizearray(L, t, oldasize, newasize); |
613 | if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ | 686 | if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ |
614 | freehash(L, &newt); /* release new hash part */ | 687 | freehash(L, &newt); /* release new hash part */ |
615 | luaM_error(L); /* raise error (with array unchanged) */ | 688 | luaM_error(L); /* raise error (with array unchanged) */ |
@@ -619,7 +692,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
619 | t->array = newarray; /* set new array part */ | 692 | t->array = newarray; /* set new array part */ |
620 | t->alimit = newasize; | 693 | t->alimit = newasize; |
621 | for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ | 694 | for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ |
622 | setempty(&t->array[i]); | 695 | *getArrTag(t, i) = LUA_VEMPTY; |
623 | /* re-insert elements from old hash part into new parts */ | 696 | /* re-insert elements from old hash part into new parts */ |
624 | reinsert(L, &newt, t); /* 'newt' now has the old hash */ | 697 | reinsert(L, &newt, t); /* 'newt' now has the old hash */ |
625 | freehash(L, &newt); /* free old hash part */ | 698 | freehash(L, &newt); /* free old hash part */ |
@@ -675,8 +748,9 @@ Table *luaH_new (lua_State *L) { | |||
675 | 748 | ||
676 | 749 | ||
677 | void luaH_free (lua_State *L, Table *t) { | 750 | void luaH_free (lua_State *L, Table *t) { |
751 | unsigned ps = concretesize(luaH_realasize(t)); | ||
678 | freehash(L, t); | 752 | freehash(L, t); |
679 | luaM_freearray(L, t->array, luaH_realasize(t)); | 753 | luaM_freearray(L, t->array, ps); |
680 | luaM_free(L, t); | 754 | luaM_free(L, t); |
681 | } | 755 | } |
682 | 756 | ||
@@ -770,57 +844,57 @@ static void luaH_newkey (lua_State *L, Table *t, const TValue *key, | |||
770 | } | 844 | } |
771 | 845 | ||
772 | 846 | ||
773 | /* | 847 | static const TValue *getintfromhash (Table *t, lua_Integer key) { |
774 | ** Search function for integers. If integer is inside 'alimit', get it | 848 | Node *n = hashint(t, key); |
775 | ** directly from the array part. Otherwise, if 'alimit' is not | 849 | lua_assert(l_castS2U(key) - 1u >= luaH_realasize(t)); |
776 | ** the real size of the array, the key still can be in the array part. | 850 | for (;;) { /* check whether 'key' is somewhere in the chain */ |
777 | ** In this case, do the "Xmilia trick" to check whether 'key-1' is | 851 | if (keyisinteger(n) && keyival(n) == key) |
778 | ** smaller than the real size. | 852 | return gval(n); /* that's it */ |
779 | ** The trick works as follow: let 'p' be an integer such that | 853 | else { |
780 | ** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'. | 854 | int nx = gnext(n); |
781 | ** That is, 2^(p+1) is the real size of the array, and 'p' is the highest | 855 | if (nx == 0) break; |
782 | ** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'. | 856 | n += nx; |
783 | ** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will | 857 | } |
784 | ** have the 'p' bit cleared. If the key is outside the array, that is, | ||
785 | ** 'key-1 >= 2^(p+1)', then 'res' will have some bit on higher than 'p', | ||
786 | ** therefore it will be larger or equal to 'alimit', and the check | ||
787 | ** will fail. If 'key-1 < 2^(p+1)', then 'res' has no bit on higher than | ||
788 | ** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller | ||
789 | ** than 2^p, therefore smaller than 'alimit', and the check succeeds. | ||
790 | ** As special cases, when 'alimit' is 0 the condition is trivially false, | ||
791 | ** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'. | ||
792 | ** If key is 0 or negative, 'res' will have its higher bit on, so that | ||
793 | ** if cannot be smaller than alimit. | ||
794 | */ | ||
795 | const TValue *luaH_getint (Table *t, lua_Integer key) { | ||
796 | lua_Unsigned alimit = t->alimit; | ||
797 | if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */ | ||
798 | return &t->array[key - 1]; | ||
799 | else if (!isrealasize(t) && /* key still may be in the array part? */ | ||
800 | (((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) { | ||
801 | t->alimit = cast_uint(key); /* probably '#t' is here now */ | ||
802 | return &t->array[key - 1]; | ||
803 | } | 858 | } |
804 | else { /* key is not in the array part; check the hash */ | 859 | return &absentkey; |
805 | Node *n = hashint(t, key); | 860 | } |
806 | for (;;) { /* check whether 'key' is somewhere in the chain */ | 861 | |
807 | if (keyisinteger(n) && keyival(n) == key) | 862 | |
808 | return gval(n); /* that's it */ | 863 | static int hashkeyisempty (Table *t, lua_Integer key) { |
809 | else { | 864 | const TValue *val = getintfromhash(t, key); |
810 | int nx = gnext(n); | 865 | return isempty(val); |
811 | if (nx == 0) break; | 866 | } |
812 | n += nx; | 867 | |
813 | } | 868 | |
869 | static int finishnodeget (const TValue *val, TValue *res) { | ||
870 | if (!ttisnil(val)) { | ||
871 | setobj(((lua_State*)NULL), res, val); | ||
872 | return HOK; /* success */ | ||
873 | } | ||
874 | else | ||
875 | return HNOTFOUND; /* could not get value */ | ||
876 | } | ||
877 | |||
878 | |||
879 | int luaH_getint (Table *t, lua_Integer key, TValue *res) { | ||
880 | if (keyinarray(t, key)) { | ||
881 | int tag = *getArrTag(t, key - 1); | ||
882 | if (!tagisempty(tag)) { | ||
883 | farr2val(t, key, tag, res); | ||
884 | return HOK; /* success */ | ||
814 | } | 885 | } |
815 | return &absentkey; | 886 | else |
887 | return ~cast_int(key); /* empty slot in the array part */ | ||
816 | } | 888 | } |
889 | else | ||
890 | return finishnodeget(getintfromhash(t, key), res); | ||
817 | } | 891 | } |
818 | 892 | ||
819 | 893 | ||
820 | /* | 894 | /* |
821 | ** search function for short strings | 895 | ** search function for short strings |
822 | */ | 896 | */ |
823 | const TValue *luaH_getshortstr (Table *t, TString *key) { | 897 | const TValue *luaH_Hgetshortstr (Table *t, TString *key) { |
824 | Node *n = hashstr(t, key); | 898 | Node *n = hashstr(t, key); |
825 | lua_assert(key->tt == LUA_VSHRSTR); | 899 | lua_assert(key->tt == LUA_VSHRSTR); |
826 | for (;;) { /* check whether 'key' is somewhere in the chain */ | 900 | for (;;) { /* check whether 'key' is somewhere in the chain */ |
@@ -836,9 +910,14 @@ const TValue *luaH_getshortstr (Table *t, TString *key) { | |||
836 | } | 910 | } |
837 | 911 | ||
838 | 912 | ||
839 | const TValue *luaH_getstr (Table *t, TString *key) { | 913 | int luaH_getshortstr (Table *t, TString *key, TValue *res) { |
914 | return finishnodeget(luaH_Hgetshortstr(t, key), res); | ||
915 | } | ||
916 | |||
917 | |||
918 | static const TValue *Hgetstr (Table *t, TString *key) { | ||
840 | if (key->tt == LUA_VSHRSTR) | 919 | if (key->tt == LUA_VSHRSTR) |
841 | return luaH_getshortstr(t, key); | 920 | return luaH_Hgetshortstr(t, key); |
842 | else { /* for long strings, use generic case */ | 921 | else { /* for long strings, use generic case */ |
843 | TValue ko; | 922 | TValue ko; |
844 | setsvalue(cast(lua_State *, NULL), &ko, key); | 923 | setsvalue(cast(lua_State *, NULL), &ko, key); |
@@ -847,38 +926,121 @@ const TValue *luaH_getstr (Table *t, TString *key) { | |||
847 | } | 926 | } |
848 | 927 | ||
849 | 928 | ||
929 | int luaH_getstr (Table *t, TString *key, TValue *res) { | ||
930 | return finishnodeget(Hgetstr(t, key), res); | ||
931 | } | ||
932 | |||
933 | |||
934 | TString *luaH_getstrkey (Table *t, TString *key) { | ||
935 | const TValue *o = Hgetstr(t, key); | ||
936 | if (!isabstkey(o)) /* string already present? */ | ||
937 | return keystrval(nodefromval(o)); /* get saved copy */ | ||
938 | else | ||
939 | return NULL; | ||
940 | } | ||
941 | |||
942 | |||
850 | /* | 943 | /* |
851 | ** main search function | 944 | ** main search function |
852 | */ | 945 | */ |
853 | const TValue *luaH_get (Table *t, const TValue *key) { | 946 | int luaH_get (Table *t, const TValue *key, TValue *res) { |
947 | const TValue *slot; | ||
854 | switch (ttypetag(key)) { | 948 | switch (ttypetag(key)) { |
855 | case LUA_VSHRSTR: return luaH_getshortstr(t, tsvalue(key)); | 949 | case LUA_VSHRSTR: |
856 | case LUA_VNUMINT: return luaH_getint(t, ivalue(key)); | 950 | slot = luaH_Hgetshortstr(t, tsvalue(key)); |
857 | case LUA_VNIL: return &absentkey; | 951 | break; |
952 | case LUA_VNUMINT: | ||
953 | return luaH_getint(t, ivalue(key), res); | ||
954 | case LUA_VNIL: | ||
955 | slot = &absentkey; | ||
956 | break; | ||
858 | case LUA_VNUMFLT: { | 957 | case LUA_VNUMFLT: { |
859 | lua_Integer k; | 958 | lua_Integer k; |
860 | if (luaV_flttointeger(fltvalue(key), &k, F2Ieq)) /* integral index? */ | 959 | if (luaV_flttointeger(fltvalue(key), &k, F2Ieq)) /* integral index? */ |
861 | return luaH_getint(t, k); /* use specialized version */ | 960 | return luaH_getint(t, k, res); /* use specialized version */ |
862 | /* else... */ | 961 | /* else... */ |
863 | } /* FALLTHROUGH */ | 962 | } /* FALLTHROUGH */ |
864 | default: | 963 | default: |
865 | return getgeneric(t, key, 0); | 964 | slot = getgeneric(t, key, 0); |
965 | break; | ||
866 | } | 966 | } |
967 | return finishnodeget(slot, res); | ||
867 | } | 968 | } |
868 | 969 | ||
869 | 970 | ||
971 | static int finishnodeset (Table *t, const TValue *slot, TValue *val) { | ||
972 | if (!ttisnil(slot)) { | ||
973 | setobj(((lua_State*)NULL), cast(TValue*, slot), val); | ||
974 | return HOK; /* success */ | ||
975 | } | ||
976 | else if (isabstkey(slot)) | ||
977 | return HNOTFOUND; /* no slot with that key */ | ||
978 | else return (cast(Node*, slot) - t->node) + HFIRSTNODE; /* node encoded */ | ||
979 | } | ||
980 | |||
981 | |||
982 | int luaH_psetint (Table *t, lua_Integer key, TValue *val) { | ||
983 | if (keyinarray(t, key)) { | ||
984 | lu_byte *tag = getArrTag(t, key - 1); | ||
985 | if (!tagisempty(*tag)) { | ||
986 | fval2arr(t, key, tag, val); | ||
987 | return HOK; /* success */ | ||
988 | } | ||
989 | else | ||
990 | return ~cast_int(key); /* empty slot in the array part */ | ||
991 | } | ||
992 | else | ||
993 | return finishnodeset(t, getintfromhash(t, key), val); | ||
994 | } | ||
995 | |||
996 | |||
997 | int luaH_psetshortstr (Table *t, TString *key, TValue *val) { | ||
998 | return finishnodeset(t, luaH_Hgetshortstr(t, key), val); | ||
999 | } | ||
1000 | |||
1001 | |||
1002 | int luaH_psetstr (Table *t, TString *key, TValue *val) { | ||
1003 | return finishnodeset(t, Hgetstr(t, key), val); | ||
1004 | } | ||
1005 | |||
1006 | |||
1007 | int luaH_pset (Table *t, const TValue *key, TValue *val) { | ||
1008 | switch (ttypetag(key)) { | ||
1009 | case LUA_VSHRSTR: return luaH_psetshortstr(t, tsvalue(key), val); | ||
1010 | case LUA_VNUMINT: return luaH_psetint(t, ivalue(key), val); | ||
1011 | case LUA_VNIL: return HNOTFOUND; | ||
1012 | case LUA_VNUMFLT: { | ||
1013 | lua_Integer k; | ||
1014 | if (luaV_flttointeger(fltvalue(key), &k, F2Ieq)) /* integral index? */ | ||
1015 | return luaH_psetint(t, k, val); /* use specialized version */ | ||
1016 | /* else... */ | ||
1017 | } /* FALLTHROUGH */ | ||
1018 | default: | ||
1019 | return finishnodeset(t, getgeneric(t, key, 0), val); | ||
1020 | } | ||
1021 | } | ||
1022 | |||
870 | /* | 1023 | /* |
871 | ** Finish a raw "set table" operation, where 'slot' is where the value | 1024 | ** Finish a raw "set table" operation, where 'slot' is where the value |
872 | ** should have been (the result of a previous "get table"). | 1025 | ** should have been (the result of a previous "get table"). |
873 | ** Beware: when using this function you probably need to check a GC | 1026 | ** Beware: when using this function you probably need to check a GC |
874 | ** barrier and invalidate the TM cache. | 1027 | ** barrier and invalidate the TM cache. |
875 | */ | 1028 | */ |
1029 | |||
1030 | |||
876 | void luaH_finishset (lua_State *L, Table *t, const TValue *key, | 1031 | void luaH_finishset (lua_State *L, Table *t, const TValue *key, |
877 | const TValue *slot, TValue *value) { | 1032 | TValue *value, int hres) { |
878 | if (isabstkey(slot)) | 1033 | lua_assert(hres != HOK); |
1034 | if (hres == HNOTFOUND) { | ||
879 | luaH_newkey(L, t, key, value); | 1035 | luaH_newkey(L, t, key, value); |
880 | else | 1036 | } |
881 | setobj2t(L, cast(TValue *, slot), value); | 1037 | else if (hres > 0) { /* regular Node? */ |
1038 | setobj2t(L, gval(gnode(t, hres - HFIRSTNODE)), value); | ||
1039 | } | ||
1040 | else { /* array entry */ | ||
1041 | hres = ~hres; /* real index */ | ||
1042 | obj2arr(t, hres, value); | ||
1043 | } | ||
882 | } | 1044 | } |
883 | 1045 | ||
884 | 1046 | ||
@@ -887,20 +1049,19 @@ void luaH_finishset (lua_State *L, Table *t, const TValue *key, | |||
887 | ** barrier and invalidate the TM cache. | 1049 | ** barrier and invalidate the TM cache. |
888 | */ | 1050 | */ |
889 | void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) { | 1051 | void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) { |
890 | const TValue *slot = luaH_get(t, key); | 1052 | int hres = luaH_pset(t, key, value); |
891 | luaH_finishset(L, t, key, slot, value); | 1053 | if (hres != HOK) |
1054 | luaH_finishset(L, t, key, value, hres); | ||
892 | } | 1055 | } |
893 | 1056 | ||
894 | 1057 | ||
895 | void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { | 1058 | void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { |
896 | const TValue *p = luaH_getint(t, key); | 1059 | int hres = luaH_psetint(t, key, value); |
897 | if (isabstkey(p)) { | 1060 | if (hres != HOK) { |
898 | TValue k; | 1061 | TValue k; |
899 | setivalue(&k, key); | 1062 | setivalue(&k, key); |
900 | luaH_newkey(L, t, &k, value); | 1063 | luaH_finishset(L, t, &k, value, hres); |
901 | } | 1064 | } |
902 | else | ||
903 | setobj2t(L, cast(TValue *, p), value); | ||
904 | } | 1065 | } |
905 | 1066 | ||
906 | 1067 | ||
@@ -926,27 +1087,26 @@ static lua_Unsigned hash_search (Table *t, lua_Unsigned j) { | |||
926 | j *= 2; | 1087 | j *= 2; |
927 | else { | 1088 | else { |
928 | j = LUA_MAXINTEGER; | 1089 | j = LUA_MAXINTEGER; |
929 | if (isempty(luaH_getint(t, j))) /* t[j] not present? */ | 1090 | if (hashkeyisempty(t, j)) /* t[j] not present? */ |
930 | break; /* 'j' now is an absent index */ | 1091 | break; /* 'j' now is an absent index */ |
931 | else /* weird case */ | 1092 | else /* weird case */ |
932 | return j; /* well, max integer is a boundary... */ | 1093 | return j; /* well, max integer is a boundary... */ |
933 | } | 1094 | } |
934 | } while (!isempty(luaH_getint(t, j))); /* repeat until an absent t[j] */ | 1095 | } while (!hashkeyisempty(t, j)); /* repeat until an absent t[j] */ |
935 | /* i < j && t[i] present && t[j] absent */ | 1096 | /* i < j && t[i] present && t[j] absent */ |
936 | while (j - i > 1u) { /* do a binary search between them */ | 1097 | while (j - i > 1u) { /* do a binary search between them */ |
937 | lua_Unsigned m = (i + j) / 2; | 1098 | lua_Unsigned m = (i + j) / 2; |
938 | if (isempty(luaH_getint(t, m))) j = m; | 1099 | if (hashkeyisempty(t, m)) j = m; |
939 | else i = m; | 1100 | else i = m; |
940 | } | 1101 | } |
941 | return i; | 1102 | return i; |
942 | } | 1103 | } |
943 | 1104 | ||
944 | 1105 | ||
945 | static unsigned int binsearch (const TValue *array, unsigned int i, | 1106 | static unsigned int binsearch (Table *array, unsigned int i, unsigned int j) { |
946 | unsigned int j) { | ||
947 | while (j - i > 1u) { /* binary search */ | 1107 | while (j - i > 1u) { /* binary search */ |
948 | unsigned int m = (i + j) / 2; | 1108 | unsigned int m = (i + j) / 2; |
949 | if (isempty(&array[m - 1])) j = m; | 1109 | if (arraykeyisempty(array, m)) j = m; |
950 | else i = m; | 1110 | else i = m; |
951 | } | 1111 | } |
952 | return i; | 1112 | return i; |
@@ -987,9 +1147,9 @@ static unsigned int binsearch (const TValue *array, unsigned int i, | |||
987 | */ | 1147 | */ |
988 | lua_Unsigned luaH_getn (Table *t) { | 1148 | lua_Unsigned luaH_getn (Table *t) { |
989 | unsigned int limit = t->alimit; | 1149 | unsigned int limit = t->alimit; |
990 | if (limit > 0 && isempty(&t->array[limit - 1])) { /* (1)? */ | 1150 | if (limit > 0 && arraykeyisempty(t, limit)) { /* (1)? */ |
991 | /* there must be a boundary before 'limit' */ | 1151 | /* there must be a boundary before 'limit' */ |
992 | if (limit >= 2 && !isempty(&t->array[limit - 2])) { | 1152 | if (limit >= 2 && !arraykeyisempty(t, limit - 1)) { |
993 | /* 'limit - 1' is a boundary; can it be a new limit? */ | 1153 | /* 'limit - 1' is a boundary; can it be a new limit? */ |
994 | if (ispow2realasize(t) && !ispow2(limit - 1)) { | 1154 | if (ispow2realasize(t) && !ispow2(limit - 1)) { |
995 | t->alimit = limit - 1; | 1155 | t->alimit = limit - 1; |
@@ -998,7 +1158,7 @@ lua_Unsigned luaH_getn (Table *t) { | |||
998 | return limit - 1; | 1158 | return limit - 1; |
999 | } | 1159 | } |
1000 | else { /* must search for a boundary in [0, limit] */ | 1160 | else { /* must search for a boundary in [0, limit] */ |
1001 | unsigned int boundary = binsearch(t->array, 0, limit); | 1161 | unsigned int boundary = binsearch(t, 0, limit); |
1002 | /* can this boundary represent the real size of the array? */ | 1162 | /* can this boundary represent the real size of the array? */ |
1003 | if (ispow2realasize(t) && boundary > luaH_realasize(t) / 2) { | 1163 | if (ispow2realasize(t) && boundary > luaH_realasize(t) / 2) { |
1004 | t->alimit = boundary; /* use it as the new limit */ | 1164 | t->alimit = boundary; /* use it as the new limit */ |
@@ -1010,14 +1170,14 @@ lua_Unsigned luaH_getn (Table *t) { | |||
1010 | /* 'limit' is zero or present in table */ | 1170 | /* 'limit' is zero or present in table */ |
1011 | if (!limitequalsasize(t)) { /* (2)? */ | 1171 | if (!limitequalsasize(t)) { /* (2)? */ |
1012 | /* 'limit' > 0 and array has more elements after 'limit' */ | 1172 | /* 'limit' > 0 and array has more elements after 'limit' */ |
1013 | if (isempty(&t->array[limit])) /* 'limit + 1' is empty? */ | 1173 | if (arraykeyisempty(t, limit + 1)) /* 'limit + 1' is empty? */ |
1014 | return limit; /* this is the boundary */ | 1174 | return limit; /* this is the boundary */ |
1015 | /* else, try last element in the array */ | 1175 | /* else, try last element in the array */ |
1016 | limit = luaH_realasize(t); | 1176 | limit = luaH_realasize(t); |
1017 | if (isempty(&t->array[limit - 1])) { /* empty? */ | 1177 | if (arraykeyisempty(t, limit)) { /* empty? */ |
1018 | /* there must be a boundary in the array after old limit, | 1178 | /* there must be a boundary in the array after old limit, |
1019 | and it must be a valid new limit */ | 1179 | and it must be a valid new limit */ |
1020 | unsigned int boundary = binsearch(t->array, t->alimit, limit); | 1180 | unsigned int boundary = binsearch(t, t->alimit, limit); |
1021 | t->alimit = boundary; | 1181 | t->alimit = boundary; |
1022 | return boundary; | 1182 | return boundary; |
1023 | } | 1183 | } |
@@ -1025,8 +1185,8 @@ lua_Unsigned luaH_getn (Table *t) { | |||
1025 | } | 1185 | } |
1026 | /* (3) 'limit' is the last element and either is zero or present in table */ | 1186 | /* (3) 'limit' is the last element and either is zero or present in table */ |
1027 | lua_assert(limit == luaH_realasize(t) && | 1187 | lua_assert(limit == luaH_realasize(t) && |
1028 | (limit == 0 || !isempty(&t->array[limit - 1]))); | 1188 | (limit == 0 || !arraykeyisempty(t, limit))); |
1029 | if (isdummy(t) || isempty(luaH_getint(t, cast(lua_Integer, limit + 1)))) | 1189 | if (isdummy(t) || hashkeyisempty(t, cast(lua_Integer, limit + 1))) |
1030 | return limit; /* 'limit + 1' is absent */ | 1190 | return limit; /* 'limit + 1' is absent */ |
1031 | else /* 'limit + 1' is also present */ | 1191 | else /* 'limit + 1' is also present */ |
1032 | return hash_search(t, limit); | 1192 | return hash_search(t, limit); |
@@ -45,16 +45,105 @@ | |||
45 | #define nodefromval(v) cast(Node *, (v)) | 45 | #define nodefromval(v) cast(Node *, (v)) |
46 | 46 | ||
47 | 47 | ||
48 | LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); | 48 | /* results from get/pset */ |
49 | #define HOK 0 | ||
50 | #define HNOTFOUND 1 | ||
51 | #define HNOTATABLE 2 | ||
52 | #define HFIRSTNODE 3 | ||
53 | |||
54 | /* | ||
55 | ** Besides these values, pset (pre-set) operations may also return an | ||
56 | ** encoding of where the value should go (usually called 'hres'). That | ||
57 | ** means that there is a slot with that key but with no value. (pset | ||
58 | ** cannot set that value because there might be a metamethod.) If the | ||
59 | ** slot is in the hash part, the encoding is (HFIRSTNODE + hash index); | ||
60 | ** if the slot is in the array part, the encoding is (~array index). | ||
61 | */ | ||
62 | |||
63 | |||
64 | /* | ||
65 | ** The array part of a table is represented by an array of cells. | ||
66 | ** Each cell is composed of (NM + 1) elements, and each element has the | ||
67 | ** type 'ArrayCell'. In each cell, only one element has the variant | ||
68 | ** 'tag', while the other NM elements have the variant 'value'. The | ||
69 | ** array in the 'tag' element holds the tags of the other elements in | ||
70 | ** that cell. | ||
71 | */ | ||
72 | #define NM ((unsigned int)sizeof(Value)) | ||
73 | |||
74 | union ArrayCell { | ||
75 | unsigned char tag[NM]; | ||
76 | Value value; | ||
77 | }; | ||
78 | |||
79 | |||
80 | /* | ||
81 | ** 'NMTag' defines which cell element has the tags; that could be any | ||
82 | ** value between 0 (tags come before all values) and NM (tags come after | ||
83 | ** all values). | ||
84 | */ | ||
85 | #define NMTag 0 | ||
86 | |||
87 | |||
88 | /* | ||
89 | ** Computes the concrete index that holds the tag of abstract index 'i' | ||
90 | */ | ||
91 | #define TagIndex(i) (((i)/NM * (NM + 1u)) + NMTag) | ||
92 | |||
93 | /* | ||
94 | ** Computes the concrete index that holds the value of abstract index 'i' | ||
95 | */ | ||
96 | #define ValueIndex(i) ((i) + (((i) + (NM - NMTag))/NM)) | ||
97 | |||
98 | |||
99 | /* Computes the address of the tag for the abstract index 'k' */ | ||
100 | #define getArrTag(t,k) (&(t)->array[TagIndex(k)].tag[(k)%NM]) | ||
101 | |||
102 | /* Computes the address of the value for the abstract index 'k' */ | ||
103 | #define getArrVal(t,k) (&(t)->array[ValueIndex(k)].value) | ||
104 | |||
105 | |||
106 | /* | ||
107 | ** Move TValues to/from arrays, using Lua indices | ||
108 | */ | ||
109 | #define arr2obj(h,k,val) \ | ||
110 | ((val)->tt_ = *getArrTag(h,(k)-1u), (val)->value_ = *getArrVal(h,(k)-1u)) | ||
111 | |||
112 | #define obj2arr(h,k,val) \ | ||
113 | (*getArrTag(h,(k)-1u) = (val)->tt_, *getArrVal(h,(k)-1u) = (val)->value_) | ||
114 | |||
115 | |||
116 | /* | ||
117 | ** Often, we need to check the tag of a value before moving it. These | ||
118 | ** macros also move TValues to/from arrays, but receive the precomputed | ||
119 | ** tag value or address as an extra argument. | ||
120 | */ | ||
121 | #define farr2val(h,k,tag,res) \ | ||
122 | ((res)->tt_ = tag, (res)->value_ = *getArrVal(h,(k)-1u)) | ||
123 | |||
124 | #define fval2arr(h,k,tag,val) \ | ||
125 | (*tag = (val)->tt_, *getArrVal(h,(k)-1u) = (val)->value_) | ||
126 | |||
127 | |||
128 | LUAI_FUNC int luaH_getshortstr (Table *t, TString *key, TValue *res); | ||
129 | LUAI_FUNC int luaH_getstr (Table *t, TString *key, TValue *res); | ||
130 | LUAI_FUNC int luaH_get (Table *t, const TValue *key, TValue *res); | ||
131 | LUAI_FUNC int luaH_getint (Table *t, lua_Integer key, TValue *res); | ||
132 | |||
133 | LUAI_FUNC TString *luaH_getstrkey (Table *t, TString *key); | ||
134 | |||
135 | LUAI_FUNC int luaH_psetint (Table *t, lua_Integer key, TValue *val); | ||
136 | LUAI_FUNC int luaH_psetshortstr (Table *t, TString *key, TValue *val); | ||
137 | LUAI_FUNC int luaH_psetstr (Table *t, TString *key, TValue *val); | ||
138 | LUAI_FUNC int luaH_pset (Table *t, const TValue *key, TValue *val); | ||
139 | |||
49 | LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, | 140 | LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, |
50 | TValue *value); | 141 | TValue *value); |
51 | LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); | 142 | LUAI_FUNC const TValue *luaH_Hgetshortstr (Table *t, TString *key); |
52 | LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); | ||
53 | LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); | ||
54 | LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key, | 143 | LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key, |
55 | TValue *value); | 144 | TValue *value); |
56 | LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key, | 145 | LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key, |
57 | const TValue *slot, TValue *value); | 146 | TValue *value, int aux); |
58 | LUAI_FUNC Table *luaH_new (lua_State *L); | 147 | LUAI_FUNC Table *luaH_new (lua_State *L); |
59 | LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, | 148 | LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, |
60 | unsigned int nhsize); | 149 | 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; |
@@ -1004,7 +1007,8 @@ static int table_query (lua_State *L) { | |||
1004 | } | 1007 | } |
1005 | else if ((unsigned int)i < asize) { | 1008 | else if ((unsigned int)i < asize) { |
1006 | lua_pushinteger(L, i); | 1009 | lua_pushinteger(L, i); |
1007 | pushobject(L, &t->array[i]); | 1010 | arr2obj(t, i + 1, s2v(L->top.p)); |
1011 | api_incr_top(L); | ||
1008 | lua_pushnil(L); | 1012 | lua_pushnil(L); |
1009 | } | 1013 | } |
1010 | else if ((i -= asize) < sizenode(t)) { | 1014 | 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 | } |
@@ -286,15 +286,13 @@ static int floatforloop (StkId ra) { | |||
286 | 286 | ||
287 | /* | 287 | /* |
288 | ** Finish the table access 'val = t[key]'. | 288 | ** Finish the table access 'val = t[key]'. |
289 | ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to | ||
290 | ** t[k] entry (which must be empty). | ||
291 | */ | 289 | */ |
292 | void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | 290 | void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, |
293 | const TValue *slot) { | 291 | int hres) { |
294 | int loop; /* counter to avoid infinite loops */ | 292 | int loop; /* counter to avoid infinite loops */ |
295 | const TValue *tm; /* metamethod */ | 293 | const TValue *tm; /* metamethod */ |
296 | for (loop = 0; loop < MAXTAGLOOP; loop++) { | 294 | for (loop = 0; loop < MAXTAGLOOP; loop++) { |
297 | if (slot == NULL) { /* 't' is not a table? */ | 295 | if (hres == HNOTATABLE) { /* 't' is not a table? */ |
298 | lua_assert(!ttistable(t)); | 296 | lua_assert(!ttistable(t)); |
299 | tm = luaT_gettmbyobj(L, t, TM_INDEX); | 297 | tm = luaT_gettmbyobj(L, t, TM_INDEX); |
300 | if (l_unlikely(notm(tm))) | 298 | if (l_unlikely(notm(tm))) |
@@ -302,7 +300,6 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | |||
302 | /* else will try the metamethod */ | 300 | /* else will try the metamethod */ |
303 | } | 301 | } |
304 | else { /* 't' is a table */ | 302 | else { /* 't' is a table */ |
305 | lua_assert(isempty(slot)); | ||
306 | tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ | 303 | tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ |
307 | if (tm == NULL) { /* no metamethod? */ | 304 | if (tm == NULL) { /* no metamethod? */ |
308 | setnilvalue(s2v(val)); /* result is nil */ | 305 | setnilvalue(s2v(val)); /* result is nil */ |
@@ -315,10 +312,9 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | |||
315 | return; | 312 | return; |
316 | } | 313 | } |
317 | t = tm; /* else try to access 'tm[key]' */ | 314 | t = tm; /* else try to access 'tm[key]' */ |
318 | if (luaV_fastget(L, t, key, slot, luaH_get)) { /* fast track? */ | 315 | luaV_fastget(t, key, s2v(val), luaH_get, hres); |
319 | setobj2s(L, val, slot); /* done */ | 316 | if (hres == HOK) |
320 | return; | 317 | return; /* done */ |
321 | } | ||
322 | /* else repeat (tail call 'luaV_finishget') */ | 318 | /* else repeat (tail call 'luaV_finishget') */ |
323 | } | 319 | } |
324 | luaG_runerror(L, "'__index' chain too long; possible loop"); | 320 | luaG_runerror(L, "'__index' chain too long; possible loop"); |
@@ -327,22 +323,17 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | |||
327 | 323 | ||
328 | /* | 324 | /* |
329 | ** Finish a table assignment 't[key] = val'. | 325 | ** Finish a table assignment 't[key] = val'. |
330 | ** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points | ||
331 | ** to the entry 't[key]', or to a value with an absent key if there | ||
332 | ** is no such entry. (The value at 'slot' must be empty, otherwise | ||
333 | ** 'luaV_fastget' would have done the job.) | ||
334 | */ | 326 | */ |
335 | void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | 327 | void luaV_finishset (lua_State *L, const TValue *t, TValue *key, |
336 | TValue *val, const TValue *slot) { | 328 | TValue *val, int hres) { |
337 | int loop; /* counter to avoid infinite loops */ | 329 | int loop; /* counter to avoid infinite loops */ |
338 | for (loop = 0; loop < MAXTAGLOOP; loop++) { | 330 | for (loop = 0; loop < MAXTAGLOOP; loop++) { |
339 | const TValue *tm; /* '__newindex' metamethod */ | 331 | const TValue *tm; /* '__newindex' metamethod */ |
340 | if (slot != NULL) { /* is 't' a table? */ | 332 | if (hres != HNOTATABLE) { /* is 't' a table? */ |
341 | Table *h = hvalue(t); /* save 't' table */ | 333 | Table *h = hvalue(t); /* save 't' table */ |
342 | lua_assert(isempty(slot)); /* slot must be empty */ | ||
343 | tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ | 334 | tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ |
344 | if (tm == NULL) { /* no metamethod? */ | 335 | if (tm == NULL) { /* no metamethod? */ |
345 | luaH_finishset(L, h, key, slot, val); /* set new value */ | 336 | luaH_finishset(L, h, key, val, hres); /* set new value */ |
346 | invalidateTMcache(h); | 337 | invalidateTMcache(h); |
347 | luaC_barrierback(L, obj2gco(h), val); | 338 | luaC_barrierback(L, obj2gco(h), val); |
348 | return; | 339 | return; |
@@ -360,10 +351,9 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | |||
360 | return; | 351 | return; |
361 | } | 352 | } |
362 | t = tm; /* else repeat assignment over 'tm' */ | 353 | t = tm; /* else repeat assignment over 'tm' */ |
363 | if (luaV_fastget(L, t, key, slot, luaH_get)) { | 354 | luaV_fastset(t, key, val, hres, luaH_pset); |
364 | luaV_finishfastset(L, t, slot, val); | 355 | if (hres == HOK) |
365 | return; /* done */ | 356 | return; /* done */ |
366 | } | ||
367 | /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ | 357 | /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ |
368 | } | 358 | } |
369 | luaG_runerror(L, "'__newindex' chain too long; possible loop"); | 359 | luaG_runerror(L, "'__newindex' chain too long; possible loop"); |
@@ -1252,114 +1242,109 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1252 | } | 1242 | } |
1253 | vmcase(OP_GETTABUP) { | 1243 | vmcase(OP_GETTABUP) { |
1254 | StkId ra = RA(i); | 1244 | StkId ra = RA(i); |
1255 | const TValue *slot; | ||
1256 | TValue *upval = cl->upvals[GETARG_B(i)]->v.p; | 1245 | TValue *upval = cl->upvals[GETARG_B(i)]->v.p; |
1257 | TValue *rc = KC(i); | 1246 | TValue *rc = KC(i); |
1258 | TString *key = tsvalue(rc); /* key must be a short string */ | 1247 | TString *key = tsvalue(rc); /* key must be a short string */ |
1259 | if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { | 1248 | int hres; |
1260 | setobj2s(L, ra, slot); | 1249 | luaV_fastget(upval, key, s2v(ra), luaH_getshortstr, hres); |
1261 | } | 1250 | if (hres != HOK) |
1262 | else | 1251 | Protect(luaV_finishget(L, upval, rc, ra, hres)); |
1263 | Protect(luaV_finishget(L, upval, rc, ra, slot)); | ||
1264 | vmbreak; | 1252 | vmbreak; |
1265 | } | 1253 | } |
1266 | vmcase(OP_GETTABLE) { | 1254 | vmcase(OP_GETTABLE) { |
1267 | StkId ra = RA(i); | 1255 | StkId ra = RA(i); |
1268 | const TValue *slot; | ||
1269 | TValue *rb = vRB(i); | 1256 | TValue *rb = vRB(i); |
1270 | TValue *rc = vRC(i); | 1257 | TValue *rc = vRC(i); |
1271 | lua_Unsigned n; | 1258 | int hres; |
1272 | if (ttisinteger(rc) /* fast track for integers? */ | 1259 | if (ttisinteger(rc)) { /* fast track for integers? */ |
1273 | ? (cast_void(n = ivalue(rc)), luaV_fastgeti(L, rb, n, slot)) | 1260 | luaV_fastgeti(rb, ivalue(rc), s2v(ra), hres); |
1274 | : luaV_fastget(L, rb, rc, slot, luaH_get)) { | ||
1275 | setobj2s(L, ra, slot); | ||
1276 | } | 1261 | } |
1277 | else | 1262 | else |
1278 | Protect(luaV_finishget(L, rb, rc, ra, slot)); | 1263 | luaV_fastget(rb, rc, s2v(ra), luaH_get, hres); |
1264 | if (hres != HOK) /* fast track for integers? */ | ||
1265 | Protect(luaV_finishget(L, rb, rc, ra, hres)); | ||
1279 | vmbreak; | 1266 | vmbreak; |
1280 | } | 1267 | } |
1281 | vmcase(OP_GETI) { | 1268 | vmcase(OP_GETI) { |
1282 | StkId ra = RA(i); | 1269 | StkId ra = RA(i); |
1283 | const TValue *slot; | ||
1284 | TValue *rb = vRB(i); | 1270 | TValue *rb = vRB(i); |
1285 | int c = GETARG_C(i); | 1271 | int c = GETARG_C(i); |
1286 | if (luaV_fastgeti(L, rb, c, slot)) { | 1272 | int hres; |
1287 | setobj2s(L, ra, slot); | 1273 | luaV_fastgeti(rb, c, s2v(ra), hres); |
1288 | } | 1274 | if (hres != HOK) { |
1289 | else { | ||
1290 | TValue key; | 1275 | TValue key; |
1291 | setivalue(&key, c); | 1276 | setivalue(&key, c); |
1292 | Protect(luaV_finishget(L, rb, &key, ra, slot)); | 1277 | Protect(luaV_finishget(L, rb, &key, ra, hres)); |
1293 | } | 1278 | } |
1294 | vmbreak; | 1279 | vmbreak; |
1295 | } | 1280 | } |
1296 | vmcase(OP_GETFIELD) { | 1281 | vmcase(OP_GETFIELD) { |
1297 | StkId ra = RA(i); | 1282 | StkId ra = RA(i); |
1298 | const TValue *slot; | ||
1299 | TValue *rb = vRB(i); | 1283 | TValue *rb = vRB(i); |
1300 | TValue *rc = KC(i); | 1284 | TValue *rc = KC(i); |
1301 | TString *key = tsvalue(rc); /* key must be a short string */ | 1285 | TString *key = tsvalue(rc); /* key must be a short string */ |
1302 | if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) { | 1286 | int hres; |
1303 | setobj2s(L, ra, slot); | 1287 | luaV_fastget(rb, key, s2v(ra), luaH_getshortstr, hres); |
1304 | } | 1288 | if (hres != HOK) |
1305 | else | 1289 | Protect(luaV_finishget(L, rb, rc, ra, hres)); |
1306 | Protect(luaV_finishget(L, rb, rc, ra, slot)); | ||
1307 | vmbreak; | 1290 | vmbreak; |
1308 | } | 1291 | } |
1309 | vmcase(OP_SETTABUP) { | 1292 | vmcase(OP_SETTABUP) { |
1310 | const TValue *slot; | 1293 | int hres; |
1311 | TValue *upval = cl->upvals[GETARG_A(i)]->v.p; | 1294 | TValue *upval = cl->upvals[GETARG_A(i)]->v.p; |
1312 | TValue *rb = KB(i); | 1295 | TValue *rb = KB(i); |
1313 | TValue *rc = RKC(i); | 1296 | TValue *rc = RKC(i); |
1314 | TString *key = tsvalue(rb); /* key must be a short string */ | 1297 | TString *key = tsvalue(rb); /* key must be a short string */ |
1315 | if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { | 1298 | luaV_fastset(upval, key, rc, hres, luaH_psetshortstr); |
1316 | luaV_finishfastset(L, upval, slot, rc); | 1299 | if (hres == HOK) |
1317 | } | 1300 | luaV_finishfastset(L, upval, rc); |
1318 | else | 1301 | else |
1319 | Protect(luaV_finishset(L, upval, rb, rc, slot)); | 1302 | Protect(luaV_finishset(L, upval, rb, rc, hres)); |
1320 | vmbreak; | 1303 | vmbreak; |
1321 | } | 1304 | } |
1322 | vmcase(OP_SETTABLE) { | 1305 | vmcase(OP_SETTABLE) { |
1323 | StkId ra = RA(i); | 1306 | StkId ra = RA(i); |
1324 | const TValue *slot; | 1307 | int hres; |
1325 | TValue *rb = vRB(i); /* key (table is in 'ra') */ | 1308 | TValue *rb = vRB(i); /* key (table is in 'ra') */ |
1326 | TValue *rc = RKC(i); /* value */ | 1309 | TValue *rc = RKC(i); /* value */ |
1327 | lua_Unsigned n; | 1310 | if (ttisinteger(rb)) { /* fast track for integers? */ |
1328 | if (ttisinteger(rb) /* fast track for integers? */ | 1311 | luaV_fastseti(s2v(ra), ivalue(rb), rc, hres); |
1329 | ? (cast_void(n = ivalue(rb)), luaV_fastgeti(L, s2v(ra), n, slot)) | 1312 | } |
1330 | : luaV_fastget(L, s2v(ra), rb, slot, luaH_get)) { | 1313 | else { |
1331 | luaV_finishfastset(L, s2v(ra), slot, rc); | 1314 | luaV_fastset(s2v(ra), rb, rc, hres, luaH_pset); |
1332 | } | 1315 | } |
1316 | if (hres == HOK) | ||
1317 | luaV_finishfastset(L, s2v(ra), rc); | ||
1333 | else | 1318 | else |
1334 | Protect(luaV_finishset(L, s2v(ra), rb, rc, slot)); | 1319 | Protect(luaV_finishset(L, s2v(ra), rb, rc, hres)); |
1335 | vmbreak; | 1320 | vmbreak; |
1336 | } | 1321 | } |
1337 | vmcase(OP_SETI) { | 1322 | vmcase(OP_SETI) { |
1338 | StkId ra = RA(i); | 1323 | StkId ra = RA(i); |
1339 | const TValue *slot; | 1324 | int hres; |
1340 | int c = GETARG_B(i); | 1325 | int b = GETARG_B(i); |
1341 | TValue *rc = RKC(i); | 1326 | TValue *rc = RKC(i); |
1342 | if (luaV_fastgeti(L, s2v(ra), c, slot)) { | 1327 | luaV_fastseti(s2v(ra), b, rc, hres); |
1343 | luaV_finishfastset(L, s2v(ra), slot, rc); | 1328 | if (hres == HOK) |
1344 | } | 1329 | luaV_finishfastset(L, s2v(ra), rc); |
1345 | else { | 1330 | else { |
1346 | TValue key; | 1331 | TValue key; |
1347 | setivalue(&key, c); | 1332 | setivalue(&key, b); |
1348 | Protect(luaV_finishset(L, s2v(ra), &key, rc, slot)); | 1333 | Protect(luaV_finishset(L, s2v(ra), &key, rc, hres)); |
1349 | } | 1334 | } |
1350 | vmbreak; | 1335 | vmbreak; |
1351 | } | 1336 | } |
1352 | vmcase(OP_SETFIELD) { | 1337 | vmcase(OP_SETFIELD) { |
1353 | StkId ra = RA(i); | 1338 | StkId ra = RA(i); |
1354 | const TValue *slot; | 1339 | int hres; |
1355 | TValue *rb = KB(i); | 1340 | TValue *rb = KB(i); |
1356 | TValue *rc = RKC(i); | 1341 | TValue *rc = RKC(i); |
1357 | TString *key = tsvalue(rb); /* key must be a short string */ | 1342 | TString *key = tsvalue(rb); /* key must be a short string */ |
1358 | if (luaV_fastget(L, s2v(ra), key, slot, luaH_getshortstr)) { | 1343 | luaV_fastset(s2v(ra), key, rc, hres, luaH_psetshortstr); |
1359 | luaV_finishfastset(L, s2v(ra), slot, rc); | 1344 | if (hres == HOK) |
1360 | } | 1345 | luaV_finishfastset(L, s2v(ra), rc); |
1361 | else | 1346 | else |
1362 | Protect(luaV_finishset(L, s2v(ra), rb, rc, slot)); | 1347 | Protect(luaV_finishset(L, s2v(ra), rb, rc, hres)); |
1363 | vmbreak; | 1348 | vmbreak; |
1364 | } | 1349 | } |
1365 | vmcase(OP_NEWTABLE) { | 1350 | vmcase(OP_NEWTABLE) { |
@@ -1383,16 +1368,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1383 | } | 1368 | } |
1384 | vmcase(OP_SELF) { | 1369 | vmcase(OP_SELF) { |
1385 | StkId ra = RA(i); | 1370 | StkId ra = RA(i); |
1386 | const TValue *slot; | 1371 | int hres; |
1387 | TValue *rb = vRB(i); | 1372 | TValue *rb = vRB(i); |
1388 | TValue *rc = RKC(i); | 1373 | TValue *rc = RKC(i); |
1389 | TString *key = tsvalue(rc); /* key must be a string */ | 1374 | TString *key = tsvalue(rc); /* key must be a string */ |
1390 | setobj2s(L, ra + 1, rb); | 1375 | setobj2s(L, ra + 1, rb); |
1391 | if (luaV_fastget(L, rb, key, slot, luaH_getstr)) { | 1376 | luaV_fastget(rb, key, s2v(ra), luaH_getstr, hres); |
1392 | setobj2s(L, ra, slot); | 1377 | if (hres != HOK) |
1393 | } | 1378 | Protect(luaV_finishget(L, rb, rc, ra, hres)); |
1394 | else | ||
1395 | Protect(luaV_finishget(L, rb, rc, ra, slot)); | ||
1396 | vmbreak; | 1379 | vmbreak; |
1397 | } | 1380 | } |
1398 | vmcase(OP_ADDI) { | 1381 | vmcase(OP_ADDI) { |
@@ -1873,7 +1856,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1873 | luaH_resizearray(L, h, last); /* preallocate it at once */ | 1856 | luaH_resizearray(L, h, last); /* preallocate it at once */ |
1874 | for (; n > 0; n--) { | 1857 | for (; n > 0; n--) { |
1875 | TValue *val = s2v(ra + n); | 1858 | TValue *val = s2v(ra + n); |
1876 | setobj2t(L, &h->array[last - 1], val); | 1859 | obj2arr(h, last, val); |
1877 | last--; | 1860 | last--; |
1878 | luaC_barrierback(L, obj2gco(h), val); | 1861 | luaC_barrierback(L, obj2gco(h), val); |
1879 | } | 1862 | } |
@@ -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); |