aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lfunc.c2
-rw-r--r--lgc.c64
-rw-r--r--lgc.h4
-rw-r--r--lobject.h2
-rw-r--r--lstate.c2
-rw-r--r--lstate.h3
-rw-r--r--ltests.c4
-rw-r--r--lvm.c39
-rw-r--r--testes/closure.lua13
9 files changed, 10 insertions, 123 deletions
diff --git a/lfunc.c b/lfunc.c
index 15874f88..aa6ce58f 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -219,8 +219,6 @@ Proto *luaF_newproto (lua_State *L) {
219 f->p = NULL; 219 f->p = NULL;
220 f->sizep = 0; 220 f->sizep = 0;
221 f->code = NULL; 221 f->code = NULL;
222 f->cache = NULL;
223 f->cachemiss = 0;
224 f->sizecode = 0; 222 f->sizecode = 0;
225 f->lineinfo = NULL; 223 f->lineinfo = NULL;
226 f->sizelineinfo = 0; 224 f->sizelineinfo = 0;
diff --git a/lgc.c b/lgc.c
index 9d196a18..95a8ad5b 100644
--- a/lgc.c
+++ b/lgc.c
@@ -221,27 +221,6 @@ void luaC_barrierback_ (lua_State *L, GCObject *o) {
221} 221}
222 222
223 223
224/*
225** Barrier for prototype's cache of closures. It turns the prototype
226** back to gray (it was black). For an 'OLD1' prototype, making it
227** gray stops it from being visited by 'markold', so it is linked in
228** the 'grayagain' list to ensure it will be visited. For other ages,
229** it goes to the 'protogray' list, as only its 'cache' field needs to
230** be revisited. (A prototype to be in this barrier must be already
231** finished, so its other fields cannot change and do not need to be
232** revisited.)
233*/
234LUAI_FUNC void luaC_protobarrier_ (lua_State *L, Proto *p) {
235 global_State *g = G(L);
236 lua_assert(g->gckind != KGC_GEN || isold(p));
237 if (getage(p) == G_OLD1) /* still need to be visited? */
238 linkgclist(p, g->grayagain); /* link it in 'grayagain' */
239 else
240 linkgclist(p, g->protogray); /* link it in 'protogray' */
241 black2gray(p); /* make prototype gray */
242}
243
244
245void luaC_fix (lua_State *L, GCObject *o) { 224void luaC_fix (lua_State *L, GCObject *o) {
246 global_State *g = G(L); 225 global_State *g = G(L);
247 lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ 226 lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */
@@ -379,7 +358,7 @@ static int remarkupvals (global_State *g) {
379*/ 358*/
380static void restartcollection (global_State *g) { 359static void restartcollection (global_State *g) {
381 g->gray = g->grayagain = NULL; 360 g->gray = g->grayagain = NULL;
382 g->weak = g->allweak = g->ephemeron = g->protogray = NULL; 361 g->weak = g->allweak = g->ephemeron = NULL;
383 markobject(g, g->mainthread); 362 markobject(g, g->mainthread);
384 markvalue(g, &g->l_registry); 363 markvalue(g, &g->l_registry);
385 markmt(g); 364 markmt(g);
@@ -535,39 +514,12 @@ static int traverseudata (global_State *g, Udata *u) {
535 514
536 515
537/* 516/*
538** Check the cache of a prototype, to keep invariants. If the
539** cache is white, clear it. (A cache should not prevent the
540** collection of its reference.) Otherwise, if in generational
541** mode, check the generational invariant. If the cache is old,
542** everything is ok. If the prototype is 'OLD0', everything
543** is ok too. (It will naturally be visited again.) If the
544** prototype is older than 'OLD0', then its cache (which is new)
545** must be visited again in the next collection, so the prototype
546** goes to the 'protogray' list. (If the prototype has a cache,
547** it is already immutable and does not need other barriers;
548** then, it can become gray without problems for its other fields.)
549*/
550static void checkprotocache (global_State *g, Proto *p) {
551 if (p->cache) {
552 if (iswhite(p->cache))
553 p->cache = NULL; /* allow cache to be collected */
554 else if (g->gckind == KGC_GEN && !isold(p->cache) && getage(p) >= G_OLD1) {
555 linkgclist(p, g->protogray); /* link it in 'protogray' */
556 black2gray(p); /* make prototype gray */
557 }
558 }
559 p->cachemiss = 0; /* restart counting */
560}
561
562
563/*
564** Traverse a prototype. (While a prototype is being build, its 517** Traverse a prototype. (While a prototype is being build, its
565** arrays can be larger than needed; the extra slots are filled with 518** arrays can be larger than needed; the extra slots are filled with
566** NULL, so the use of 'markobjectN') 519** NULL, so the use of 'markobjectN')
567*/ 520*/
568static int traverseproto (global_State *g, Proto *f) { 521static int traverseproto (global_State *g, Proto *f) {
569 int i; 522 int i;
570 checkprotocache(g, f);
571 markobjectN(g, f->source); 523 markobjectN(g, f->source);
572 for (i = 0; i < f->sizek; i++) /* mark literals */ 524 for (i = 0; i < f->sizek; i++) /* mark literals */
573 markvalue(g, &f->k[i]); 525 markvalue(g, &f->k[i]);
@@ -696,19 +648,6 @@ static void convergeephemerons (global_State *g) {
696** ======================================================= 648** =======================================================
697*/ 649*/
698 650
699static void clearprotolist (global_State *g) {
700 GCObject *p = g->protogray;
701 g->protogray = NULL;
702 while (p != NULL) {
703 Proto *pp = gco2p(p);
704 GCObject *next = pp->gclist;
705 lua_assert(isgray(pp) && (pp->cache != NULL || pp->cachemiss >= MAXMISS));
706 gray2black(pp);
707 checkprotocache(g, pp);
708 p = next;
709 }
710}
711
712 651
713/* 652/*
714** clear entries with unmarked keys from all weaktables in list 'l' 653** clear entries with unmarked keys from all weaktables in list 'l'
@@ -1439,7 +1378,6 @@ static lu_mem atomic (lua_State *L) {
1439 clearbyvalues(g, g->weak, origweak); 1378 clearbyvalues(g, g->weak, origweak);
1440 clearbyvalues(g, g->allweak, origall); 1379 clearbyvalues(g, g->allweak, origall);
1441 luaS_clearcache(g); 1380 luaS_clearcache(g);
1442 clearprotolist(g);
1443 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ 1381 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
1444 lua_assert(g->gray == NULL); 1382 lua_assert(g->gray == NULL);
1445 return work; /* estimate of slots marked by 'atomic' */ 1383 return work; /* estimate of slots marked by 'atomic' */
diff --git a/lgc.h b/lgc.h
index e0a8806b..6b1c2861 100644
--- a/lgc.h
+++ b/lgc.h
@@ -164,9 +164,6 @@
164 (isblack(p) && iswhite(o)) ? \ 164 (isblack(p) && iswhite(o)) ? \
165 luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) 165 luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
166 166
167#define luaC_protobarrier(L,p,o) \
168 (isblack(p) ? luaC_protobarrier_(L,p) : cast_void(0))
169
170LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); 167LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
171LUAI_FUNC void luaC_freeallobjects (lua_State *L); 168LUAI_FUNC void luaC_freeallobjects (lua_State *L);
172LUAI_FUNC void luaC_step (lua_State *L); 169LUAI_FUNC void luaC_step (lua_State *L);
@@ -175,7 +172,6 @@ LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
175LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); 172LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
176LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); 173LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
177LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); 174LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
178LUAI_FUNC void luaC_protobarrier_ (lua_State *L, Proto *p);
179LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); 175LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
180LUAI_FUNC void luaC_changemode (lua_State *L, int newmode); 176LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
181 177
diff --git a/lobject.h b/lobject.h
index ea3511de..df31a1a0 100644
--- a/lobject.h
+++ b/lobject.h
@@ -505,7 +505,6 @@ typedef struct Proto {
505 lu_byte numparams; /* number of fixed (named) parameters */ 505 lu_byte numparams; /* number of fixed (named) parameters */
506 lu_byte is_vararg; 506 lu_byte is_vararg;
507 lu_byte maxstacksize; /* number of registers needed by this function */ 507 lu_byte maxstacksize; /* number of registers needed by this function */
508 lu_byte cachemiss; /* count for successive misses for 'cache' field */
509 int sizeupvalues; /* size of 'upvalues' */ 508 int sizeupvalues; /* size of 'upvalues' */
510 int sizek; /* size of 'k' */ 509 int sizek; /* size of 'k' */
511 int sizecode; 510 int sizecode;
@@ -516,7 +515,6 @@ typedef struct Proto {
516 int linedefined; /* debug information */ 515 int linedefined; /* debug information */
517 int lastlinedefined; /* debug information */ 516 int lastlinedefined; /* debug information */
518 TValue *k; /* constants used by the function */ 517 TValue *k; /* constants used by the function */
519 struct LClosure *cache; /* last-created closure with this prototype */
520 Instruction *code; /* opcodes */ 518 Instruction *code; /* opcodes */
521 struct Proto **p; /* functions defined inside the function */ 519 struct Proto **p; /* functions defined inside the function */
522 Upvaldesc *upvalues; /* upvalue information */ 520 Upvaldesc *upvalues; /* upvalue information */
diff --git a/lstate.c b/lstate.c
index 4a2453d1..9d399959 100644
--- a/lstate.c
+++ b/lstate.c
@@ -340,7 +340,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
340 g->finobjsur = g->finobjold = g->finobjrold = NULL; 340 g->finobjsur = g->finobjold = g->finobjrold = NULL;
341 g->sweepgc = NULL; 341 g->sweepgc = NULL;
342 g->gray = g->grayagain = NULL; 342 g->gray = g->grayagain = NULL;
343 g->weak = g->ephemeron = g->allweak = g->protogray = NULL; 343 g->weak = g->ephemeron = g->allweak = NULL;
344 g->twups = NULL; 344 g->twups = NULL;
345 g->totalbytes = sizeof(LG); 345 g->totalbytes = sizeof(LG);
346 g->GCdebt = 0; 346 g->GCdebt = 0;
diff --git a/lstate.h b/lstate.h
index f08c2355..ce337707 100644
--- a/lstate.h
+++ b/lstate.h
@@ -43,8 +43,6 @@
43** 'weak': tables with weak values to be cleared; 43** 'weak': tables with weak values to be cleared;
44** 'ephemeron': ephemeron tables with white->white entries; 44** 'ephemeron': ephemeron tables with white->white entries;
45** 'allweak': tables with weak keys and/or weak values to be cleared. 45** 'allweak': tables with weak keys and/or weak values to be cleared.
46** There is also a list 'protogray' for prototypes that need to have
47** their caches cleared.
48 46
49*/ 47*/
50 48
@@ -186,7 +184,6 @@ typedef struct global_State {
186 GCObject *weak; /* list of tables with weak values */ 184 GCObject *weak; /* list of tables with weak values */
187 GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ 185 GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
188 GCObject *allweak; /* list of all-weak tables */ 186 GCObject *allweak; /* list of all-weak tables */
189 GCObject *protogray; /* list of prototypes with "new" caches */
190 GCObject *tobefnz; /* list of userdata to be GC */ 187 GCObject *tobefnz; /* list of userdata to be GC */
191 GCObject *fixedgc; /* list of objects not to be collected */ 188 GCObject *fixedgc; /* list of objects not to be collected */
192 /* fields for generational collector */ 189 /* fields for generational collector */
diff --git a/ltests.c b/ltests.c
index 7cf08891..aba44b87 100644
--- a/ltests.c
+++ b/ltests.c
@@ -283,7 +283,6 @@ static void checkudata (global_State *g, Udata *u) {
283static void checkproto (global_State *g, Proto *f) { 283static void checkproto (global_State *g, Proto *f) {
284 int i; 284 int i;
285 GCObject *fgc = obj2gco(f); 285 GCObject *fgc = obj2gco(f);
286 checkobjref(g, fgc, f->cache);
287 checkobjref(g, fgc, f->source); 286 checkobjref(g, fgc, f->source);
288 for (i=0; i<f->sizek; i++) { 287 for (i=0; i<f->sizek; i++) {
289 if (ttisstring(f->k + i)) 288 if (ttisstring(f->k + i))
@@ -417,8 +416,6 @@ static void checkobject (global_State *g, GCObject *o, int maybedead,
417 getage(o) == G_TOUCHED1 || 416 getage(o) == G_TOUCHED1 ||
418 getage(o) == G_OLD0 || 417 getage(o) == G_OLD0 ||
419 o->tt == LUA_TTHREAD || 418 o->tt == LUA_TTHREAD ||
420 (o->tt == LUA_TPROTO &&
421 (gco2p(o)->cache != NULL || gco2p(o)->cachemiss >= MAXMISS)) ||
422 (o->tt == LUA_TUPVAL && upisopen(gco2upv(o)))); 419 (o->tt == LUA_TUPVAL && upisopen(gco2upv(o))));
423 } 420 }
424 } 421 }
@@ -452,7 +449,6 @@ static void checkgrays (global_State *g) {
452 checkgraylist(g, g->grayagain); 449 checkgraylist(g, g->grayagain);
453 checkgraylist(g, g->weak); 450 checkgraylist(g, g->weak);
454 checkgraylist(g, g->ephemeron); 451 checkgraylist(g, g->ephemeron);
455 checkgraylist(g, g->protogray);
456} 452}
457 453
458 454
diff --git a/lvm.c b/lvm.c
index 1535700f..d9671055 100644
--- a/lvm.c
+++ b/lvm.c
@@ -684,30 +684,8 @@ lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
684 684
685 685
686/* 686/*
687** check whether cached closure in prototype 'p' may be reused, that is,
688** whether there is a cached closure with the same upvalues needed by
689** new closure to be created.
690*/
691static LClosure *getcached (Proto *p, UpVal **encup, StkId base) {
692 LClosure *c = p->cache;
693 if (c != NULL) { /* is there a cached closure? */
694 int nup = p->sizeupvalues;
695 Upvaldesc *uv = p->upvalues;
696 int i;
697 for (i = 0; i < nup; i++) { /* check whether it has right upvalues */
698 TValue *v = uv[i].instack ? s2v(base + uv[i].idx) : encup[uv[i].idx]->v;
699 if (c->upvals[i]->v != v)
700 return NULL; /* wrong upvalue; cannot reuse closure */
701 }
702 p->cachemiss = 0; /* got a hit */
703 }
704 return c; /* return cached closure (or NULL if no cached closure) */
705}
706
707
708/*
709** create a new Lua closure, push it in the stack, and initialize 687** create a new Lua closure, push it in the stack, and initialize
710** its upvalues. ??? 688** its upvalues.
711*/ 689*/
712static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, 690static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
713 StkId ra) { 691 StkId ra) {
@@ -724,13 +702,6 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
724 ncl->upvals[i] = encup[uv[i].idx]; 702 ncl->upvals[i] = encup[uv[i].idx];
725 luaC_objbarrier(L, ncl, ncl->upvals[i]); 703 luaC_objbarrier(L, ncl, ncl->upvals[i]);
726 } 704 }
727 if (p->cachemiss >= MAXMISS) /* too many missings? */
728 p->cache = NULL; /* give up cache */
729 else {
730 p->cache = ncl; /* save it on cache for reuse */
731 luaC_protobarrier(L, p, ncl);
732 p->cachemiss++;
733 }
734} 705}
735 706
736 707
@@ -1811,13 +1782,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1811 } 1782 }
1812 vmcase(OP_CLOSURE) { 1783 vmcase(OP_CLOSURE) {
1813 Proto *p = cl->p->p[GETARG_Bx(i)]; 1784 Proto *p = cl->p->p[GETARG_Bx(i)];
1814 LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ 1785 halfProtect(pushclosure(L, p, cl->upvals, base, ra));
1815 if (ncl == NULL) { /* no match? */
1816 savestate(L, ci); /* in case of allocation errors */
1817 pushclosure(L, p, cl->upvals, base, ra); /* create a new one */
1818 }
1819 else
1820 setclLvalue2s(L, ra, ncl); /* push cashed closure */
1821 checkGC(L, ra + 1); 1786 checkGC(L, ra + 1);
1822 vmbreak; 1787 vmbreak;
1823 } 1788 }
diff --git a/testes/closure.lua b/testes/closure.lua
index 5d090d91..cdeaebaa 100644
--- a/testes/closure.lua
+++ b/testes/closure.lua
@@ -44,18 +44,17 @@ assert(B.g == 19)
44 44
45-- testing equality 45-- testing equality
46a = {} 46a = {}
47collectgarbage"stop"
48for i = 1, 5 do a[i] = function (x) return x + a + _ENV end end
49collectgarbage"restart"
50assert(a[3] == a[4] and a[4] == a[5])
51 47
52for i = 1, 5 do a[i] = function (x) return i + a + _ENV end end 48for i = 1, 5 do a[i] = function (x) return i + a + _ENV end end
53assert(a[3] ~= a[4] and a[4] ~= a[5]) 49assert(a[3] ~= a[4] and a[4] ~= a[5])
54 50
55local function f() 51do
56 return function (x) return math.sin(_ENV[x]) end 52 local a = function (x) return math.sin(_ENV[x]) end
53 local function f()
54 return a
55 end
56 assert(f() == f())
57end 57end
58assert(f() == f())
59 58
60 59
61-- testing closures with 'for' control variable 60-- testing closures with 'for' control variable