| @@ -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 | ** Garbage Collector | 3 | ** Garbage Collector |
| 4 | ** See Copyright Notice in lua.h | 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 | return (*p == NULL) ? NULL : p; | 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 | L->allowhook = oldah; /* restore hooks */ | 827 | L->allowhook = oldah; /* restore hooks */ |
| 813 | g->gcrunning = running; /* restore state */ | 828 | g->gcrunning = running; /* restore state */ |
| 814 | if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ | 829 | if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ |
| 815 | if (status == LUA_ERRRUN) { /* is there an error msg.? */ | 830 | if (status == LUA_ERRRUN) { /* is there an error object? */ |
| 816 | luaO_pushfstring(L, "error in __gc metamethod (%s)", | 831 | const char *msg = (ttisstring(L->top - 1)) |
| 817 | lua_tostring(L, -1)); | 832 | ? svalue(L->top - 1) |
| | 833 | : "no message"; |
| | 834 | luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); |
| 818 | status = LUA_ERRGCMM; /* error in __gc metamethod */ | 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 | else { /* move 'o' to 'finobj' list */ | 881 | else { /* move 'o' to 'finobj' list */ |
| 865 | GCObject **p; | 882 | GCObject **p; |
| 866 | GCheader *ho = gch(o); | 883 | GCheader *ho = gch(o); |
| 867 | /* avoid removing current sweep object */ | 884 | if (g->sweepgc == &ho->next) { /* avoid removing current sweep object */ |
| 868 | if (g->sweepgc == &ho->next) { | 885 | lua_assert(issweepphase(g)); |
| 869 | /* step to next object in the list */ | 886 | g->sweepgc = sweeptolive(L, g->sweepgc, NULL); |
| 870 | g->sweepgc = (ho->next == NULL) ? NULL : &gch(ho->next)->next; | | |
| 871 | } | 887 | } |
| 872 | /* search for pointer pointing to 'o' */ | 888 | /* search for pointer pointing to 'o' */ |
| 873 | for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ } | 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 | ho->next = g->finobj; /* link it in list 'finobj' */ | 891 | ho->next = g->finobj; /* link it in list 'finobj' */ |
| 876 | g->finobj = o; | 892 | g->finobj = o; |
| 877 | l_setbit(ho->marked, SEPARATED); /* mark it as such */ | 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 | ** enter first sweep phase (strings) and prepare pointers for other | 916 | ** enter first sweep phase (strings) and prepare pointers for other |
| 898 | ** sweep phases. The calls to 'sweeplist' attempt to make pointers | 917 | ** sweep phases. The calls to 'sweeptolive' make pointers point to an |
| 899 | ** point to an object inside the list (instead of to the header), so | 918 | ** object inside the list (instead of to the header), so that the real |
| 900 | ** that the real sweep do not need to skip objects created between "now" | 919 | ** sweep do not need to skip objects created between "now" and the start |
| 901 | ** and the start of the real sweep. | 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 | global_State *g = G(L); | 924 | global_State *g = G(L); |
| | 925 | int n = 0; |
| 905 | g->gcstate = GCSsweepstring; | 926 | g->gcstate = GCSsweepstring; |
| 906 | lua_assert(g->sweepgc == NULL && g->sweepfin == NULL); | 927 | lua_assert(g->sweepgc == NULL && g->sweepfin == NULL); |
| 907 | g->sweepstrgc = 0; /* prepare to sweep strings, ... */ | 928 | /* prepare to sweep strings, finalizable objects, and regular objects */ |
| 908 | g->sweepfin = sweeplist(L, &g->finobj, 1); /* finalizable objects, ... */ | 929 | g->sweepstrgc = 0; |
| 909 | g->sweepgc = sweeplist(L, &g->allgc, 1); /* and regular objects */ | 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 | static l_mem atomic (lua_State *L) { | 986 | static l_mem atomic (lua_State *L) { |
| 964 | global_State *g = G(L); | 987 | global_State *g = G(L); |
| 965 | l_mem trav = g->GCmemtrav; | 988 | l_mem work = -g->GCmemtrav; /* start counting work */ |
| 966 | GCObject *origweak, *origall; | 989 | GCObject *origweak, *origall; |
| 967 | lua_assert(!iswhite(obj2gco(g->mainthread))); | 990 | lua_assert(!iswhite(obj2gco(g->mainthread))); |
| 968 | markobject(g, L); /* mark running thread */ | 991 | markobject(g, L); /* mark running thread */ |
| @@ -971,18 +994,22 @@ static l_mem atomic (lua_State *L) { · 2 unmodified lines |
| 971 | markmt(g); /* mark basic metatables */ | 994 | markmt(g); /* mark basic metatables */ |
| 972 | /* remark occasional upvalues of (maybe) dead threads */ | 995 | /* remark occasional upvalues of (maybe) dead threads */ |
| 973 | remarkupvals(g); | 996 | remarkupvals(g); |
| | 997 | propagateall(g); /* propagate changes */ |
| | 998 | work += g->GCmemtrav; /* stop counting (do not (re)count grays) */ |
| 974 | /* traverse objects caught by write barrier and by 'remarkupvals' */ | 999 | /* traverse objects caught by write barrier and by 'remarkupvals' */ |
| 975 | retraversegrays(g); | 1000 | retraversegrays(g); |
| | 1001 | work -= g->GCmemtrav; /* restart counting */ |
| 976 | convergeephemerons(g); | 1002 | convergeephemerons(g); |
| 977 | /* at this point, all strongly accessible objects are marked. */ | 1003 | /* at this point, all strongly accessible objects are marked. */ |
| 978 | /* clear values from weak tables, before checking finalizers */ | 1004 | /* clear values from weak tables, before checking finalizers */ |
| 979 | clearvalues(g, g->weak, NULL); | 1005 | clearvalues(g, g->weak, NULL); |
| 980 | clearvalues(g, g->allweak, NULL); | 1006 | clearvalues(g, g->allweak, NULL); |
| 981 | origweak = g->weak; origall = g->allweak; | 1007 | origweak = g->weak; origall = g->allweak; |
| | 1008 | work += g->GCmemtrav; /* stop counting (objects being finalized) */ |
| 982 | separatetobefnz(L, 0); /* separate objects to be finalized */ | 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 | propagateall(g); /* remark, to propagate `preserveness' */ | 1011 | propagateall(g); /* remark, to propagate `preserveness' */ |
| 985 | trav = g->GCmemtrav - trav; /* avoid adding convergence twice */ | 1012 | work -= g->GCmemtrav; /* restart counting */ |
| 986 | convergeephemerons(g); | 1013 | convergeephemerons(g); |
| 987 | /* at this point, all resurrected objects are marked. */ | 1014 | /* at this point, all resurrected objects are marked. */ |
| 988 | /* remove dead objects from weak tables */ | 1015 | /* remove dead objects from weak tables */ |
| @@ -992,9 +1019,8 @@ static l_mem atomic (lua_State *L) { · 3 unmodified lines |
| 992 | clearvalues(g, g->weak, origweak); | 1019 | clearvalues(g, g->weak, origweak); |
| 993 | clearvalues(g, g->allweak, origall); | 1020 | clearvalues(g, g->allweak, origall); |
| 994 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ | 1021 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ |
| 995 | entersweep(L); /* prepare to sweep strings */ | 1022 | work += g->GCmemtrav; /* complete counting */ |
| 996 | /*lua_checkmemory(L);*/ | 1023 | return work; /* estimate of memory marked by 'atomic' */ |
| 997 | return trav; /* reasonable estimate of the work done by 'atomic' */ | | |
| 998 | } | 1024 | } |
| 999 | | 1025 | |
| 1000 | | 1026 | |
| @@ -1018,9 +1044,14 @@ static lu_mem singlestep (lua_State *L) { · 17 unmodified lines |
| 1018 | return g->GCmemtrav - oldtrav; /* memory traversed in this step */ | 1044 | return g->GCmemtrav - oldtrav; /* memory traversed in this step */ |
| 1019 | } | 1045 | } |
| 1020 | else { /* no more `gray' objects */ | 1046 | else { /* no more `gray' objects */ |
| | 1047 | lu_mem work; |
| | 1048 | int sw; |
| 1021 | g->gcstate = GCSatomic; /* finish mark phase */ | 1049 | g->gcstate = GCSatomic; /* finish mark phase */ |
| 1022 | g->GCestimate = g->GCmemtrav; /* save what was counted */ | 1050 | g->GCestimate = g->GCmemtrav; /* save what was counted */; |
| 1023 | return atomic(L); | 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 | case GCSsweepstring: { | 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 | global_State *g = G(L); | 1124 | global_State *g = G(L); |
| 1094 | l_mem debt = g->GCdebt; | 1125 | l_mem debt = g->GCdebt; |
| 1095 | int stepmul = g->gcstepmul; | 1126 | int stepmul = g->gcstepmul; |
| @@ -1116,7 +1147,7 @@ void luaC_forcestep (lua_State *L) { · 20 unmodified lines |
| 1116 | global_State *g = G(L); | 1147 | global_State *g = G(L); |
| 1117 | int i; | 1148 | int i; |
| 1118 | if (isgenerational(g)) generationalcollection(L); | 1149 | if (isgenerational(g)) generationalcollection(L); |
| 1119 | else step(L); | 1150 | else incstep(L); |
| 1120 | /* run a few finalizers (or all of them at the end of a collect cycle) */ | 1151 | /* run a few finalizers (or all of them at the end of a collect cycle) */ |
| 1121 | for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++) | 1152 | for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++) |
| 1122 | GCTM(L, 1); /* call one finalizer */ | 1153 | GCTM(L, 1); /* call one finalizer */ |