From fabe4ec487cb034ef983a29c52df2927be463d3c Mon Sep 17 00:00:00 2001
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Mon, 7 Jun 2010 13:55:34 -0300
Subject: better barrier for prototypes

---
 lgc.c | 48 ++++++++++++++++++++----------------------------
 lgc.h |  8 ++++----
 lvm.c | 10 ++++++----
 3 files changed, 30 insertions(+), 36 deletions(-)

diff --git a/lgc.c b/lgc.c
index bf36d025..dd6af6c5 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.97 2010/06/02 18:36:58 roberto Exp roberto $
+** $Id: lgc.c,v 2.98 2010/06/04 13:25:10 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -157,14 +157,24 @@ void luaC_barrierback_ (lua_State *L, GCObject *o) {
 
 
 /*
-** barrier for prototypes
+** barrier for prototypes. When creating first closure (cache is
+** NULL), use a forward barrier; this may be the only closure of the
+** prototype (if it is a "regular" function, with a single instance)
+** and the prototype may be big, so it is better to avoid traversing
+** it again. Otherwise, use a backward barrier, to avoid marking all
+** possible instances.
 */
-LUAI_FUNC void luaC_barrierproto_ (lua_State *L, GCObject *p) {
+LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c) {
   global_State *g = G(L);
-  lua_assert(isblack(p));
-  black2gray(p);  /* make object gray (again) */
-  gco2p(p)->gclist = g->clearcache;
-  g->clearcache = p;
+  lua_assert(isblack(obj2gco(p)));
+  if (p->cache == NULL) {  /* first time? */
+    luaC_objbarrier(L, p, c);
+  }
+  else {  /* use a backward barrier */
+    black2gray(obj2gco(p));  /* make prototype gray (again) */
+    p->gclist = g->grayagain;
+    g->grayagain = obj2gco(p);
+  }
 }
 
 
@@ -312,7 +322,7 @@ static void remarkupvals (global_State *g) {
 static void markroot (lua_State *L) {
   global_State *g = G(L);
   g->gray = g->grayagain = NULL;
-  g->weak = g->allweak = g->ephemeron = g->clearcache = NULL;
+  g->weak = g->allweak = g->ephemeron = NULL;
   markobject(g, g->mainthread);
   markvalue(g, &g->l_registry);
   markmt(g);
@@ -422,19 +432,10 @@ static int traversetable (global_State *g, Table *h) {
 }
 
 
-/*
-** if prototype's cached closure is not marked, erase it so it
-** can be collected
-*/
-static void checkcache (Proto *p) {
-  if (p->cache && iswhite(obj2gco(p->cache)))
-    p->cache = NULL;  /* allow cache to be collected */
-}
-
-
 static int traverseproto (global_State *g, Proto *f) {
   int i;
-  checkcache(f);
+  if (f->cache && iswhite(obj2gco(f->cache)))
+    f->cache = NULL;  /* allow cache to be collected */
   stringmark(f->source);
   for (i = 0; i < f->sizek; i++)  /* mark literals */
     markvalue(g, &f->k[i]);
@@ -557,14 +558,6 @@ static void convergeephemerons (global_State *g) {
 ** =======================================================
 */
 
-/*
-** clear cache field in all prototypes in list 'l'
-*/
-static void clearproto (GCObject *l) {
-  for (; l != NULL; l = gco2p(l)->gclist)
-    checkcache(gco2p(l));
-}
-
 
 /*
 ** clear collected entries from all weaktables in list 'l'
@@ -878,7 +871,6 @@ static void atomic (lua_State *L) {
   cleartable(g->weak);
   cleartable(g->ephemeron);
   cleartable(g->allweak);
-  clearproto(g->clearcache);
   g->sweepstrgc = 0;  /* prepare to sweep strings */
   g->gcstate = GCSsweepstring;
   g->currentwhite = cast_byte(otherwhite(g));  /* flip current white */
diff --git a/lgc.h b/lgc.h
index fa007969..191adfeb 100644
--- a/lgc.h
+++ b/lgc.h
@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.h,v 2.41 2010/05/10 18:23:45 roberto Exp roberto $
+** $Id: lgc.h,v 2.42 2010/06/04 13:25:10 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -124,8 +124,8 @@
 #define luaC_objbarrierback(L,p,o)  \
    { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) luaC_barrierback_(L,p); }
 
-#define luaC_barrierproto(L,p) \
-   { if (isblack(obj2gco(p))) luaC_barrierproto_(L,p); }
+#define luaC_barrierproto(L,p,c) \
+   { if (isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); }
 
 LUAI_FUNC void luaC_separateudata (lua_State *L, int all);
 LUAI_FUNC void luaC_freeallobjects (lua_State *L);
@@ -136,7 +136,7 @@ LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz,
                                  GCObject **list, int offset);
 LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
 LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
-LUAI_FUNC void luaC_barrierproto_ (lua_State *L, GCObject *p);
+LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c);
 LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u);
 LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv);
 LUAI_FUNC void luaC_changemode (lua_State *L, int mode);
diff --git a/lvm.c b/lvm.c
index 3a66e0aa..8361d3dd 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.120 2010/05/13 19:53:05 roberto Exp roberto $
+** $Id: lvm.c,v 2.121 2010/06/04 13:25:10 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -368,7 +368,9 @@ static Closure *getcached (Proto *p, UpVal **encup, StkId base) {
 
 /*
 ** create a new Lua closure, push it in the stack, and initialize
-** its upvalues
+** its upvalues. Note that the call to 'luaC_barrierproto' must come
+** before the assignment to 'p->cache', as the function needs the
+** orginal value of that field.
 */
 static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
                          StkId ra) {
@@ -383,8 +385,8 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
     else  /* get upvalue from enclosing function */
       ncl->l.upvals[i] = encup[uv[i].idx];
   }
-  p->cache = ncl;  /* save it on cache, so it can be reused */
-  luaC_barrierproto(L, obj2gco(p));
+  luaC_barrierproto(L, p, ncl);
+  p->cache = ncl;  /* save it on cache for reuse */
 }
 
 
-- 
cgit v1.2.3-55-g6feb