From 73d641f4cb9788757188ee1147c558bd07a16a93 Mon Sep 17 00:00:00 2001 From: daurnimator Date: Wed, 24 May 2017 16:55:45 +1000 Subject: src/lvm.js: cache closures --- src/lvm.js | 26 +++++++++++++++++++++++++- tests/test-suite/closure.js | 3 +-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/lvm.js b/src/lvm.js index 31ad74d..5f32129 100644 --- a/src/lvm.js +++ b/src/lvm.js @@ -687,7 +687,11 @@ const luaV_execute = function(L) { } case OCi.OP_CLOSURE: { let p = cl.p.p[i.Bx]; - pushclosure(L, p, cl.upvals, base, ra); /* create a new one */ + let ncl = getcached(p, cl.upvals, L.stack, base); /* cached closure */ + if (ncl === null) /* no match? */ + pushclosure(L, p, cl.upvals, base, ra); /* create a new one */ + else + L.stack[ra].setclLvalue(ncl); break; } case OCi.OP_VARARG: { @@ -1023,6 +1027,25 @@ const luaV_shiftl = function(x, y) { } }; +/* +** check whether cached closure in prototype 'p' may be reused, that is, +** whether there is a cached closure with the same upvalues needed by +** new closure to be created. +*/ +const getcached = function(p, encup, stack, base) { + let c = p.cache; + if (c !== null) { /* is there a cached closure? */ + let uv = p.upvalues; + let nup = uv.length; + for (let i = 0; i < nup; i++) { /* check whether it has right upvalues */ + let v = uv[i].instack ? stack[base + uv[i].idx] : encup[uv[i].idx].v; + if (c.upvals[i].v !== v) + return null; /* wrong upvalue; cannot reuse closure */ + } + } + return c; /* return cached closure (or NULL if no cached closure) */ +}; + /* ** create a new Lua closure, push it in the stack, and initialize ** its upvalues. @@ -1040,6 +1063,7 @@ const pushclosure = function(L, p, encup, base, ra) { ncl.upvals[i] = encup[uv[i].idx]; ncl.upvals[i].refcount++; } + p.cache = ncl; /* save it on cache for reuse */ }; const cvt2str = function(o) { diff --git a/tests/test-suite/closure.js b/tests/test-suite/closure.js index 3f63f17..8e9e4b1 100644 --- a/tests/test-suite/closure.js +++ b/tests/test-suite/closure.js @@ -8,8 +8,7 @@ const lua = require('../../src/lua.js'); const lauxlib = require('../../src/lauxlib.js'); const lualib = require('../../src/lualib.js'); -// TODO: fengari doesn't cache closures yet/ever -test("[test-suite] closure: testing equality", { skip: true }, function (t) { +test("[test-suite] closure: testing equality", function (t) { let luaCode = ` a = {} for i = 1, 5 do a[i] = function (x) return x + a + _ENV end end -- cgit v1.2.3-54-g00ecf