diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1997-09-16 16:25:59 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1997-09-16 16:25:59 -0300 |
commit | 189d64409b5f7e09fb7650e7217d55277b1fccba (patch) | |
tree | f08f8ba854b92a061435f191e0f0d87fdc06701e | |
parent | 60cc473bcfce079d1525fcffcfdfbeb66e35afa2 (diff) | |
download | lua-189d64409b5f7e09fb7650e7217d55277b1fccba.tar.gz lua-189d64409b5f7e09fb7650e7217d55277b1fccba.tar.bz2 lua-189d64409b5f7e09fb7650e7217d55277b1fccba.zip |
Garbage Collector
-rw-r--r-- | lgc.c | 295 | ||||
-rw-r--r-- | lgc.h | 21 |
2 files changed, 316 insertions, 0 deletions
@@ -0,0 +1,295 @@ | |||
1 | /* | ||
2 | ** $Id: $ | ||
3 | ** Garbage Collector | ||
4 | ** See Copyright Notice in lua.h | ||
5 | */ | ||
6 | |||
7 | |||
8 | #include "ldo.h" | ||
9 | #include "lfunc.h" | ||
10 | #include "lgc.h" | ||
11 | #include "lglobal.h" | ||
12 | #include "lmem.h" | ||
13 | #include "lobject.h" | ||
14 | #include "lstring.h" | ||
15 | #include "ltable.h" | ||
16 | #include "ltm.h" | ||
17 | #include "lua.h" | ||
18 | |||
19 | |||
20 | |||
21 | static int markobject (TObject *o); | ||
22 | |||
23 | |||
24 | |||
25 | /* | ||
26 | ** ======================================================= | ||
27 | ** REF mechanism | ||
28 | ** ======================================================= | ||
29 | */ | ||
30 | |||
31 | static struct ref { | ||
32 | TObject o; | ||
33 | enum {LOCK, HOLD, FREE, COLLECTED} status; | ||
34 | } *refArray = NULL; | ||
35 | static int refSize = 0; | ||
36 | |||
37 | |||
38 | int luaC_ref (TObject *o, int lock) | ||
39 | { | ||
40 | int ref; | ||
41 | if (ttype(o) == LUA_T_NIL) | ||
42 | ref = -1; /* special ref for nil */ | ||
43 | else { | ||
44 | for (ref=0; ref<refSize; ref++) | ||
45 | if (refArray[ref].status == FREE) | ||
46 | goto found; | ||
47 | /* no more empty spaces */ { | ||
48 | int oldSize = refSize; | ||
49 | refSize = luaM_growvector(&refArray, refSize, struct ref, refEM, MAX_WORD); | ||
50 | for (ref=oldSize; ref<refSize; ref++) | ||
51 | refArray[ref].status = FREE; | ||
52 | ref = oldSize; | ||
53 | } found: | ||
54 | refArray[ref].o = *o; | ||
55 | refArray[ref].status = lock ? LOCK : HOLD; | ||
56 | } | ||
57 | return ref; | ||
58 | } | ||
59 | |||
60 | |||
61 | void lua_unref (int ref) | ||
62 | { | ||
63 | if (ref >= 0 && ref < refSize) | ||
64 | refArray[ref].status = FREE; | ||
65 | } | ||
66 | |||
67 | |||
68 | TObject* luaC_getref (int ref) | ||
69 | { | ||
70 | static TObject nul = {LUA_T_NIL, {0}}; | ||
71 | if (ref == -1) | ||
72 | return &nul; | ||
73 | if (ref >= 0 && ref < refSize && | ||
74 | (refArray[ref].status == LOCK || refArray[ref].status == HOLD)) | ||
75 | return &refArray[ref].o; | ||
76 | else | ||
77 | return NULL; | ||
78 | } | ||
79 | |||
80 | |||
81 | static void travlock (void) | ||
82 | { | ||
83 | int i; | ||
84 | for (i=0; i<refSize; i++) | ||
85 | if (refArray[i].status == LOCK) | ||
86 | markobject(&refArray[i].o); | ||
87 | } | ||
88 | |||
89 | |||
90 | static int ismarked (TObject *o) | ||
91 | { | ||
92 | switch (o->ttype) { | ||
93 | case LUA_T_STRING: case LUA_T_USERDATA: | ||
94 | return o->value.ts->marked; | ||
95 | case LUA_T_FUNCTION: | ||
96 | return o->value.cl->head.marked; | ||
97 | case LUA_T_PROTO: | ||
98 | return o->value.tf->head.marked; | ||
99 | case LUA_T_ARRAY: | ||
100 | return o->value.a->head.marked; | ||
101 | default: /* nil, number or cfunction */ | ||
102 | return 1; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | |||
107 | static void invalidaterefs (void) | ||
108 | { | ||
109 | int i; | ||
110 | for (i=0; i<refSize; i++) | ||
111 | if (refArray[i].status == HOLD && !ismarked(&refArray[i].o)) | ||
112 | refArray[i].status = COLLECTED; | ||
113 | } | ||
114 | |||
115 | |||
116 | |||
117 | static void hashcallIM (Hash *l) | ||
118 | { | ||
119 | TObject t; | ||
120 | ttype(&t) = LUA_T_ARRAY; | ||
121 | for (; l; l=(Hash *)l->head.next) { | ||
122 | avalue(&t) = l; | ||
123 | luaD_gcIM(&t); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | |||
128 | static void strcallIM (TaggedString *l) | ||
129 | { | ||
130 | TObject o; | ||
131 | ttype(&o) = LUA_T_USERDATA; | ||
132 | for (; l; l=l->uu.next) { | ||
133 | tsvalue(&o) = l; | ||
134 | luaD_gcIM(&o); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | |||
139 | |||
140 | static GCnode *listcollect (GCnode **root) | ||
141 | { | ||
142 | GCnode *curr = *root, *prev = NULL, *frees = NULL; | ||
143 | while (curr) { | ||
144 | GCnode *next = curr->next; | ||
145 | if (!curr->marked) { | ||
146 | if (prev == NULL) | ||
147 | *root = next; | ||
148 | else | ||
149 | prev->next = next; | ||
150 | curr->next = frees; | ||
151 | frees = curr; | ||
152 | --luaO_nentities; | ||
153 | } | ||
154 | else { | ||
155 | curr->marked = 0; | ||
156 | prev = curr; | ||
157 | } | ||
158 | curr = next; | ||
159 | } | ||
160 | return frees; | ||
161 | } | ||
162 | |||
163 | |||
164 | |||
165 | static void strmark (TaggedString *s) | ||
166 | { | ||
167 | if (!s->marked) | ||
168 | s->marked = 1; | ||
169 | } | ||
170 | |||
171 | |||
172 | static void protomark (TProtoFunc *f) | ||
173 | { | ||
174 | if (!f->head.marked) { | ||
175 | LocVar *v = f->locvars; | ||
176 | int i; | ||
177 | f->head.marked = 1; | ||
178 | if (f->fileName) | ||
179 | strmark(f->fileName); | ||
180 | for (i=0; i<f->nconsts; i++) | ||
181 | markobject(&f->consts[i]); | ||
182 | if (v) { | ||
183 | for (; v->line != -1; v++) | ||
184 | if (v->varname) | ||
185 | strmark(v->varname); | ||
186 | } | ||
187 | } | ||
188 | } | ||
189 | |||
190 | |||
191 | static void funcmark (Closure *f) | ||
192 | { | ||
193 | if (!f->head.marked) { | ||
194 | int i; | ||
195 | f->head.marked = 1; | ||
196 | for (i=f->consts[0].value.tf->nupvalues; i>=0; i--) | ||
197 | markobject(&f->consts[i]); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | |||
202 | static void hashmark (Hash *h) | ||
203 | { | ||
204 | if (!h->head.marked) { | ||
205 | int i; | ||
206 | h->head.marked = 1; | ||
207 | for (i=0; i<nhash(h); i++) { | ||
208 | Node *n = node(h,i); | ||
209 | if (ttype(ref(n)) != LUA_T_NIL) { | ||
210 | markobject(&n->ref); | ||
211 | markobject(&n->val); | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | |||
217 | |||
218 | static int markobject (TObject *o) | ||
219 | { | ||
220 | switch (ttype(o)) { | ||
221 | case LUA_T_USERDATA: case LUA_T_STRING: | ||
222 | strmark(tsvalue(o)); | ||
223 | break; | ||
224 | case LUA_T_ARRAY: | ||
225 | hashmark(avalue(o)); | ||
226 | break; | ||
227 | case LUA_T_FUNCTION: case LUA_T_MARK: | ||
228 | funcmark(o->value.cl); | ||
229 | break; | ||
230 | case LUA_T_PROTO: | ||
231 | protomark(o->value.tf); | ||
232 | break; | ||
233 | default: break; /* numbers, cfunctions, etc */ | ||
234 | } | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | |||
239 | static void call_nilIM (void) | ||
240 | { /* signals end of garbage collection */ | ||
241 | TObject t; | ||
242 | ttype(&t) = LUA_T_NIL; | ||
243 | luaD_gcIM(&t); /* end of list */ | ||
244 | } | ||
245 | |||
246 | |||
247 | |||
248 | #define GARBAGE_BLOCK 150 | ||
249 | |||
250 | long luaC_threshold = GARBAGE_BLOCK; | ||
251 | |||
252 | |||
253 | static void markall (void) | ||
254 | { | ||
255 | luaD_travstack(markobject); /* mark stack objects */ | ||
256 | luaG_travsymbol(markobject); /* mark symbol table objects */ | ||
257 | travlock(); /* mark locked objects */ | ||
258 | luaT_travtagmethods(markobject); /* mark fallbacks */ | ||
259 | } | ||
260 | |||
261 | |||
262 | long lua_collectgarbage (long limit) | ||
263 | { | ||
264 | long recovered = luaO_nentities; /* to subtract luaM_new value after gc */ | ||
265 | Hash *freetable; | ||
266 | TaggedString *freestr; | ||
267 | TProtoFunc *freefunc; | ||
268 | Closure *freeclos; | ||
269 | markall(); | ||
270 | invalidaterefs(); | ||
271 | freestr = luaS_collector(); | ||
272 | freetable = (Hash *)listcollect((GCnode **)&luaH_root); | ||
273 | freefunc = (TProtoFunc *)listcollect((GCnode **)&luaF_root); | ||
274 | freeclos = (Closure *)listcollect((GCnode **)&luaF_rootcl); | ||
275 | recovered = recovered-luaO_nentities; | ||
276 | /*printf("==total %ld coletados %ld\n", luaO_nentities+recovered, recovered);*/ | ||
277 | luaC_threshold = (limit == 0) ? 2*luaO_nentities : luaO_nentities+limit; | ||
278 | hashcallIM(freetable); | ||
279 | strcallIM(freestr); | ||
280 | call_nilIM(); | ||
281 | luaH_free(freetable); | ||
282 | luaS_free(freestr); | ||
283 | luaF_freeproto(freefunc); | ||
284 | luaF_freeclosure(freeclos); | ||
285 | luaM_clearbuffer(); | ||
286 | return recovered; | ||
287 | } | ||
288 | |||
289 | |||
290 | void luaC_checkGC (void) | ||
291 | { | ||
292 | if (luaO_nentities >= luaC_threshold) | ||
293 | lua_collectgarbage(0); | ||
294 | } | ||
295 | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | ** $Id: $ | ||
3 | ** Garbage Collector | ||
4 | ** See Copyright Notice in lua.h | ||
5 | */ | ||
6 | |||
7 | #ifndef lgc_h | ||
8 | #define lgc_h | ||
9 | |||
10 | |||
11 | #include "lobject.h" | ||
12 | |||
13 | |||
14 | extern long luaC_threshold; | ||
15 | |||
16 | void luaC_checkGC (void); | ||
17 | TObject* luaC_getref (int ref); | ||
18 | int luaC_ref (TObject *o, int lock); | ||
19 | |||
20 | |||
21 | #endif | ||