Browse Source

new implementation for lua upvalues (sugested by E.T.): simpler and solves
a bug for multi-stacks

Roberto Ierusalimschy 24 years ago
parent
commit
413fc7334b
8 changed files with 67 additions and 112 deletions
  1. 0 1
      ldo.c
  2. 23 59
      lfunc.c
  3. 1 1
      lfunc.h
  4. 20 30
      lgc.c
  5. 10 10
      lobject.h
  6. 6 1
      lstate.c
  7. 4 4
      lstate.h
  8. 3 6
      lvm.c

+ 0 - 1
ldo.c

@@ -215,7 +215,6 @@ static void f_parser (lua_State *L, void *ud) {
   Proto *tf = p->bin ? luaU_undump(L, p->z) : luaY_parser(L, p->z);
   Closure *cl = luaF_newLclosure(L, 0);
   cl->l.p = tf;
-  luaF_LConlist(L, cl);
   setclvalue(L->top, cl);
   incr_top;
 }

+ 23 - 59
lfunc.c

@@ -22,6 +22,7 @@
                          cast(int, sizeof(TObject *)*((n)-1)))
 
 
+
 Closure *luaF_newCclosure (lua_State *L, int nelems) {
   Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems)));
   c->c.isC = 1;
@@ -36,76 +37,39 @@ Closure *luaF_newCclosure (lua_State *L, int nelems) {
 Closure *luaF_newLclosure (lua_State *L, int nelems) {
   Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems)));
   c->l.isC = 0;
+  c->c.next = G(L)->rootcl;
+  G(L)->rootcl = c;
   c->l.marked = 0;
   c->l.nupvalues = nelems;
   return c;
 }
 
 
