aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>1997-09-16 16:25:59 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>1997-09-16 16:25:59 -0300
commit189d64409b5f7e09fb7650e7217d55277b1fccba (patch)
treef08f8ba854b92a061435f191e0f0d87fdc06701e
parent60cc473bcfce079d1525fcffcfdfbeb66e35afa2 (diff)
downloadlua-189d64409b5f7e09fb7650e7217d55277b1fccba.tar.gz
lua-189d64409b5f7e09fb7650e7217d55277b1fccba.tar.bz2
lua-189d64409b5f7e09fb7650e7217d55277b1fccba.zip
Garbage Collector
-rw-r--r--lgc.c295
-rw-r--r--lgc.h21
2 files changed, 316 insertions, 0 deletions
diff --git a/lgc.c b/lgc.c
new file mode 100644
index 00000000..d50d5d07
--- /dev/null
+++ b/lgc.c
@@ -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
21static int markobject (TObject *o);
22
23
24
25/*
26** =======================================================
27** REF mechanism
28** =======================================================
29*/
30
31static struct ref {
32 TObject o;
33 enum {LOCK, HOLD, FREE, COLLECTED} status;
34} *refArray = NULL;
35static int refSize = 0;
36
37
38int 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
61void lua_unref (int ref)
62{
63 if (ref >= 0 && ref < refSize)
64 refArray[ref].status = FREE;
65}
66
67
68TObject* 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
81static 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
90static 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
107static 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
117static 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
128static 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
140static 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
165static void strmark (TaggedString *s)
166{
167 if (!s->marked)
168 s->marked = 1;
169}
170
171
172static 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
191static 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
202static 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
218static 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
239static 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
250long luaC_threshold = GARBAGE_BLOCK;
251
252
253static 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
262long 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
290void luaC_checkGC (void)
291{
292 if (luaO_nentities >= luaC_threshold)
293 lua_collectgarbage(0);
294}
295
diff --git a/lgc.h b/lgc.h
new file mode 100644
index 00000000..fdf75d05
--- /dev/null
+++ b/lgc.h
@@ -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
14extern long luaC_threshold;
15
16void luaC_checkGC (void);
17TObject* luaC_getref (int ref);
18int luaC_ref (TObject *o, int lock);
19
20
21#endif