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 | 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); |
