diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2001-11-29 18:22:22 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2001-11-29 18:22:22 -0200 |
commit | 413fc7334bf8ceaea71417d73edef15c99d3a793 (patch) | |
tree | 50e762d979ad8e80681902cdeb8aa42b041ae323 | |
parent | fca0a12e23f964006ce43d35ab86b27c6bbb0a48 (diff) | |
download | lua-413fc7334bf8ceaea71417d73edef15c99d3a793.tar.gz lua-413fc7334bf8ceaea71417d73edef15c99d3a793.tar.bz2 lua-413fc7334bf8ceaea71417d73edef15c99d3a793.zip |
new implementation for lua upvalues (sugested by E.T.): simpler and solves
a bug for multi-stacks
-rw-r--r-- | ldo.c | 1 | ||||
-rw-r--r-- | lfunc.c | 82 | ||||
-rw-r--r-- | lfunc.h | 2 | ||||
-rw-r--r-- | lgc.c | 50 | ||||
-rw-r--r-- | lobject.h | 20 | ||||
-rw-r--r-- | lstate.c | 7 | ||||
-rw-r--r-- | lstate.h | 8 | ||||
-rw-r--r-- | lvm.c | 9 |
8 files changed, 67 insertions, 112 deletions
@@ -215,7 +215,6 @@ static void f_parser (lua_State *L, void *ud) { | |||
215 | Proto *tf = p->bin ? luaU_undump(L, p->z) : luaY_parser(L, p->z); | 215 | Proto *tf = p->bin ? luaU_undump(L, p->z) : luaY_parser(L, p->z); |
216 | Closure *cl = luaF_newLclosure(L, 0); | 216 | Closure *cl = luaF_newLclosure(L, 0); |
217 | cl->l.p = tf; | 217 | cl->l.p = tf; |
218 | luaF_LConlist(L, cl); | ||
219 | setclvalue(L->top, cl); | 218 | setclvalue(L->top, cl); |
220 | incr_top; | 219 | incr_top; |
221 | } | 220 | } |
@@ -22,6 +22,7 @@ | |||
22 | cast(int, sizeof(TObject *)*((n)-1))) | 22 | cast(int, sizeof(TObject *)*((n)-1))) |
23 | 23 | ||
24 | 24 | ||
25 | |||
25 | Closure *luaF_newCclosure (lua_State *L, int nelems) { | 26 | Closure *luaF_newCclosure (lua_State *L, int nelems) { |
26 | Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); | 27 | Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); |
27 | c->c.isC = 1; | 28 | c->c.isC = 1; |
@@ -36,76 +37,39 @@ Closure *luaF_newCclosure (lua_State *L, int nelems) { | |||
36 | Closure *luaF_newLclosure (lua_State *L, int nelems) { | 37 | Closure *luaF_newLclosure (lua_State *L, int nelems) { |
37 | Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); | 38 | Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); |
38 | c->l.isC = 0; | 39 | c->l.isC = 0; |
40 | c->c.next = G(L)->rootcl; | ||
41 | G(L)->rootcl = c; | ||
39 | c->l.marked = 0; | 42 | c->l.marked = 0; |
40 | c->l.nupvalues = nelems; | 43 | c->l.nupvalues = nelems; |
41 | return c; | 44 | return c; |
42 | } | 45 | } |
43 | 46 | ||
44 | 47 | ||
45 | /* | 48 | UpVal *luaF_findupval (lua_State *L, StkId level) { |
46 | ** returns the open pointer in a closure that points higher into the stack | 49 | UpVal **pp = &L->openupval; |
47 | */ | 50 | UpVal *p; |
48 | static StkId uppoint (LClosure *cl) { | 51 | while ((p = *pp) != NULL && p->v >= level) { |
49 | StkId lp = NULL; | 52 | if (p->v == level) return p; |
50 | int i; | 53 | pp = &p->next; |
51 | for (i=0; i<cl->nupvalues; i++) { | ||
52 | if (!isclosed(cl->upvals[i]) && (lp == NULL || cl->upvals[i] > lp)) | ||
53 | lp = cl->upvals[i]; | ||
54 | } | ||
55 | return lp; | ||
56 | } | ||
57 | |||
58 | |||
59 | void luaF_LConlist (lua_State *L, Closure *cl) { | ||
60 | StkId cli = uppoint(&cl->l); | ||
61 | if (cli == NULL) { /* no more open entries? */ | ||
62 | cl->l.next = G(L)->rootcl; /* insert in final list */ | ||
63 | G(L)->rootcl = cl; | ||
64 | } | ||
65 | else { /* insert in list of open closures, ordered by decreasing uppoints */ | ||
66 | Closure **p = &L->opencl; | ||
67 | while (*p != NULL && uppoint(&(*p)->l) > cli) p = &(*p)->l.next; | ||
68 | cl->l.next = *p; | ||
69 | *p = cl; | ||
70 | } | 54 | } |
71 | } | 55 | p = luaM_new(L, UpVal); /* not found: create a new one */ |
72 | 56 | p->v = level; /* current value lives in the stack */ | |
73 | 57 | p->mark = 1; /* won't participate in GC while open */ | |
74 | static int closeCl (lua_State *L, LClosure *cl, StkId level) { | 58 | p->next = *pp; /* chain it in the proper position */ |
75 | int got = 0; /* flag: 1 if some pointer in the closure was corrected */ | 59 | *pp = p; |
76 | int i; | 60 | return p; |
77 | for (i=0; i<cl->nupvalues; i++) { | ||
78 | StkId var; | ||
79 | if (!isclosed(cl->upvals[i]) && (var=cl->upvals[i]) >= level) { | ||
80 | if (ttype(var) != LUA_TUPVAL) { | ||
81 | TObject *v = luaM_newvector(L, 2, TObject); | ||
82 | v[1] = *var; | ||
83 | setupvalue(v, G(L)->rootupval, LUA_HEAPUPVAL); | ||
84 | G(L)->rootupval = v; | ||
85 | setupvalue(var, &v[1], LUA_TUPVAL); | ||
86 | } | ||
87 | cl->upvals[i] = vvalue(var); | ||
88 | got = 1; | ||
89 | } | ||
90 | } | ||
91 | return got; | ||
92 | } | 61 | } |
93 | 62 | ||
94 | 63 | ||
95 | void luaF_close (lua_State *L, StkId level) { | 64 | void luaF_close (lua_State *L, StkId level) { |
96 | Closure *affected = NULL; /* closures with open pointers >= level */ | 65 | UpVal *p; |
97 | Closure *cl; | 66 | while ((p = L->openupval) != NULL && p->v >= level) { |
98 | while ((cl=L->opencl) != NULL) { | 67 | setobj(&p->value, p->v); /* save current value */ |
99 | if (!closeCl(L, cast(LClosure *, cl), level)) break; | 68 | p->v = &p->value; /* now current value lives here */ |
100 | /* some pointer in `cl' changed; will re-insert it in original list */ | 69 | L->openupval = p->next; /* remove from `open' list */ |
101 | L->opencl = cl->l.next; /* remove from original list */ | 70 | p->next = G(L)->rootupval; /* chain in `closed' list */ |
102 | cl->l.next = affected; | 71 | p->mark = 0; /* now it can be collected */ |
103 | affected = cl; /* insert in affected list */ | 72 | G(L)->rootupval = p; |
104 | } | ||
105 | /* re-insert all affected closures in original list */ | ||
106 | while ((cl=affected) != NULL) { | ||
107 | affected = cl->l.next; | ||
108 | luaF_LConlist(L, cl); | ||
109 | } | 73 | } |
110 | } | 74 | } |
111 | 75 | ||
@@ -14,7 +14,7 @@ | |||
14 | Proto *luaF_newproto (lua_State *L); | 14 | Proto *luaF_newproto (lua_State *L); |
15 | Closure *luaF_newCclosure (lua_State *L, int nelems); | 15 | Closure *luaF_newCclosure (lua_State *L, int nelems); |
16 | Closure *luaF_newLclosure (lua_State *L, int nelems); | 16 | Closure *luaF_newLclosure (lua_State *L, int nelems); |
17 | void luaF_LConlist (lua_State *L, Closure *cl); | 17 | UpVal *luaF_findupval (lua_State *L, StkId level); |
18 | void luaF_close (lua_State *L, StkId level); | 18 | void luaF_close (lua_State *L, StkId level); |
19 | void luaF_freeproto (lua_State *L, Proto *f); | 19 | void luaF_freeproto (lua_State *L, Proto *f); |
20 | void luaF_freeclosure (lua_State *L, Closure *c); | 20 | void luaF_freeclosure (lua_State *L, Closure *c); |
@@ -65,10 +65,10 @@ static void markclosure (GCState *st, Closure *cl) { | |||
65 | lua_assert(cl->l.nupvalues == cl->l.p->nupvalues); | 65 | lua_assert(cl->l.nupvalues == cl->l.p->nupvalues); |
66 | protomark(cl->l.p); | 66 | protomark(cl->l.p); |
67 | for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ | 67 | for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ |
68 | TObject *u = cl->l.upvals[i]; | 68 | UpVal *u = cl->l.upvals[i]; |
69 | if (isclosed(u)) { | 69 | if (!u->mark) { |
70 | ttype(u-1) = LUA_TNIL; /* temporary value (to mark as visited) */ | 70 | u->mark = 1; |
71 | markobject(st, u); | 71 | markobject(st, u->v); |
72 | } | 72 | } |
73 | } | 73 | } |
74 | } | 74 | } |
@@ -101,7 +101,7 @@ static void markobject (GCState *st, TObject *o) { | |||
101 | break; | 101 | break; |
102 | } | 102 | } |
103 | default: { | 103 | default: { |
104 | lua_assert(0 <= ttype(o) && ttype(o) <= LUA_TUPVAL); | 104 | lua_assert(ttype(o) == LUA_TNIL || ttype(o) == LUA_TNUMBER); |
105 | break; | 105 | break; |
106 | } | 106 | } |
107 | } | 107 | } |
@@ -241,7 +241,8 @@ static void collectproto (lua_State *L) { | |||
241 | } | 241 | } |
242 | 242 | ||
243 | 243 | ||
244 | static void collectclosure (lua_State *L, Closure **p) { | 244 | static void collectclosures (lua_State *L) { |
245 | Closure **p = &G(L)->rootcl; | ||
245 | Closure *curr; | 246 | Closure *curr; |
246 | while ((curr = *p) != NULL) { | 247 | while ((curr = *p) != NULL) { |
247 | if (curr->c.marked) { | 248 | if (curr->c.marked) { |
@@ -256,13 +257,19 @@ static void collectclosure (lua_State *L, Closure **p) { | |||
256 | } | 257 | } |
257 | 258 | ||
258 | 259 | ||
259 | static void collectclosures (lua_State *L) { | 260 | static void collectupval (lua_State *L) { |
260 | lua_State *L1 = L; | 261 | UpVal **v = &G(L)->rootupval; |
261 | do { /* for each thread */ | 262 | UpVal *curr; |
262 | collectclosure(L1, &L1->opencl); | 263 | while ((curr = *v) != NULL) { |
263 | L1 = L1->next; | 264 | if (curr->mark) { |
264 | } while (L1 != L); | 265 | curr->mark = 0; |
265 | collectclosure(L, &G(L)->rootcl); | 266 | v = &curr->next; /* next */ |
267 | } | ||
268 | else { | ||
269 | *v = curr->next; /* next */ | ||
270 | luaM_freelem(L, curr); | ||
271 | } | ||
272 | } | ||
266 | } | 273 | } |
267 | 274 | ||
268 | 275 | ||
@@ -282,23 +289,6 @@ static void collecttable (lua_State *L) { | |||
282 | } | 289 | } |
283 | 290 | ||
284 | 291 | ||
285 | static void collectupval (lua_State *L) { | ||
286 | TObject **v = &G(L)->rootupval; | ||
287 | TObject *curr; | ||
288 | while ((curr = *v) != NULL) { | ||
289 | if (ttype(curr) == LUA_TNIL) { /* was marked? */ | ||
290 | ttype(curr) = LUA_HEAPUPVAL; /* unmark */ | ||
291 | v = &vvalue(curr); /* next */ | ||
292 | } | ||
293 | else { | ||
294 | lua_assert(ttype(curr) == LUA_HEAPUPVAL); | ||
295 | *v = vvalue(curr); /* next */ | ||
296 | luaM_freearray(L, curr, 2, TObject); | ||
297 | } | ||
298 | } | ||
299 | } | ||
300 | |||
301 | |||
302 | static void collectudata (lua_State *L, int keep) { | 292 | static void collectudata (lua_State *L, int keep) { |
303 | Udata **p = &G(L)->rootudata; | 293 | Udata **p = &G(L)->rootudata; |
304 | Udata *curr; | 294 | Udata *curr; |
@@ -170,15 +170,15 @@ typedef struct LocVar { | |||
170 | 170 | ||
171 | 171 | ||
172 | /* | 172 | /* |
173 | ** Upvalues in the heap. There is a small trick here: to allow a closure to | 173 | ** Upvalues |
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. | ||
179 | */ | 174 | */ |
180 | 175 | ||
181 | #define isclosed(u) (ttype((u)-1) == LUA_HEAPUPVAL) | 176 | typedef struct UpVal { |
177 | TObject *v; /* points to stack or to its own value */ | ||
178 | int mark; | ||
179 | struct UpVal *next; | ||
180 | TObject value; /* the value (when closed) */ | ||
181 | } UpVal; | ||
182 | 182 | ||
183 | 183 | ||
184 | /* | 184 | /* |
@@ -201,7 +201,7 @@ typedef struct LClosure { | |||
201 | lu_byte marked; | 201 | lu_byte marked; |
202 | union Closure *next; /* first four fields must be equal to CClosure!! */ | 202 | union Closure *next; /* first four fields must be equal to CClosure!! */ |
203 | struct Proto *p; | 203 | struct Proto *p; |
204 | TObject *upvals[1]; | 204 | UpVal *upvals[1]; |
205 | } LClosure; | 205 | } LClosure; |
206 | 206 | ||
207 | 207 | ||
@@ -221,8 +221,8 @@ typedef union Closure { | |||
221 | 221 | ||
222 | typedef struct Node { | 222 | typedef struct Node { |
223 | struct Node *next; /* for chaining */ | 223 | struct Node *next; /* for chaining */ |
224 | TObject key; | 224 | TObject _key; |
225 | TObject val; | 225 | TObject _val; |
226 | } Node; | 226 | } Node; |
227 | 227 | ||
228 | 228 | ||
@@ -10,6 +10,7 @@ | |||
10 | #include "lua.h" | 10 | #include "lua.h" |
11 | 11 | ||
12 | #include "ldo.h" | 12 | #include "ldo.h" |
13 | #include "lfunc.h" | ||
13 | #include "lgc.h" | 14 | #include "lgc.h" |
14 | #include "llex.h" | 15 | #include "llex.h" |
15 | #include "lmem.h" | 16 | #include "lmem.h" |
@@ -88,7 +89,7 @@ LUA_API lua_State *lua_newthread (lua_State *OL, int stacksize) { | |||
88 | L->errorJmp = NULL; | 89 | L->errorJmp = NULL; |
89 | L->callhook = NULL; | 90 | L->callhook = NULL; |
90 | L->linehook = NULL; | 91 | L->linehook = NULL; |
91 | L->opencl = NULL; | 92 | L->openupval = NULL; |
92 | L->allowhooks = 1; | 93 | L->allowhooks = 1; |
93 | L->next = L->previous = L; | 94 | L->next = L->previous = L; |
94 | so.stacksize = stacksize; | 95 | so.stacksize = stacksize; |
@@ -105,6 +106,8 @@ LUA_API lua_State *lua_newthread (lua_State *OL, int stacksize) { | |||
105 | 106 | ||
106 | 107 | ||
107 | static void close_state (lua_State *L, lua_State *OL) { | 108 | static void close_state (lua_State *L, lua_State *OL) { |
109 | luaF_close(L, L->stack); /* close all upvalues for this thread */ | ||
110 | lua_assert(L->openupval == NULL); | ||
108 | if (OL != NULL) { /* are there other threads? */ | 111 | if (OL != NULL) { /* are there other threads? */ |
109 | lua_assert(L->previous != L); | 112 | lua_assert(L->previous != L); |
110 | L->previous->next = L->next; | 113 | L->previous->next = L->next; |
@@ -116,6 +119,7 @@ static void close_state (lua_State *L, lua_State *OL) { | |||
116 | lua_assert(G(L)->rootproto == NULL); | 119 | lua_assert(G(L)->rootproto == NULL); |
117 | lua_assert(G(L)->rootudata == NULL); | 120 | lua_assert(G(L)->rootudata == NULL); |
118 | lua_assert(G(L)->rootcl == NULL); | 121 | lua_assert(G(L)->rootcl == NULL); |
122 | lua_assert(G(L)->rootupval == NULL); | ||
119 | lua_assert(G(L)->roottable == NULL); | 123 | lua_assert(G(L)->roottable == NULL); |
120 | luaS_freeall(L); | 124 | luaS_freeall(L); |
121 | luaM_freearray(L, G(L)->TMtable, G(L)->sizeTM, struct TM); | 125 | luaM_freearray(L, G(L)->TMtable, G(L)->sizeTM, struct TM); |
@@ -126,6 +130,7 @@ static void close_state (lua_State *L, lua_State *OL) { | |||
126 | luaM_freelem(OL, L); | 130 | luaM_freelem(OL, L); |
127 | } | 131 | } |
128 | 132 | ||
133 | |||
129 | LUA_API void lua_close (lua_State *L) { | 134 | LUA_API void lua_close (lua_State *L) { |
130 | lua_State *OL; | 135 | lua_State *OL; |
131 | lua_assert(L != lua_state || lua_gettop(L) == 0); | 136 | lua_assert(L != lua_state || lua_gettop(L) == 0); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.h,v 1.63 2001/10/31 19:58:11 roberto Exp $ | 2 | ** $Id: lstate.h,v 1.64 2001/11/06 21:40:51 roberto Exp $ |
3 | ** Global State | 3 | ** Global State |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -65,10 +65,10 @@ typedef struct global_State { | |||
65 | lu_mem GCthreshold; | 65 | lu_mem GCthreshold; |
66 | lu_mem nblocks; /* number of `bytes' currently allocated */ | 66 | lu_mem nblocks; /* number of `bytes' currently allocated */ |
67 | Proto *rootproto; /* list of all prototypes */ | 67 | Proto *rootproto; /* list of all prototypes */ |
68 | Closure *rootcl; /* list of all C closures and closed Lua closures */ | 68 | Closure *rootcl; /* list of all closures */ |
69 | Table *roottable; /* list of all tables */ | 69 | Table *roottable; /* list of all tables */ |
70 | Udata *rootudata; /* list of all userdata */ | 70 | Udata *rootudata; /* list of all userdata */ |
71 | TObject *rootupval; /* list of all up values */ | 71 | UpVal *rootupval; /* list of closed up values */ |
72 | } global_State; | 72 | } global_State; |
73 | 73 | ||
74 | 74 | ||
@@ -88,7 +88,7 @@ struct lua_State { | |||
88 | lua_Hook linehook; | 88 | lua_Hook linehook; |
89 | int allowhooks; | 89 | int allowhooks; |
90 | struct lua_longjmp *errorJmp; /* current error recover point */ | 90 | struct lua_longjmp *errorJmp; /* current error recover point */ |
91 | Closure *opencl; /* list of closures still pointing to this stack */ | 91 | UpVal *openupval; /* list of open upvalues in this stack */ |
92 | lua_State *next; /* circular double linked list of states */ | 92 | lua_State *next; /* circular double linked list of states */ |
93 | lua_State *previous; | 93 | lua_State *previous; |
94 | CallInfo basefunc; | 94 | CallInfo basefunc; |
@@ -390,8 +390,7 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { | |||
390 | } | 390 | } |
391 | case OP_GETUPVAL: { | 391 | case OP_GETUPVAL: { |
392 | int b = GETARG_B(i); | 392 | int b = GETARG_B(i); |
393 | lua_assert(isclosed(cl->upvals[b]) || cl->upvals[b] < base); | 393 | setobj(ra, cl->upvals[b]->v); |
394 | setobj(ra, cl->upvals[b]); | ||
395 | break; | 394 | break; |
396 | } | 395 | } |
397 | case OP_GETGLOBAL: { | 396 | case OP_GETGLOBAL: { |
@@ -410,8 +409,7 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { | |||
410 | } | 409 | } |
411 | case OP_SETUPVAL: { | 410 | case OP_SETUPVAL: { |
412 | int b = GETARG_B(i); | 411 | int b = GETARG_B(i); |
413 | lua_assert(isclosed(cl->upvals[b]) || cl->upvals[b] < base); | 412 | setobj(cl->upvals[b]->v, ra); |
414 | setobj(cl->upvals[b], ra); | ||
415 | break; | 413 | break; |
416 | } | 414 | } |
417 | case OP_SETTABLE: { | 415 | case OP_SETTABLE: { |
@@ -648,10 +646,9 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { | |||
648 | ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)]; | 646 | ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)]; |
649 | else { | 647 | else { |
650 | lua_assert(GET_OPCODE(*pc) == OP_MOVE); | 648 | lua_assert(GET_OPCODE(*pc) == OP_MOVE); |
651 | ncl->l.upvals[j] = base + GETARG_B(*pc); | 649 | ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); |
652 | } | 650 | } |
653 | } | 651 | } |
654 | luaF_LConlist(L, ncl); | ||
655 | setclvalue(ra, ncl); | 652 | setclvalue(ra, ncl); |
656 | break; | 653 | break; |
657 | } | 654 | } |