-/*
-** returns the open pointer in a closure that points higher into the stack
-*/
-static StkId uppoint (LClosure *cl) {
-  StkId lp = NULL;
-  int i;
-  for (i=0; i<cl->nupvalues; i++) {
-    if (!isclosed(cl->upvals[i]) && (lp == NULL || cl->upvals[i] > lp))
-      lp = cl->upvals[i];
-  }
-  return lp;
-}
-
-
-void luaF_LConlist (lua_State *L, Closure *cl) {
-  StkId cli = uppoint(&cl->l);
-  if (cli == NULL) {  /* no more open entries? */
-    cl->l.next = G(L)->rootcl;  /* insert in final list */
-    G(L)->rootcl = cl;
-  }
-  else {  /* insert in list of open closures, ordered by decreasing uppoints */
-    Closure **p = &L->opencl;
-    while (*p != NULL && uppoint(&(*p)->l) > cli) p = &(*p)->l.next;
-    cl->l.next = *p;
-    *p = cl;
+UpVal *luaF_findupval (lua_State *L, StkId level) {
+  UpVal **pp = &L->openupval;
+  UpVal *p;
+  while ((p = *pp) != NULL && p->v >= level) {
+    if (p->v == level) return p;
+    pp = &p->next;
   }
-}
-
-
-static int closeCl (lua_State *L, LClosure *cl, StkId level) {
-  int got = 0;  /* flag: 1 if some pointer in the closure was corrected */
-  int i;
-  for  (i=0; i<cl->nupvalues; i++) {
-    StkId var;
-    if (!isclosed(cl->upvals[i]) && (var=cl->upvals[i]) >= level) {
-      if (ttype(var) != LUA_TUPVAL) {
-        TObject *v = luaM_newvector(L, 2, TObject);
-        v[1] = *var;
-        setupvalue(v, G(L)->rootupval, LUA_HEAPUPVAL);
-        G(L)->rootupval = v;
-        setupvalue(var, &v[1], LUA_TUPVAL);
-      }
-      cl->upvals[i] = vvalue(var);
-      got = 1;
-    }
-  }
-  return got;
+  p = luaM_new(L, UpVal);  /* not found: create a new one */
+  p->v = level;  /* current value lives in the stack */
+  p->mark = 1;  /* won't participate in GC while open */
+  p->next = *pp;  /* chain it in the proper position */
+  *pp = p;
+  return p;
 }
 
 
 void luaF_close (lua_State *L, StkId level) {
-  Closure *affected = NULL;  /* closures with open pointers >= level */
-  Closure *cl;
-  while ((cl=L->opencl) != NULL) {
-    if (!closeCl(L, cast(LClosure *, cl), level)) break;
-    /* some pointer in `cl' changed; will re-insert it in original list */
-    L->opencl = cl->l.next;  /* remove from original list */
-    cl->l.next = affected;
-    affected = cl;  /* insert in affected list */
-  }
-  /* re-insert all affected closures in original list */
-  while ((cl=affected) != NULL) {
-    affected = cl->l.next;
-    luaF_LConlist(L, cl);
+  UpVal *p;
+  while ((p = L->openupval) != NULL && p->v >= level) {
+    setobj(&p->value, p->v);  /* save current value */
+    p->v = &p->value;  /* now current value lives here */
+    L->openupval = p->next;  /* remove from `open' list */
+    p->next = G(L)->rootupval;  /* chain in `closed' list */
+    p->mark = 0;  /* now it can be collected */
+    G(L)->rootupval = p;
   }
 }
 

+ 1 - 1
lfunc.h

@@ -14,7 +14,7 @@
 Proto *luaF_newproto (lua_State *L);
 Closure *luaF_newCclosure (lua_State *L, int nelems);
 Closure *luaF_newLclosure (lua_State *L, int nelems);
-void luaF_LConlist (lua_State *L, Closure *cl);
+UpVal *luaF_findupval (lua_State *L, StkId level);
 void luaF_close (lua_State *L, StkId level);
 void luaF_freeproto (lua_State *L, Proto *f);
 void luaF_freeclosure (lua_State *L, Closure *c);

+ 20 - 30
lgc.c

@@ -65,10 +65,10 @@ static void markclosure (GCState *st, Closure *cl) {
       lua_assert(cl->l.nupvalues == cl->l.p->nupvalues);
       protomark(cl->l.p);
       for (i=0; i<cl->l.nupvalues; i++) {  /* mark its upvalues */
-        TObject *u = cl->l.upvals[i];
-        if (isclosed(u)) {
-          ttype(u-1) = LUA_TNIL;  /* temporary value (to mark as visited) */
-          markobject(st, u);
+        UpVal *u = cl->l.upvals[i];
+        if (!u->mark) {
+          u->mark = 1;
+          markobject(st, u->v);
         }
       }
     }
@@ -101,7 +101,7 @@ static void markobject (GCState *st, TObject *o) {
       break;
     }
     default: {
-      lua_assert(0 <= ttype(o) && ttype(o) <= LUA_TUPVAL);
+      lua_assert(ttype(o) == LUA_TNIL || ttype(o) == LUA_TNUMBER);
       break;
     }
   }
@@ -241,7 +241,8 @@ static void collectproto (lua_State *L) {
 }
 
 
-static void collectclosure (lua_State *L, Closure **p) {
+static void collectclosures (lua_State *L) {
+  Closure **p = &G(L)->rootcl;
   Closure *curr;
   while ((curr = *p) != NULL) {
     if (curr->c.marked) {
@@ -256,13 +257,19 @@ static void collectclosure (lua_State *L, Closure **p) {
 }
 
 
-static void collectclosures (lua_State *L) {
-  lua_State *L1 = L;
-  do {  /* for each thread */
-    collectclosure(L1, &L1->opencl);
-    L1 = L1->next;
-  } while (L1 != L);
-  collectclosure(L, &G(L)->rootcl);
+static void collectupval (lua_State *L) {
+  UpVal **v = &G(L)->rootupval;
+  UpVal *curr;
+  while ((curr = *v) != NULL) {
+    if (curr->mark) {
+      curr->mark = 0;
+      v = &curr->next;  /* next */
+    }
+    else {
+      *v = curr->next;  /* next */
+      luaM_freelem(L, curr);
+    }
+  }
 }
 
 
@@ -282,23 +289,6 @@ static void collecttable (lua_State *L) {
 }
 
 
-static void collectupval (lua_State *L) {
-  TObject **v = &G(L)->rootupval;
-  TObject *curr;
-  while ((curr = *v) != NULL) {
-    if (ttype(curr) == LUA_TNIL) {  /* was marked? */
-      ttype(curr) = LUA_HEAPUPVAL;  /* unmark */
-      v = &vvalue(curr);  /* next */
-    }
-    else {
-      lua_assert(ttype(curr) == LUA_HEAPUPVAL);
-      *v = vvalue(curr);  /* next */
-      luaM_freearray(L, curr, 2, TObject);
-    }
-  }
-}
-
-
 static void collectudata (lua_State *L, int keep) {
   Udata **p = &G(L)->rootudata;
   Udata *curr;

+ 10 - 10
lobject.h

@@ -170,15 +170,15 @@ typedef struct LocVar {
 
 
 /*
-** Upvalues in the heap. There is a small trick here: to allow a closure to
-** diferentiate between upvalues in the heap and in the stack, upvalues in
-** the heap always have another TObject before them (like those in the stack),
-** but those `prefix' objects have a tag that cannot happen in the stack.
-** Moreover, we use these extra `prexif' object to store GC-related
-** information.
+** Upvalues
 */
 
-#define isclosed(u)	(ttype((u)-1) == LUA_HEAPUPVAL)
+typedef struct UpVal {
+  TObject *v;  /* points to stack or to its own value */
+  int mark;
+  struct UpVal *next;
+  TObject value;  /* the value (when closed) */
+} UpVal;
 
 
 /*
@@ -201,7 +201,7 @@ typedef struct LClosure {
   lu_byte marked;
   union Closure *next;  /* first four fields must be equal to CClosure!! */
   struct Proto *p;
-  TObject *upvals[1];
+  UpVal *upvals[1];
 } LClosure;
 
 
@@ -221,8 +221,8 @@ typedef union Closure {
 
 typedef struct Node {
   struct Node *next;  /* for chaining */
-  TObject key;
-  TObject val;
+  TObject _key;
+  TObject _val;
 } Node;
 
 

+ 6 - 1
lstate.c

@@ -10,6 +10,7 @@
 #include "lua.h"
 
 #include "ldo.h"
+#include "lfunc.h"
 #include "lgc.h"
 #include "llex.h"
 #include "lmem.h"
@@ -88,7 +89,7 @@ LUA_API lua_State *lua_newthread (lua_State *OL, int stacksize) {
     L->errorJmp = NULL;
     L->callhook = NULL;
     L->linehook = NULL;
-    L->opencl = NULL;
+    L->openupval = NULL;
     L->allowhooks = 1;
     L->next = L->previous = L;
     so.stacksize = stacksize;
@@ -105,6 +106,8 @@ LUA_API lua_State *lua_newthread (lua_State *OL, int stacksize) {
 
 
 static void close_state (lua_State *L, lua_State *OL) {
+  luaF_close(L, L->stack);  /* close all upvalues for this thread */
+  lua_assert(L->openupval == NULL);
   if (OL != NULL) {  /* are there other threads? */
     lua_assert(L->previous != L);
     L->previous->next = L->next;
@@ -116,6 +119,7 @@ static void close_state (lua_State *L, lua_State *OL) {
     lua_assert(G(L)->rootproto == NULL);
     lua_assert(G(L)->rootudata == NULL);
     lua_assert(G(L)->rootcl == NULL);
+    lua_assert(G(L)->rootupval == NULL);
     lua_assert(G(L)->roottable == NULL);
     luaS_freeall(L);
     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) {
   luaM_freelem(OL, L);
 }
 
+
 LUA_API void lua_close (lua_State *L) {
   lua_State *OL;
   lua_assert(L != lua_state || lua_gettop(L) == 0);

+ 4 - 4
lstate.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.h,v 1.63 2001/10/31 19:58:11 roberto Exp $
+** $Id: lstate.h,v 1.64 2001/11/06 21:40:51 roberto Exp $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -65,10 +65,10 @@ typedef struct global_State {
   lu_mem GCthreshold;
   lu_mem nblocks;  /* number of `bytes' currently allocated */
   Proto *rootproto;  /* list of all prototypes */
-  Closure *rootcl;  /* list of all C closures and closed Lua closures */
+  Closure *rootcl;  /* list of all closures */
   Table *roottable;  /* list of all tables */
   Udata *rootudata;   /* list of all userdata */
-  TObject *rootupval;  /* list of all up values */
+  UpVal *rootupval;  /* list of closed up values */
 } global_State;
 
 
@@ -88,7 +88,7 @@ struct lua_State {
   lua_Hook linehook;
   int allowhooks;
   struct lua_longjmp *errorJmp;  /* current error recover point */
-  Closure *opencl;  /* list of closures still pointing to this stack */
+  UpVal *openupval;  /* list of open upvalues in this stack */
   lua_State *next;  /* circular double linked list of states */
   lua_State *previous;
   CallInfo basefunc;

+ 3 - 6
lvm.c

@@ -390,8 +390,7 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) {
       }
       case OP_GETUPVAL: {
         int b = GETARG_B(i);
-        lua_assert(isclosed(cl->upvals[b]) || cl->upvals[b] < base);
-        setobj(ra, cl->upvals[b]);
+        setobj(ra, cl->upvals[b]->v);
         break;
       }
       case OP_GETGLOBAL: {
@@ -410,8 +409,7 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) {
       }
       case OP_SETUPVAL: {
         int b = GETARG_B(i);
-        lua_assert(isclosed(cl->upvals[b]) || cl->upvals[b] < base);
-        setobj(cl->upvals[b], ra);
+        setobj(cl->upvals[b]->v, ra);
         break;
       }
       case OP_SETTABLE: {
@@ -648,10 +646,9 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) {
             ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)];
           else {
             lua_assert(GET_OPCODE(*pc) == OP_MOVE);
-            ncl->l.upvals[j] = base + GETARG_B(*pc);
+            ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc));
           }
         }
-        luaF_LConlist(L, ncl);
         setclvalue(ra, ncl);
         break;
       }