| @@ -1,5 +1,5 @@ |
| 1 | 1 | /* |
| 2 | | −** $Id: lgc.c,v 2.129 2012/05/28 20:41:00 roberto Exp $ |
| 2 | +** $Id: lgc.c,v 2.133 2012/05/31 21:28:59 roberto Exp $ |
| 3 | 3 | ** Garbage Collector |
| 4 | 4 | ** See Copyright Notice in lua.h |
| 5 | 5 | */ |
| @@ -753,6 +753,21 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { · 747 unmodified lines |
| 753 | 753 | return (*p == NULL) ? NULL : p; |
| 754 | 754 | } |
| 755 | 755 | |
| 756 | + |
| 757 | +/* |
| 758 | +** sweep a list until a live object (or end of list) |
| 759 | +*/ |
| 760 | +static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { |
| 761 | + GCObject ** old = p; |
| 762 | + int i = 0; |
| 763 | + do { |
| 764 | + i++; |
| 765 | + p = sweeplist(L, p, 1); |
| 766 | + } while (p == old); |
| 767 | + if (n) *n += i; |
| 768 | + return p; |
| 769 | +} |
| 770 | + |
| 756 | 771 | /* }====================================================== */ |
| 757 | 772 | |
| 758 | 773 | |
| @@ -812,12 +827,14 @@ static void GCTM (lua_State *L, int propagateerrors) { · 53 unmodified lines |
| 812 | 827 | L->allowhook = oldah; /* restore hooks */ |
| 813 | 828 | g->gcrunning = running; /* restore state */ |
| 814 | 829 | if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ |
| 815 | | − if (status == LUA_ERRRUN) { /* is there an error msg.? */ |
| 816 | | − luaO_pushfstring(L, "error in __gc metamethod (%s)", |
| 817 | | − lua_tostring(L, -1)); |
| 830 | + if (status == LUA_ERRRUN) { /* is there an error object? */ |
| 831 | + const char *msg = (ttisstring(L->top - 1)) |
| 832 | + ? svalue(L->top - 1) |
| 833 | + : "no message"; |
| 834 | + luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); |
| 818 | 835 | status = LUA_ERRGCMM; /* error in __gc metamethod */ |
| 819 | 836 | } |
| 820 | | − luaD_throw(L, status); /* re-send error */ |
| 837 | + luaD_throw(L, status); /* re-throw error */ |
| 821 | 838 | } |
| 822 | 839 | } |
| 823 | 840 | } |
| @@ -864,10 +881,9 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { · 40 unmodified lines |
| 864 | 881 | else { /* move 'o' to 'finobj' list */ |
| 865 | 882 | GCObject **p; |
| 866 | 883 | GCheader *ho = gch(o); |
| 867 | | − /* avoid removing current sweep object */ |
| 868 | | − if (g->sweepgc == &ho->next) { |
| 869 | | − /* step to next object in the list */ |
| 870 | | − g->sweepgc = (ho->next == NULL) ? NULL : &gch(ho->next)->next; |
| 884 | + if (g->sweepgc == &ho->next) { /* avoid removing current sweep object */ |
| 885 | + lua_assert(issweepphase(g)); |
| 886 | + g->sweepgc = sweeptolive(L, g->sweepgc, NULL); |
| 871 | 887 | } |
| 872 | 888 | /* search for pointer pointing to 'o' */ |
| 873 | 889 | for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ } |
| @@ -875,7 +891,10 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { · 1 unmodified line |
| 875 | 891 | ho->next = g->finobj; /* link it in list 'finobj' */ |
| 876 | 892 | g->finobj = o; |
| 877 | 893 | l_setbit(ho->marked, SEPARATED); /* mark it as such */ |
| 878 | | − resetoldbit(o); /* see MOVE OLD rule */ |
| 894 | + if (!keepinvariant(g)) /* not keeping invariant? */ |
| 895 | + makewhite(g, o); /* "sweep" object */ |
| 896 | + else |
| 897 | + resetoldbit(o); /* see MOVE OLD rule */ |
| 879 | 898 | } |
| 880 | 899 | } |
| 881 | 900 | |
| @@ -895,18 +914,22 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { · 13 unmodified lines |
| 895 | 914 | |
| 896 | 915 | /* |
| 897 | 916 | ** enter first sweep phase (strings) and prepare pointers for other |
| 898 | | −** sweep phases. The calls to 'sweeplist' attempt to make pointers |
| 899 | | −** point to an object inside the list (instead of to the header), so |
| 900 | | −** that the real sweep do not need to skip objects created between "now" |
| 901 | | −** and the start of the real sweep. |
| 917 | +** sweep phases. The calls to 'sweeptolive' make pointers point to an |
| 918 | +** object inside the list (instead of to the header), so that the real |
| 919 | +** sweep do not need to skip objects created between "now" and the start |
| 920 | +** of the real sweep. |
| 921 | +** Returns how many objects it sweeped. |
| 902 | 922 | */ |
| 903 | | −static void entersweep (lua_State *L) { |
| 923 | +static int entersweep (lua_State *L) { |
| 904 | 924 | global_State *g = G(L); |
| 925 | + int n = 0; |
| 905 | 926 | g->gcstate = GCSsweepstring; |
| 906 | 927 | lua_assert(g->sweepgc == NULL && g->sweepfin == NULL); |
| 907 | | − g->sweepstrgc = 0; /* prepare to sweep strings, ... */ |
| 908 | | − g->sweepfin = sweeplist(L, &g->finobj, 1); /* finalizable objects, ... */ |
| 909 | | − g->sweepgc = sweeplist(L, &g->allgc, 1); /* and regular objects */ |
| 928 | + /* prepare to sweep strings, finalizable objects, and regular objects */ |
| 929 | + g->sweepstrgc = 0; |
| 930 | + g->sweepfin = sweeptolive(L, &g->finobj, &n); |
| 931 | + g->sweepgc = sweeptolive(L, &g->allgc, &n); |
| 932 | + return n; |
| 910 | 933 | } |
| 911 | 934 | |
| 912 | 935 | |
| @@ -962,7 +985,7 @@ void luaC_freeallobjects (lua_State *L) { · 49 unmodified lines |
| 962 | 985 | |
| 963 | 986 | static l_mem atomic (lua_State *L) { |
| 964 | 987 | global_State *g = G(L); |
| 965 | | − l_mem trav = g->GCmemtrav; |
| 988 | + l_mem work = -g->GCmemtrav; /* start counting work */ |
| 966 | 989 | GCObject *origweak, *origall; |
| 967 | 990 | lua_assert(!iswhite(obj2gco(g->mainthread))); |
| 968 | 991 | markobject(g, L); /* mark running thread */ |
| @@ -971,18 +994,22 @@ static l_mem atomic (lua_State *L) { · 2 unmodified lines |
| 971 | 994 | markmt(g); /* mark basic metatables */ |
| 972 | 995 | /* remark occasional upvalues of (maybe) dead threads */ |
| 973 | 996 | remarkupvals(g); |
| 997 | + propagateall(g); /* propagate changes */ |
| 998 | + work += g->GCmemtrav; /* stop counting (do not (re)count grays) */ |
| 974 | 999 | /* traverse objects caught by write barrier and by 'remarkupvals' */ |
| 975 | 1000 | retraversegrays(g); |
| 1001 | + work -= g->GCmemtrav; /* restart counting */ |
| 976 | 1002 | convergeephemerons(g); |
| 977 | 1003 | /* at this point, all strongly accessible objects are marked. */ |
| 978 | 1004 | /* clear values from weak tables, before checking finalizers */ |
| 979 | 1005 | clearvalues(g, g->weak, NULL); |
| 980 | 1006 | clearvalues(g, g->allweak, NULL); |
| 981 | 1007 | origweak = g->weak; origall = g->allweak; |
| 1008 | + work += g->GCmemtrav; /* stop counting (objects being finalized) */ |
| 982 | 1009 | separatetobefnz(L, 0); /* separate objects to be finalized */ |
| 983 | | − markbeingfnz(g); /* mark userdata that will be finalized */ |
| 1010 | + markbeingfnz(g); /* mark objects that will be finalized */ |
| 984 | 1011 | propagateall(g); /* remark, to propagate `preserveness' */ |
| 985 | | − trav = g->GCmemtrav - trav; /* avoid adding convergence twice */ |
| 1012 | + work -= g->GCmemtrav; /* restart counting */ |
| 986 | 1013 | convergeephemerons(g); |
| 987 | 1014 | /* at this point, all resurrected objects are marked. */ |
| 988 | 1015 | /* remove dead objects from weak tables */ |
| @@ -992,9 +1019,8 @@ static l_mem atomic (lua_State *L) { · 3 unmodified lines |
| 992 | 1019 | clearvalues(g, g->weak, origweak); |
| 993 | 1020 | clearvalues(g, g->allweak, origall); |
| 994 | 1021 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ |
| 995 | | − entersweep(L); /* prepare to sweep strings */ |
| 996 | | − /*lua_checkmemory(L);*/ |
| 997 | | − return trav; /* reasonable estimate of the work done by 'atomic' */ |
| 1022 | + work += g->GCmemtrav; /* complete counting */ |
| 1023 | + return work; /* estimate of memory marked by 'atomic' */ |
| 998 | 1024 | } |
| 999 | 1025 | |
| 1000 | 1026 | |
| @@ -1018,9 +1044,14 @@ static lu_mem singlestep (lua_State *L) { · 17 unmodified lines |
| 1018 | 1044 | return g->GCmemtrav - oldtrav; /* memory traversed in this step */ |
| 1019 | 1045 | } |
| 1020 | 1046 | else { /* no more `gray' objects */ |
| 1047 | + lu_mem work; |
| 1048 | + int sw; |
| 1021 | 1049 | g->gcstate = GCSatomic; /* finish mark phase */ |
| 1022 | | − g->GCestimate = g->GCmemtrav; /* save what was counted */ |
| 1023 | | − return atomic(L); |
| 1050 | + g->GCestimate = g->GCmemtrav; /* save what was counted */; |
| 1051 | + work = atomic(L); /* add what was traversed by 'atomic' */ |
| 1052 | + g->GCestimate += work; /* estimate of total memory traversed */ |
| 1053 | + sw = entersweep(L); |
| 1054 | + return work + sw * GCSWEEPCOST; |
| 1024 | 1055 | } |
| 1025 | 1056 | } |
| 1026 | 1057 | case GCSsweepstring: { |
| @@ -1089,7 +1120,7 @@ static void generationalcollection (lua_State *L) { · 62 unmodified lines |
| 1089 | 1120 | } |
| 1090 | 1121 | |
| 1091 | 1122 | |
| 1092 | | −static void step (lua_State *L) { |
| 1123 | +static void incstep (lua_State *L) { |
| 1093 | 1124 | global_State *g = G(L); |
| 1094 | 1125 | l_mem debt = g->GCdebt; |
| 1095 | 1126 | int stepmul = g->gcstepmul; |
| @@ -1116,7 +1147,7 @@ void luaC_forcestep (lua_State *L) { · 20 unmodified lines |
| 1116 | 1147 | global_State *g = G(L); |
| 1117 | 1148 | int i; |
| 1118 | 1149 | if (isgenerational(g)) generationalcollection(L); |
| 1119 | | − else step(L); |
| 1150 | + else incstep(L); |
| 1120 | 1151 | /* run a few finalizers (or all of them at the end of a collect cycle) */ |
| 1121 | 1152 | for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++) |
| 1122 | 1153 | GCTM(L, 1); /* call one finalizer */ |