diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2000-08-07 17:21:34 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2000-08-07 17:21:34 -0300 |
commit | d9e61e8ceafe8c3f6ad936979719ca7c446ce228 (patch) | |
tree | 0808ada3d7b7219022b9002503894c76c7253df6 /lgc.c | |
parent | 397905ef8694ec716a51acebc993bb625340d388 (diff) | |
download | lua-d9e61e8ceafe8c3f6ad936979719ca7c446ce228.tar.gz lua-d9e61e8ceafe8c3f6ad936979719ca7c446ce228.tar.bz2 lua-d9e61e8ceafe8c3f6ad936979719ca7c446ce228.zip |
new algorithm for traversing in GC to avoid deep recursion calls
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 148 |
1 files changed, 86 insertions, 62 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 1.58 2000/06/26 19:28:31 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 1.59 2000/06/30 14:35:17 roberto Exp roberto $ |
3 | ** Garbage Collector | 3 | ** Garbage Collector |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -20,97 +20,94 @@ | |||
20 | #include "ltm.h" | 20 | #include "ltm.h" |
21 | 21 | ||
22 | 22 | ||
23 | typedef struct GCState { | ||
24 | Hash *tmark; /* list of marked tables to be visited */ | ||
25 | Closure *cmark; /* list of marked closures to be visited */ | ||
26 | } GCState; | ||
23 | 27 | ||
24 | 28 | ||
25 | static int markobject (lua_State *L, TObject *o); | 29 | |
30 | static int markobject (GCState *st, TObject *o); | ||
26 | 31 | ||
27 | 32 | ||
28 | /* mark a string; marks larger than 1 cannot be changed */ | 33 | /* mark a string; marks larger than 1 cannot be changed */ |
29 | #define strmark(L, s) {if ((s)->marked == 0) (s)->marked = 1;} | 34 | #define strmark(s) {if ((s)->marked == 0) (s)->marked = 1;} |
30 | 35 | ||
31 | 36 | ||
32 | 37 | ||
33 | static void protomark (lua_State *L, Proto *f) { | 38 | static void protomark (Proto *f) { |
34 | if (!f->marked) { | 39 | if (!f->marked) { |
35 | int i; | 40 | int i; |
36 | f->marked = 1; | 41 | f->marked = 1; |
37 | strmark(L, f->source); | 42 | strmark(f->source); |
38 | for (i=0; i<f->nkstr; i++) | 43 | for (i=0; i<f->nkstr; i++) |
39 | strmark(L, f->kstr[i]); | 44 | strmark(f->kstr[i]); |
40 | for (i=0; i<f->nkproto; i++) | 45 | for (i=0; i<f->nkproto; i++) |
41 | protomark(L, f->kproto[i]); | 46 | protomark(f->kproto[i]); |
42 | if (f->locvars) { /* is there debug information? */ | 47 | if (f->locvars) { /* is there debug information? */ |
43 | LocVar *lv; | 48 | LocVar *lv; |
44 | for (lv=f->locvars; lv->pc != -1; lv++) /* mark local-variable names */ | 49 | for (lv=f->locvars; lv->pc != -1; lv++) /* mark local-variable names */ |
45 | if (lv->varname) strmark(L, lv->varname); | 50 | if (lv->varname) strmark(lv->varname); |
46 | } | 51 | } |
47 | } | 52 | } |
48 | } | 53 | } |
49 | 54 | ||
50 | 55 | ||
51 | static void closuremark (lua_State *L, Closure *f) { | 56 | static void markstack (lua_State *L, GCState *st) { |
52 | if (!f->marked) { | ||
53 | int i = f->nupvalues; | ||
54 | f->marked = 1; | ||
55 | while (i--) | ||
56 | markobject(L, &f->upvalue[i]); | ||
57 | } | ||
58 | } | ||
59 | |||
60 | |||
61 | static void tablemark (lua_State *L, Hash *h) { | ||
62 | if (!h->marked) { | ||
63 | int i; | ||
64 | h->marked = 1; | ||
65 | for (i=h->size-1; i>=0; i--) { | ||
66 | Node *n = node(h,i); | ||
67 | if (ttype(key(n)) != TAG_NIL) { | ||
68 | if (ttype(val(n)) == TAG_NIL) | ||
69 | luaH_remove(h, key(n)); /* dead element; try to remove it */ | ||
70 | markobject(L, &n->key); | ||
71 | markobject(L, &n->val); | ||
72 | } | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | |||
77 | |||
78 | static void travstack (lua_State *L) { | ||
79 | StkId o; | 57 | StkId o; |
80 | for (o=L->stack; o<L->top; o++) | 58 | for (o=L->stack; o<L->top; o++) |
81 | markobject(L, o); | 59 | markobject(st, o); |
82 | } | 60 | } |
83 | 61 | ||
84 | 62 | ||
85 | static void travlock (lua_State *L) { | 63 | static void marklock (lua_State *L, GCState *st) { |
86 | int i; | 64 | int i; |
87 | for (i=0; i<L->refSize; i++) { | 65 | for (i=0; i<L->refSize; i++) { |
88 | if (L->refArray[i].st == LOCK) | 66 | if (L->refArray[i].st == LOCK) |
89 | markobject(L, &L->refArray[i].o); | 67 | markobject(st, &L->refArray[i].o); |
68 | } | ||
69 | } | ||
70 | |||
71 | |||
72 | static void marktagmethods (lua_State *L, GCState *st) { | ||
73 | int e; | ||
74 | for (e=0; e<IM_N; e++) { | ||
75 | int t; | ||
76 | for (t=0; t<=L->last_tag; t++) | ||
77 | markobject(st, luaT_getim(L, t,e)); | ||
90 | } | 78 | } |
91 | } | 79 | } |
92 | 80 | ||
93 | 81 | ||
94 | static int markobject (lua_State *L, TObject *o) { | 82 | static int markobject (GCState *st, TObject *o) { |
95 | switch (ttype(o)) { | 83 | switch (ttype(o)) { |
96 | case TAG_USERDATA: case TAG_STRING: | 84 | case TAG_USERDATA: case TAG_STRING: |
97 | strmark(L, tsvalue(o)); | 85 | strmark(tsvalue(o)); |
98 | break; | ||
99 | case TAG_TABLE: | ||
100 | tablemark(L, hvalue(o)); | ||
101 | break; | 86 | break; |
102 | case TAG_LCLOSURE: | 87 | case TAG_TABLE: { |
103 | protomark(L, clvalue(o)->f.l); | 88 | if (!ismarked(hvalue(o))) { |
104 | closuremark(L, clvalue(o)); | 89 | hvalue(o)->mark = st->tmark; /* chain it in list of marked */ |
90 | st->tmark = hvalue(o); | ||
91 | } | ||
105 | break; | 92 | break; |
93 | } | ||
106 | case TAG_LMARK: { | 94 | case TAG_LMARK: { |
107 | Closure *cl = infovalue(o)->func; | 95 | Closure *cl = infovalue(o)->func; |
108 | protomark(L, cl->f.l); | 96 | if (!ismarked(cl)) { |
109 | closuremark(L, cl); | 97 | protomark(cl->f.l); |
98 | cl->mark = st->cmark; /* chain it for later traversal */ | ||
99 | st->cmark = cl; | ||
100 | } | ||
110 | break; | 101 | break; |
111 | } | 102 | } |
103 | case TAG_LCLOSURE: | ||
104 | protomark(clvalue(o)->f.l); | ||
105 | /* go through */ | ||
112 | case TAG_CCLOSURE: case TAG_CMARK: | 106 | case TAG_CCLOSURE: case TAG_CMARK: |
113 | closuremark(L, clvalue(o)); | 107 | if (!ismarked(clvalue(o))) { |
108 | clvalue(o)->mark = st->cmark; /* chain it for later traversal */ | ||
109 | st->cmark = clvalue(o); | ||
110 | } | ||
114 | break; | 111 | break; |
115 | default: break; /* numbers, etc */ | 112 | default: break; /* numbers, etc */ |
116 | } | 113 | } |
@@ -118,6 +115,41 @@ static int markobject (lua_State *L, TObject *o) { | |||
118 | } | 115 | } |
119 | 116 | ||
120 | 117 | ||
118 | static void markall (lua_State *L) { | ||
119 | GCState st; | ||
120 | st.cmark = NULL; | ||
121 | st.tmark = L->gt; /* put table of globals in mark list */ | ||
122 | L->gt->mark = NULL; | ||
123 | marktagmethods(L, &st); /* mark tag methods */ | ||
124 | markstack(L, &st); /* mark stack objects */ | ||
125 | marklock(L, &st); /* mark locked objects */ | ||
126 | for (;;) { /* mark tables and closures */ | ||
127 | if (st.cmark) { | ||
128 | int i; | ||
129 | Closure *f = st.cmark; /* get first closure from list */ | ||
130 | st.cmark = f->mark; /* remove it from list */ | ||
131 | for (i=0; i<f->nupvalues; i++) /* mark its upvalues */ | ||
132 | markobject(&st, &f->upvalue[i]); | ||
133 | } | ||
134 | else if (st.tmark) { | ||
135 | int i; | ||
136 | Hash *h = st.tmark; /* get first table from list */ | ||
137 | st.tmark = h->mark; /* remove it from list */ | ||
138 | for (i=0; i<h->size; i++) { | ||
139 | Node *n = node(h, i); | ||
140 | if (ttype(key(n)) != TAG_NIL) { | ||
141 | if (ttype(val(n)) == TAG_NIL) | ||
142 | luaH_remove(h, key(n)); /* dead element; try to remove it */ | ||
143 | markobject(&st, &n->key); | ||
144 | markobject(&st, &n->val); | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | else break; /* nothing else to mark */ | ||
149 | } | ||
150 | } | ||
151 | |||
152 | |||
121 | static void collectproto (lua_State *L) { | 153 | static void collectproto (lua_State *L) { |
122 | Proto **p = &L->rootproto; | 154 | Proto **p = &L->rootproto; |
123 | Proto *next; | 155 | Proto *next; |
@@ -138,8 +170,8 @@ static void collectclosure (lua_State *L) { | |||
138 | Closure **p = &L->rootcl; | 170 | Closure **p = &L->rootcl; |
139 | Closure *next; | 171 | Closure *next; |
140 | while ((next = *p) != NULL) { | 172 | while ((next = *p) != NULL) { |
141 | if (next->marked) { | 173 | if (ismarked(next)) { |
142 | next->marked = 0; | 174 | next->mark = next; /* unmark */ |
143 | p = &next->next; | 175 | p = &next->next; |
144 | } | 176 | } |
145 | else { | 177 | else { |
@@ -154,8 +186,8 @@ static void collecttable (lua_State *L) { | |||
154 | Hash **p = &L->roottable; | 186 | Hash **p = &L->roottable; |
155 | Hash *next; | 187 | Hash *next; |
156 | while ((next = *p) != NULL) { | 188 | while ((next = *p) != NULL) { |
157 | if (next->marked) { | 189 | if (ismarked(next)) { |
158 | next->marked = 0; | 190 | next->mark = next; /* unmark */ |
159 | p = &next->next; | 191 | p = &next->next; |
160 | } | 192 | } |
161 | else { | 193 | else { |
@@ -256,14 +288,6 @@ static void callgcTMudata (lua_State *L) { | |||
256 | } | 288 | } |
257 | 289 | ||
258 | 290 | ||
259 | static void markall (lua_State *L) { | ||
260 | luaT_travtagmethods(L, markobject); /* mark tag methods */ | ||
261 | travstack(L); /* mark stack objects */ | ||
262 | tablemark(L, L->gt); /* mark global variables */ | ||
263 | travlock(L); /* mark locked objects */ | ||
264 | } | ||
265 | |||
266 | |||
267 | void luaC_collect (lua_State *L, int all) { | 291 | void luaC_collect (lua_State *L, int all) { |
268 | int oldah = L->allowhooks; | 292 | int oldah = L->allowhooks; |
269 | L->allowhooks = 0; /* stop debug hooks during GC */ | 293 | L->allowhooks = 0; /* stop debug hooks during GC */ |