diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2010-06-04 10:25:10 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2010-06-04 10:25:10 -0300 |
commit | 575074fd857b90cd7c14c7b172e8fe147080962a (patch) | |
tree | 6929e87845a56266061235f89213795806ee5291 /lvm.c | |
parent | 545f43065ff8fa20e5f8254e6270d00694b847dd (diff) | |
download | lua-575074fd857b90cd7c14c7b172e8fe147080962a.tar.gz lua-575074fd857b90cd7c14c7b172e8fe147080962a.tar.bz2 lua-575074fd857b90cd7c14c7b172e8fe147080962a.zip |
Lua closures are cached for reuse
Diffstat (limited to 'lvm.c')
-rw-r--r-- | lvm.c | 68 |
1 files changed, 52 insertions, 16 deletions
@@ -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 | */ | ||
353 | static 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 | */ | ||
373 | static 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 | */ |
351 | void luaV_finishOp (lua_State *L) { | 394 | void 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, |