aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2010-06-04 10:25:10 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2010-06-04 10:25:10 -0300
commit575074fd857b90cd7c14c7b172e8fe147080962a (patch)
tree6929e87845a56266061235f89213795806ee5291
parent545f43065ff8fa20e5f8254e6270d00694b847dd (diff)
downloadlua-575074fd857b90cd7c14c7b172e8fe147080962a.tar.gz
lua-575074fd857b90cd7c14c7b172e8fe147080962a.tar.bz2
lua-575074fd857b90cd7c14c7b172e8fe147080962a.zip
Lua closures are cached for reuse
-rw-r--r--lfunc.c7
-rw-r--r--lgc.c50
-rw-r--r--lgc.h22
-rw-r--r--lobject.h3
-rw-r--r--lvm.c68
5 files changed, 114 insertions, 36 deletions
diff --git a/lfunc.c b/lfunc.c
index 6c8dda4b..92837f09 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lfunc.c,v 2.23 2010/04/29 21:43:36 roberto Exp roberto $ 2** $Id: lfunc.c,v 2.24 2010/05/10 18:23:45 roberto Exp roberto $
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*/
@@ -29,9 +29,11 @@ Closure *luaF_newCclosure (lua_State *L, int n) {
29} 29}
30 30
31 31
32Closure *luaF_newLclosure (lua_State *L, int n) { 32Closure *luaF_newLclosure (lua_State *L, Proto *p) {
33 int n = p->sizeupvalues;
33 Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeLclosure(n), NULL, 0)->cl; 34 Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeLclosure(n), NULL, 0)->cl;
34 c->l.isC = 0; 35 c->l.isC = 0;
36 c->l.p = p;
35 c->l.nupvalues = cast_byte(n); 37 c->l.nupvalues = cast_byte(n);
36 while (n--) c->l.upvals[n] = NULL; 38 while (n--) c->l.upvals[n] = NULL;
37 return c; 39 return c;
@@ -116,6 +118,7 @@ Proto *luaF_newproto (lua_State *L) {
116 f->p = NULL; 118 f->p = NULL;
117 f->sizep = 0; 119 f->sizep = 0;
118 f->code = NULL; 120 f->code = NULL;
121 f->cache = NULL;
119 f->sizecode = 0; 122 f->sizecode = 0;
120 f->lineinfo = NULL; 123 f->lineinfo = NULL;
121 f->sizelineinfo = 0; 124 f->sizelineinfo = 0;
diff --git a/lgc.c b/lgc.c
index 552164b5..bf36d025 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 2.96 2010/05/17 20:39:31 roberto Exp roberto $ 2** $Id: lgc.c,v 2.97 2010/06/02 18:36:58 roberto Exp roberto $
3** Garbage Collector 3** Garbage Collector
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -127,7 +127,7 @@ static int iscleared (const TValue *o, int iskey) {
127** barrier that moves collector forward, that is, mark the white object 127** barrier that moves collector forward, that is, mark the white object
128** being pointed by a black object. 128** being pointed by a black object.
129*/ 129*/
130void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { 130void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
131 global_State *g = G(L); 131 global_State *g = G(L);
132 lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); 132 lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
133 lua_assert(isgenerational(g) || g->gcstate != GCSpause); 133 lua_assert(isgenerational(g) || g->gcstate != GCSpause);
@@ -143,19 +143,32 @@ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
143 143
144/* 144/*
145** barrier that moves collector backward, that is, mark the black object 145** barrier that moves collector backward, that is, mark the black object
146** pointing to a white object as gray again. 146** pointing to a white object as gray again. (Current implementation
147** only works for tables; access to 'gclist' is not uniform across
148** different types.)
147*/ 149*/
148void luaC_barrierback (lua_State *L, Table *t) { 150void luaC_barrierback_ (lua_State *L, GCObject *o) {
149 global_State *g = G(L); 151 global_State *g = G(L);
150 GCObject *o = obj2gco(t);
151 lua_assert(isblack(o) && !isdead(g, o)); 152 lua_assert(isblack(o) && !isdead(g, o));
152 black2gray(o); /* make table gray (again) */ 153 black2gray(o); /* make object gray (again) */
153 t->gclist = g->grayagain; 154 gco2t(o)->gclist = g->grayagain;
154 g->grayagain = o; 155 g->grayagain = o;
155} 156}
156 157
157 158
158/* 159/*
160** barrier for prototypes
161*/
162LUAI_FUNC void luaC_barrierproto_ (lua_State *L, GCObject *p) {
163 global_State *g = G(L);
164 lua_assert(isblack(p));
165 black2gray(p); /* make object gray (again) */
166 gco2p(p)->gclist = g->clearcache;
167 g->clearcache = p;
168}
169
170
171/*
159** check color (and invariants) for an upvalue that was closed, 172** check color (and invariants) for an upvalue that was closed,
160** i.e., moved into the 'allgc' list 173** i.e., moved into the 'allgc' list
161*/ 174*/
@@ -299,7 +312,7 @@ static void remarkupvals (global_State *g) {
299static void markroot (lua_State *L) { 312static void markroot (lua_State *L) {
300 global_State *g = G(L); 313 global_State *g = G(L);
301 g->gray = g->grayagain = NULL; 314 g->gray = g->grayagain = NULL;
302 g->weak = g->allweak = g->ephemeron = NULL; 315 g->weak = g->allweak = g->ephemeron = g->clearcache = NULL;
303 markobject(g, g->mainthread); 316 markobject(g, g->mainthread);
304 markvalue(g, &g->l_registry); 317 markvalue(g, &g->l_registry);
305 markmt(g); 318 markmt(g);
@@ -409,8 +422,19 @@ static int traversetable (global_State *g, Table *h) {
409} 422}
410 423
411 424
425/*
426** if prototype's cached closure is not marked, erase it so it
427** can be collected
428*/
429static void checkcache (Proto *p) {
430 if (p->cache && iswhite(obj2gco(p->cache)))
431 p->cache = NULL; /* allow cache to be collected */
432}
433
434
412static int traverseproto (global_State *g, Proto *f) { 435static int traverseproto (global_State *g, Proto *f) {
413 int i; 436 int i;
437 checkcache(f);
414 stringmark(f->source); 438 stringmark(f->source);
415 for (i = 0; i < f->sizek; i++) /* mark literals */ 439 for (i = 0; i < f->sizek; i++) /* mark literals */
416 markvalue(g, &f->k[i]); 440 markvalue(g, &f->k[i]);
@@ -534,6 +558,15 @@ static void convergeephemerons (global_State *g) {
534*/ 558*/
535 559
536/* 560/*
561** clear cache field in all prototypes in list 'l'
562*/
563static void clearproto (GCObject *l) {
564 for (; l != NULL; l = gco2p(l)->gclist)
565 checkcache(gco2p(l));
566}
567
568
569/*
537** clear collected entries from all weaktables in list 'l' 570** clear collected entries from all weaktables in list 'l'
538*/ 571*/
539static void cleartable (GCObject *l) { 572static void cleartable (GCObject *l) {
@@ -845,6 +878,7 @@ static void atomic (lua_State *L) {
845 cleartable(g->weak); 878 cleartable(g->weak);
846 cleartable(g->ephemeron); 879 cleartable(g->ephemeron);
847 cleartable(g->allweak); 880 cleartable(g->allweak);
881 clearproto(g->clearcache);
848 g->sweepstrgc = 0; /* prepare to sweep strings */ 882 g->sweepstrgc = 0; /* prepare to sweep strings */
849 g->gcstate = GCSsweepstring; 883 g->gcstate = GCSsweepstring;
850 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ 884 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
diff --git a/lgc.h b/lgc.h
index ae45c80d..fa007969 100644
--- a/lgc.h
+++ b/lgc.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.h,v 2.40 2010/05/10 16:46:49 roberto Exp roberto $ 2** $Id: lgc.h,v 2.41 2010/05/10 18:23:45 roberto Exp roberto $
3** Garbage Collector 3** Garbage Collector
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -112,17 +112,20 @@
112 112
113 113
114#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ 114#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
115 luaC_barrierf(L,obj2gco(p),gcvalue(v)); } 115 luaC_barrier_(L,obj2gco(p),gcvalue(v)); }
116 116
117#define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t))) \ 117#define luaC_barrierback(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
118 luaC_barrierback(L,t); } 118 luaC_barrierback_(L,p); }
119 119
120#define luaC_objbarrier(L,p,o) \ 120#define luaC_objbarrier(L,p,o) \
121 { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ 121 { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \
122 luaC_barrierf(L,obj2gco(p),obj2gco(o)); } 122 luaC_barrier_(L,obj2gco(p),obj2gco(o)); }
123 123
124#define luaC_objbarriert(L,t,o) \ 124#define luaC_objbarrierback(L,p,o) \
125 { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } 125 { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) luaC_barrierback_(L,p); }
126
127#define luaC_barrierproto(L,p) \
128 { if (isblack(obj2gco(p))) luaC_barrierproto_(L,p); }
126 129
127LUAI_FUNC void luaC_separateudata (lua_State *L, int all); 130LUAI_FUNC void luaC_separateudata (lua_State *L, int all);
128LUAI_FUNC void luaC_freeallobjects (lua_State *L); 131LUAI_FUNC void luaC_freeallobjects (lua_State *L);
@@ -131,8 +134,9 @@ LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
131LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); 134LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
132LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, 135LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz,
133 GCObject **list, int offset); 136 GCObject **list, int offset);
134LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); 137LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
135LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); 138LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
139LUAI_FUNC void luaC_barrierproto_ (lua_State *L, GCObject *p);
136LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u); 140LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u);
137LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv); 141LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv);
138LUAI_FUNC void luaC_changemode (lua_State *L, int mode); 142LUAI_FUNC void luaC_changemode (lua_State *L, int mode);
diff --git a/lobject.h b/lobject.h
index 986001f2..54d77960 100644
--- a/lobject.h
+++ b/lobject.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lobject.h,v 2.39 2010/04/18 13:22:48 roberto Exp roberto $ 2** $Id: lobject.h,v 2.40 2010/05/07 18:44:46 roberto Exp roberto $
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*/
@@ -266,6 +266,7 @@ typedef struct Proto {
266 int *lineinfo; /* map from opcodes to source lines */ 266 int *lineinfo; /* map from opcodes to source lines */
267 struct LocVar *locvars; /* information about local variables */ 267 struct LocVar *locvars; /* information about local variables */
268 Upvaldesc *upvalues; /* upvalue information */ 268 Upvaldesc *upvalues; /* upvalue information */
269 union Closure *cache; /* last created closure with this prototype */
269 TString *source; 270 TString *source;
270 int sizeupvalues; /* size of 'upvalues' */ 271 int sizeupvalues; /* size of 'upvalues' */
271 int sizek; /* size of `k' */ 272 int sizek; /* size of `k' */
diff --git a/lvm.c b/lvm.c
index ce0572f3..3a66e0aa 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lvm.c,v 2.119 2010/05/12 20:40:35 roberto Exp roberto $ 2** $Id: lvm.c,v 2.120 2010/05/13 19:53:05 roberto Exp roberto $
3** Lua virtual machine 3** Lua virtual machine
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -136,7 +136,7 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
136 if (!ttisnil(oldval) || /* result is not nil? */ 136 if (!ttisnil(oldval) || /* result is not nil? */
137 (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ 137 (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
138 setobj2t(L, oldval, val); 138 setobj2t(L, oldval, val);
139 luaC_barriert(L, h, val); 139 luaC_barrierback(L, obj2gco(h), val);
140 return; 140 return;
141 } 141 }
142 /* else will try the tag method */ 142 /* else will try the tag method */
@@ -346,6 +346,49 @@ void luaV_arith (lua_State *L, StkId ra, const TValue *rb,
346 346
347 347
348/* 348/*
349** check whether cached closure in prototype 'p' may be reused, that is,
350** whether there is a cached closure with the same upvalues needed by
351** new closure to be created.
352*/
353static Closure *getcached (Proto *p, UpVal **encup, StkId base) {
354 Closure *c = p->cache;
355 if (c != NULL) { /* is there a cached closure? */
356 int nup = p->sizeupvalues;
357 Upvaldesc *uv = p->upvalues;
358 int i;
359 for (i = 0; i < nup; i++) { /* check whether it has right upvalues */
360 TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v;
361 if (c->l.upvals[i]->v != v)
362 return NULL; /* wrong upvalue; cannot reuse closure */
363 }
364 }
365 return c; /* return cached closure (or NULL if no cached closure) */
366}
367
368
369/*
370** create a new Lua closure, push it in the stack, and initialize
371** its upvalues
372*/
373static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
374 StkId ra) {
375 int nup = p->sizeupvalues;
376 Upvaldesc *uv = p->upvalues;
377 int i;
378 Closure *ncl = luaF_newLclosure(L, p);
379 setclvalue(L, ra, ncl); /* anchor new closure in stack */
380 for (i = 0; i < nup; i++) { /* fill in its upvalues */
381 if (uv[i].instack) /* upvalue refers to local variable? */
382 ncl->l.upvals[i] = luaF_findupval(L, base + uv[i].idx);
383 else /* get upvalue from enclosing function */
384 ncl->l.upvals[i] = encup[uv[i].idx];
385 }
386 p->cache = ncl; /* save it on cache, so it can be reused */
387 luaC_barrierproto(L, obj2gco(p));
388}
389
390
391/*
349** finish execution of an opcode interrupted by an yield 392** finish execution of an opcode interrupted by an yield
350*/ 393*/
351void luaV_finishOp (lua_State *L) { 394void luaV_finishOp (lua_State *L) {
@@ -721,7 +764,7 @@ void luaV_execute (lua_State *L) {
721 for (; n > 0; n--) { 764 for (; n > 0; n--) {
722 TValue *val = ra+n; 765 TValue *val = ra+n;
723 setobj2t(L, luaH_setint(L, h, last--), val); 766 setobj2t(L, luaH_setint(L, h, last--), val);
724 luaC_barriert(L, h, val); 767 luaC_barrierback(L, obj2gco(h), val);
725 } 768 }
726 L->top = ci->top; /* correct top (in case of previous open call) */ 769 L->top = ci->top; /* correct top (in case of previous open call) */
727 ) 770 )
@@ -729,19 +772,12 @@ void luaV_execute (lua_State *L) {
729 luaF_close(L, ra); 772 luaF_close(L, ra);
730 ) 773 )
731 vmcase(OP_CLOSURE, 774 vmcase(OP_CLOSURE,
732 Proto *p = cl->p->p[GETARG_Bx(i)]; /* prototype for new closure */ 775 Proto *p = cl->p->p[GETARG_Bx(i)];
733 int nup = p->sizeupvalues; 776 Closure *ncl = getcached(p, cl->upvals, base); /* cached closure */
734 Closure *ncl = luaF_newLclosure(L, nup); 777 if (ncl == NULL) /* no match? */
735 Upvaldesc *uv = p->upvalues; 778 pushclosure(L, p, cl->upvals, base, ra); /* create a new one */
736 int j; 779 else
737 ncl->l.p = p; 780 setclvalue(L, ra, ncl); /* push cashed closure */
738 setclvalue(L, ra, ncl); /* anchor new closure in stack */
739 for (j = 0; j < nup; j++) { /* fill in upvalues */
740 if (uv[j].instack) /* upvalue refers to local variable? */
741 ncl->l.upvals[j] = luaF_findupval(L, base + uv[j].idx);
742 else /* get upvalue from enclosing function */
743 ncl->l.upvals[j] = cl->upvals[uv[j].idx];
744 }
745 checkGC(L); 781 checkGC(L);
746 ) 782 )
747 vmcase(OP_VARARG, 783 vmcase(OP_VARARG,