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 | } |
