diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2001-11-06 19:41:53 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2001-11-06 19:41:53 -0200 |
commit | 26bf2adaceb18877d836174226d2bfdc3f1fc512 (patch) | |
tree | b23ccd2e297e7c5e732ce65e88f35145271f7faa | |
parent | fd48dcc7c8734091181d8d0e54b0ba3d1770f4c3 (diff) | |
download | lua-26bf2adaceb18877d836174226d2bfdc3f1fc512.tar.gz lua-26bf2adaceb18877d836174226d2bfdc3f1fc512.tar.bz2 lua-26bf2adaceb18877d836174226d2bfdc3f1fc512.zip |
optimizations for space in LClosures and time cleanning weak tables
-rw-r--r-- | lfunc.c | 22 | ||||
-rw-r--r-- | lgc.c | 100 | ||||
-rw-r--r-- | lobject.h | 38 | ||||
-rw-r--r-- | lvm.c | 13 |
4 files changed, 88 insertions, 85 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lfunc.c,v 1.47 2001/09/07 17:39:10 roberto Exp $ | 2 | ** $Id: lfunc.c,v 1.48 2001/10/02 16:45:03 roberto Exp $ |
3 | ** Auxiliary functions to manipulate prototypes and closures | 3 | ** Auxiliary functions to manipulate prototypes and closures |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -20,7 +20,7 @@ | |||
20 | cast(int, sizeof(TObject)*((n)-1))) | 20 | cast(int, sizeof(TObject)*((n)-1))) |
21 | 21 | ||
22 | #define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ | 22 | #define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ |
23 | cast(int, sizeof(LClosureEntry)*((n)-1))) | 23 | cast(int, sizeof(TObject *)*((n)-1))) |
24 | 24 | ||
25 | 25 | ||
26 | Closure *luaF_newCclosure (lua_State *L, int nelems) { | 26 | Closure *luaF_newCclosure (lua_State *L, int nelems) { |
@@ -50,8 +50,8 @@ static StkId uppoint (LClosure *cl) { | |||
50 | StkId lp = NULL; | 50 | StkId lp = NULL; |
51 | int i; | 51 | int i; |
52 | for (i=0; i<cl->nupvalues; i++) { | 52 | for (i=0; i<cl->nupvalues; i++) { |
53 | if (cl->upvals[i].heap == NULL && (lp == NULL || cl->upvals[i].val > lp)) | 53 | if (!isclosed(cl->upvals[i]) && (lp == NULL || cl->upvals[i] > lp)) |
54 | lp = cl->upvals[i].val; | 54 | lp = cl->upvals[i]; |
55 | } | 55 | } |
56 | return lp; | 56 | return lp; |
57 | } | 57 | } |
@@ -77,17 +77,15 @@ static int closeCl (lua_State *L, LClosure *cl, StkId level) { | |||
77 | int i; | 77 | int i; |
78 | for (i=0; i<cl->nupvalues; i++) { | 78 | for (i=0; i<cl->nupvalues; i++) { |
79 | StkId var; | 79 | StkId var; |
80 | if (cl->upvals[i].heap == NULL && (var=cl->upvals[i].val) >= level) { | 80 | if (!isclosed(cl->upvals[i]) && (var=cl->upvals[i]) >= level) { |
81 | if (ttype(var) != LUA_TUPVAL) { | 81 | if (ttype(var) != LUA_TUPVAL) { |
82 | UpVal *v = luaM_new(L, UpVal); | 82 | TObject *v = luaM_newvector(L, 2, TObject); |
83 | v->val = *var; | 83 | v[1] = *var; |
84 | v->marked = 0; | 84 | setupvalue(v, G(L)->rootupval, LUA_HEAPUPVAL); |
85 | v->next = G(L)->rootupval; | ||
86 | G(L)->rootupval = v; | 85 | G(L)->rootupval = v; |
87 | setupvalue(var, v); | 86 | setupvalue(var, &v[1], LUA_TUPVAL); |
88 | } | 87 | } |
89 | cl->upvals[i].heap = vvalue(var); | 88 | cl->upvals[i] = vvalue(var); |
90 | cl->upvals[i].val = &vvalue(var)->val; | ||
91 | got = 1; | 89 | got = 1; |
92 | } | 90 | } |
93 | } | 91 | } |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 1.114 2001/10/25 19:14:14 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 1.115 2001/10/31 19:58:11 roberto Exp $ |
3 | ** Garbage Collector | 3 | ** Garbage Collector |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | typedef struct GCState { | 23 | typedef struct GCState { |
24 | Table *tmark; /* list of marked tables to be visited */ | 24 | Table *tmark; /* list of marked tables to be visited */ |
25 | Table *toclear; /* list of visited weak tables (to be cleared after GC) */ | ||
25 | } GCState; | 26 | } GCState; |
26 | 27 | ||
27 | 28 | ||
@@ -65,10 +66,10 @@ static void markclosure (GCState *st, Closure *cl) { | |||
65 | lua_assert(cl->l.nupvalues == cl->l.p->nupvalues); | 66 | lua_assert(cl->l.nupvalues == cl->l.p->nupvalues); |
66 | protomark(cl->l.p); | 67 | protomark(cl->l.p); |
67 | for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ | 68 | for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ |
68 | UpVal *u = cl->l.upvals[i].heap; | 69 | TObject *u = cl->l.upvals[i]; |
69 | if (u && !u->marked) { | 70 | if (isclosed(u)) { |
70 | u->marked = 1; | 71 | ttype(u-1) = LUA_TNIL; /* temporary value (to mark as visited) */ |
71 | markobject(st, &u->val); | 72 | markobject(st, u); |
72 | } | 73 | } |
73 | } | 74 | } |
74 | } | 75 | } |
@@ -148,6 +149,10 @@ static void removekey (Node *n) { | |||
148 | static void traversetable (GCState *st, Table *h) { | 149 | static void traversetable (GCState *st, Table *h) { |
149 | int i; | 150 | int i; |
150 | int mode = h->weakmode; | 151 | int mode = h->weakmode; |
152 | if (mode) { /* weak table? must be cleared after GC... */ | ||
153 | h->mark = st->toclear; /* put in the appropriate list */ | ||
154 | st->toclear = h; | ||
155 | } | ||
151 | if (!(mode & LUA_WEAK_VALUE)) { | 156 | if (!(mode & LUA_WEAK_VALUE)) { |
152 | i = sizearray(h); | 157 | i = sizearray(h); |
153 | while (i--) | 158 | while (i--) |
@@ -167,17 +172,15 @@ static void traversetable (GCState *st, Table *h) { | |||
167 | } | 172 | } |
168 | 173 | ||
169 | 174 | ||
170 | static void markall (lua_State *L) { | 175 | static void markall (lua_State *L, GCState *st) { |
171 | GCState st; | 176 | marktagmethods(G(L), st); /* mark tag methods */ |
172 | st.tmark = NULL; | 177 | markstacks(L, st); /* mark all stacks */ |
173 | marktagmethods(G(L), &st); /* mark tag methods */ | 178 | marktable(st, G(L)->type2tag); |
174 | markstacks(L, &st); /* mark all stacks */ | 179 | markobject(st, &G(L)->registry); |
175 | marktable(&st, G(L)->type2tag); | 180 | while (st->tmark) { /* mark tables */ |
176 | markobject(&st, &G(L)->registry); | 181 | Table *h = st->tmark; /* get first table from list */ |
177 | while (st.tmark) { /* mark tables */ | 182 | st->tmark = h->mark; /* remove it from list */ |
178 | Table *h = st.tmark; /* get first table from list */ | 183 | traversetable(st, h); |
179 | st.tmark = h->mark; /* remove it from list */ | ||
180 | traversetable(&st, h); | ||
181 | } | 184 | } |
182 | } | 185 | } |
183 | 186 | ||
@@ -198,30 +201,27 @@ static int hasmark (const TObject *o) { | |||
198 | } | 201 | } |
199 | 202 | ||
200 | 203 | ||
201 | static void cleardeadnodes (Table *h) { | 204 | /* |
202 | int i; | 205 | ** clear (set to nil) keys and values from weaktables that were collected |
203 | i = sizearray(h); | 206 | */ |
204 | while (i--) { | 207 | static void cleartables (Table *h) { |
205 | TObject *o = &h->array[i]; | 208 | for (; h; h = h->mark) { |
206 | if (!hasmark(o)) | 209 | int i; |
207 | setnilvalue(o); /* remove value */ | 210 | lua_assert(h->weakmode); |
208 | } | 211 | i = sizearray(h); |
209 | i = sizenode(h); | 212 | while (i--) { |
210 | while (i--) { | 213 | TObject *o = &h->array[i]; |
211 | Node *n = node(h, i); | 214 | if (!hasmark(o)) |
212 | if (!hasmark(val(n)) || !hasmark(key(n))) { | 215 | setnilvalue(o); /* remove value */ |
213 | setnilvalue(val(n)); /* remove value ... */ | 216 | } |
214 | removekey(n); /* ... and key */ | 217 | i = sizenode(h); |
218 | while (i--) { | ||
219 | Node *n = node(h, i); | ||
220 | if (!hasmark(val(n)) || !hasmark(key(n))) { | ||
221 | setnilvalue(val(n)); /* remove value ... */ | ||
222 | removekey(n); /* ... and key */ | ||
223 | } | ||
215 | } | 224 | } |
216 | } | ||
217 | } | ||
218 | |||
219 | |||
220 | static void cleartables (global_State *G) { | ||
221 | Table *h; | ||
222 | for (h = G->roottable; h; h = h->next) { | ||
223 | if (h->weakmode && ismarked(h)) | ||
224 | cleardeadnodes(h); | ||
225 | } | 225 | } |
226 | } | 226 | } |
227 | 227 | ||
@@ -284,16 +284,17 @@ static void collecttable (lua_State *L) { | |||
284 | 284 | ||
285 | 285 | ||
286 | static void collectupval (lua_State *L) { | 286 | static void collectupval (lua_State *L) { |
287 | UpVal **v = &G(L)->rootupval; | 287 | TObject **v = &G(L)->rootupval; |
288 | UpVal *curr; | 288 | TObject *curr; |
289 | while ((curr = *v) != NULL) { | 289 | while ((curr = *v) != NULL) { |
290 | if (curr->marked) { | 290 | if (ttype(curr) == LUA_TNIL) { /* was marked? */ |
291 | curr->marked = 0; | 291 | ttype(curr) = LUA_HEAPUPVAL; /* unmark */ |
292 | v = &curr->next; | 292 | v = &vvalue(curr); /* next */ |
293 | } | 293 | } |
294 | else { | 294 | else { |
295 | *v = curr->next; | 295 | lua_assert(ttype(curr) == LUA_HEAPUPVAL); |
296 | luaM_freelem(L, curr); | 296 | *v = vvalue(curr); /* next */ |
297 | luaM_freearray(L, curr, 2, TObject); | ||
297 | } | 298 | } |
298 | } | 299 | } |
299 | } | 300 | } |
@@ -411,8 +412,11 @@ void luaC_collect (lua_State *L, int all) { | |||
411 | 412 | ||
412 | 413 | ||
413 | void luaC_collectgarbage (lua_State *L) { | 414 | void luaC_collectgarbage (lua_State *L) { |
414 | markall(L); | 415 | GCState st; |
415 | cleartables(G(L)); | 416 | st.tmark = NULL; |
417 | st.toclear = NULL; | ||
418 | markall(L, &st); | ||
419 | cleartables(st.toclear); | ||
416 | luaC_collect(L, 0); | 420 | luaC_collect(L, 0); |
417 | checkMbuffer(L); | 421 | checkMbuffer(L); |
418 | G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ | 422 | G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lobject.h,v 1.114 2001/10/02 16:45:03 roberto Exp $ | 2 | ** $Id: lobject.h,v 1.115 2001/10/25 19:14:14 roberto Exp $ |
3 | ** Type definitions for Lua objects | 3 | ** Type definitions for Lua objects |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -31,8 +31,13 @@ | |||
31 | #define NUM_TAGS 6 | 31 | #define NUM_TAGS 6 |
32 | 32 | ||
33 | 33 | ||
34 | /* extra tag: used locally when moving an upvalue from the stack to the heap */ | 34 | /* |
35 | ** extra tags: | ||
36 | ** first is used locally when moving an upvalue from the stack to the heap; | ||
37 | ** second prefixes upvalues in the heap | ||
38 | */ | ||
35 | #define LUA_TUPVAL 6 | 39 | #define LUA_TUPVAL 6 |
40 | #define LUA_HEAPUPVAL 7 | ||
36 | 41 | ||
37 | 42 | ||
38 | typedef union { | 43 | typedef union { |
@@ -40,7 +45,7 @@ typedef union { | |||
40 | union Udata *u; | 45 | union Udata *u; |
41 | union Closure *cl; | 46 | union Closure *cl; |
42 | struct Table *h; | 47 | struct Table *h; |
43 | struct UpVal *v; | 48 | struct lua_TObject *v; |
44 | lua_Number n; /* LUA_TNUMBER */ | 49 | lua_Number n; /* LUA_TNUMBER */ |
45 | } Value; | 50 | } Value; |
46 | 51 | ||
@@ -81,8 +86,8 @@ typedef struct lua_TObject { | |||
81 | 86 | ||
82 | #define setnilvalue(obj) ((obj)->tt=LUA_TNIL) | 87 | #define setnilvalue(obj) ((obj)->tt=LUA_TNIL) |
83 | 88 | ||
84 | #define setupvalue(obj,x) \ | 89 | #define setupvalue(obj,x,t) \ |
85 | { TObject *_o=(obj); _o->tt=LUA_TUPVAL; _o->value.v=(x); } | 90 | { TObject *_o=(obj); _o->tt=(t); _o->value.v=(x); } |
86 | 91 | ||
87 | #define setobj(obj1,obj2) \ | 92 | #define setobj(obj1,obj2) \ |
88 | { TObject *o1=(obj1); const TObject *o2=(obj2); \ | 93 | { TObject *o1=(obj1); const TObject *o2=(obj2); \ |
@@ -165,13 +170,15 @@ typedef struct LocVar { | |||
165 | 170 | ||
166 | 171 | ||
167 | /* | 172 | /* |
168 | ** Upvalues in the heap | 173 | ** Upvalues in the heap. There is a small trick here: to allow a closure to |
174 | ** diferentiate between upvalues in the heap and in the stack, upvalues in | ||
175 | ** the heap always have another TObject before them (like those in the stack), | ||
176 | ** but those `prefix' objects have a tag that cannot happen in the stack. | ||
177 | ** Moreover, we use these extra `prexif' object to store GC-related | ||
178 | ** information. | ||
169 | */ | 179 | */ |
170 | typedef struct UpVal { | 180 | |
171 | TObject val; | 181 | #define isclosed(u) (ttype((u)-1) == LUA_HEAPUPVAL) |
172 | struct UpVal *next; | ||
173 | int marked; | ||
174 | } UpVal; | ||
175 | 182 | ||
176 | 183 | ||
177 | /* | 184 | /* |
@@ -188,20 +195,16 @@ typedef struct CClosure { | |||
188 | } CClosure; | 195 | } CClosure; |
189 | 196 | ||
190 | 197 | ||
191 | typedef struct LClosureEntry { | ||
192 | TObject *val; | ||
193 | UpVal *heap; /* NULL when upvalue is still in the stack */ | ||
194 | } LClosureEntry; | ||
195 | |||
196 | typedef struct LClosure { | 198 | typedef struct LClosure { |
197 | lu_byte isC; | 199 | lu_byte isC; |
198 | lu_byte nupvalues; | 200 | lu_byte nupvalues; |
199 | lu_byte marked; | 201 | lu_byte marked; |
200 | union Closure *next; /* first four fields must be equal to CClosure!! */ | 202 | union Closure *next; /* first four fields must be equal to CClosure!! */ |
201 | struct Proto *p; | 203 | struct Proto *p; |
202 | LClosureEntry upvals[1]; | 204 | TObject *upvals[1]; |
203 | } LClosure; | 205 | } LClosure; |
204 | 206 | ||
207 | |||
205 | typedef union Closure { | 208 | typedef union Closure { |
206 | CClosure c; | 209 | CClosure c; |
207 | LClosure l; | 210 | LClosure l; |
@@ -212,7 +215,6 @@ typedef union Closure { | |||
212 | 215 | ||
213 | 216 | ||
214 | 217 | ||
215 | |||
216 | /* | 218 | /* |
217 | ** Tables | 219 | ** Tables |
218 | */ | 220 | */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 1.196 2001/10/25 19:14:14 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 1.197 2001/10/31 19:58:11 roberto Exp $ |
3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -391,8 +391,8 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { | |||
391 | } | 391 | } |
392 | case OP_GETUPVAL: { | 392 | case OP_GETUPVAL: { |
393 | int b = GETARG_B(i); | 393 | int b = GETARG_B(i); |
394 | lua_assert(cl->upvals[b].heap || cl->upvals[b].val < base); | 394 | lua_assert(isclosed(cl->upvals[b]) || cl->upvals[b] < base); |
395 | setobj(ra, cl->upvals[b].val); | 395 | setobj(ra, cl->upvals[b]); |
396 | break; | 396 | break; |
397 | } | 397 | } |
398 | case OP_GETGLOBAL: { | 398 | case OP_GETGLOBAL: { |
@@ -411,8 +411,8 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { | |||
411 | } | 411 | } |
412 | case OP_SETUPVAL: { | 412 | case OP_SETUPVAL: { |
413 | int b = GETARG_B(i); | 413 | int b = GETARG_B(i); |
414 | lua_assert(cl->upvals[b].heap || cl->upvals[b].val < base); | 414 | lua_assert(isclosed(cl->upvals[b]) || cl->upvals[b] < base); |
415 | setobj(cl->upvals[b].val, ra); | 415 | setobj(cl->upvals[b], ra); |
416 | break; | 416 | break; |
417 | } | 417 | } |
418 | case OP_SETTABLE: { | 418 | case OP_SETTABLE: { |
@@ -649,8 +649,7 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { | |||
649 | ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)]; | 649 | ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)]; |
650 | else { | 650 | else { |
651 | lua_assert(GET_OPCODE(*pc) == OP_MOVE); | 651 | lua_assert(GET_OPCODE(*pc) == OP_MOVE); |
652 | ncl->l.upvals[j].heap = NULL; | 652 | ncl->l.upvals[j] = base + GETARG_B(*pc); |
653 | ncl->l.upvals[j].val = base + GETARG_B(*pc); | ||
654 | } | 653 | } |
655 | } | 654 | } |
656 | luaF_LConlist(L, ncl); | 655 | luaF_LConlist(L, ncl); |