diff options
author | daurnimator <quae@daurnimator.com> | 2018-01-29 19:01:22 +1100 |
---|---|---|
committer | daurnimator <quae@daurnimator.com> | 2018-01-29 22:07:00 +1100 |
commit | 313f55905253697fe4966f979865296aeaa7a801 (patch) | |
tree | a8f060a377d45943952ade62507951cd4555a21b | |
parent | 62b07567d9f39fa746ea35d9c08cd1dcf37dc67a (diff) | |
download | fengari-313f55905253697fe4966f979865296aeaa7a801.tar.gz fengari-313f55905253697fe4966f979865296aeaa7a801.tar.bz2 fengari-313f55905253697fe4966f979865296aeaa7a801.zip |
src/: Upvalues are now just TValues (possibly referencing on-stack)
- Removes `Upval` class
- closing over upvalues is now done by creating new on-stack TValue objects
- No more `openupval` linked list
With this fix, upvalues from collected coroutines will no longer keep other values alive
Closes #44
-rw-r--r-- | src/lapi.js | 13 | ||||
-rw-r--r-- | src/ldebug.js | 2 | ||||
-rw-r--r-- | src/lfunc.js | 64 | ||||
-rw-r--r-- | src/lobject.js | 6 | ||||
-rw-r--r-- | src/lstate.js | 4 | ||||
-rw-r--r-- | src/lvm.js | 13 |
6 files changed, 20 insertions, 82 deletions
diff --git a/src/lapi.js b/src/lapi.js index ec643b3..8ed67f5 100644 --- a/src/lapi.js +++ b/src/lapi.js @@ -32,10 +32,7 @@ const { from_userstring, to_luastring, } = require('./defs.js'); -const { - api_check, - lua_assert -} = require('./llimits.js'); +const { api_check } = require('./llimits.js'); const ldebug = require('./ldebug.js'); const ldo = require('./ldo.js'); const { luaU_dump } = require('./ldump.js'); @@ -555,7 +552,7 @@ const aux_upvalue = function(L, fi, n) { let name = p.upvalues[n-1].name; return { name: name ? name.getstr() : to_luastring("(*no name)", true), - val: f.upvals[n-1].v + val: f.upvals[n-1] }; } default: return null; /* not a closure */ @@ -930,7 +927,7 @@ const lua_load = function(L, reader, data, chunkname, mode) { /* get global table from registry */ let gt = ltable.luaH_getint(L.l_G.l_registry.value, LUA_RIDX_GLOBALS); /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ - f.upvals[0].v.setfrom(gt); + f.upvals[0].setfrom(gt); } } return status; @@ -1111,13 +1108,9 @@ const lua_upvalueid = function(L, fidx, n) { const lua_upvaluejoin = function(L, fidx1, n1, fidx2, n2) { let ref1 = getupvalref(L, fidx1, n1); let ref2 = getupvalref(L, fidx2, n2); - let up1 = ref1.upval; let up2 = ref2.upval; let f1 = ref1.closure; - lua_assert(up1.refcount > 0); - up1.refcount--; f1.upvals[ref1.upvalOff] = up2; - up2.refcount++; }; // This functions are only there for compatibility purposes diff --git a/src/ldebug.js b/src/ldebug.js index e403ba6..a471c75 100644 --- a/src/ldebug.js +++ b/src/ldebug.js @@ -537,7 +537,7 @@ const isinstack = function(L, ci, o) { const getupvalname = function(L, ci, o) { let c = ci.func.value; for (let i = 0; i < c.nupvalues; i++) { - if (c.upvals[i].v === o) { + if (c.upvals[i] === o) { return { name: upvalname(c.p, i), funcname: to_luastring('upvalue', true) diff --git a/src/lfunc.js b/src/lfunc.js index 2f28d0e..198c4b9 100644 --- a/src/lfunc.js +++ b/src/lfunc.js @@ -1,7 +1,6 @@ "use strict"; const { constant_types: { LUA_TNIL } } = require('./defs.js'); -const { lua_assert } = require('./llimits.js'); const lobject = require('./lobject.js'); class Proto { @@ -25,22 +24,6 @@ class Proto { } -class UpVal { - - constructor(L) { - this.id = L.l_G.id_counter++; - this.v = void 0; /* if open: reference to TValue on stack. if closed: TValue */ - this.vOff = void 0; /* if open: index on stack. if closed: undefined */ - this.refcount = 0; - this.open_next = null; /* linked list (when open) */ - } - - isopen() { - return this.vOff !== void 0; - } - -} - const luaF_newLclosure = function(L, n) { let c = new lobject.LClosure(L, n); return c; @@ -48,54 +31,24 @@ const luaF_newLclosure = function(L, n) { const luaF_findupval = function(L, level) { - let prevp; - let p = L.openupval; - while (p !== null && p.vOff >= level) { - lua_assert(p.isopen()); - if (p.vOff === level) /* found a corresponding upvalue? */ - return p; /* return it */ - prevp = p; - p = p.open_next; - } - /* not found: create a new upvalue */ - let uv = new UpVal(L); - /* link it to list of open upvalues */ - uv.open_next = p; - if (prevp) - prevp.open_next = uv; - else - L.openupval = uv; - uv.v = L.stack[level]; /* current value lives in the stack */ - uv.vOff = level; - return uv; + return L.stack[level]; }; const luaF_close = function(L, level) { - while (L.openupval !== null && L.openupval.vOff >= level) { - let uv = L.openupval; - lua_assert(uv.isopen()); - L.openupval = uv.open_next; /* remove from 'open' list */ - if (uv.refcount === 0) { /* no references? */ - /* free upvalue */ - uv.v = void 0; - uv.open_next = null; - } else { - let from = uv.v; - uv.v = new lobject.TValue(from.type, from.value); - } - uv.vOff = void 0; + /* Create new TValues on stack; + * any closures will keep referencing old TValues */ + for (let i=level; i<L.top; i++) { + let old = L.stack[i]; + L.stack[i] = new lobject.TValue(old.type, old.value); } }; /* -** fill a closure with new closed upvalues +** fill a closure with new upvalues */ const luaF_initupvals = function(L, cl) { for (let i = 0; i < cl.nupvalues; i++) { - let uv = new UpVal(L); - uv.refcount = 1; - uv.v = new lobject.TValue(LUA_TNIL, null); - cl.upvals[i] = uv; + cl.upvals[i] = new lobject.TValue(LUA_TNIL, null); } }; @@ -117,7 +70,6 @@ const luaF_getlocalname = function(f, local_number, pc) { module.exports.MAXUPVAL = 255; module.exports.Proto = Proto; -module.exports.UpVal = UpVal; module.exports.luaF_findupval = luaF_findupval; module.exports.luaF_close = luaF_close; module.exports.luaF_getlocalname = luaF_getlocalname; diff --git a/src/lobject.js b/src/lobject.js index 34d8550..055ccb2 100644 --- a/src/lobject.js +++ b/src/lobject.js @@ -48,7 +48,6 @@ const { } = require('./ljstype.js'); const ldebug = require('./ldebug.js'); const ldo = require('./ldo.js'); -const lfunc = require('./lfunc.js'); const lstate = require('./lstate.js'); const { luaS_bless, @@ -301,7 +300,7 @@ class LClosure { this.p = null; this.nupvalues = n; - this.upvals = new Array(n); /* list of upvalues as UpVals. initialised in luaF_initupvals */ + this.upvals = new Array(n); /* list of upvalues. initialised in luaF_initupvals */ } } @@ -656,8 +655,7 @@ const luaO_pushvfstring = function(L, fmt, argp) { v instanceof ltable.Table || v instanceof Udata || v instanceof LClosure || - v instanceof CClosure || - v instanceof lfunc.UpVal) { + v instanceof CClosure) { pushstr(L, to_luastring("0x"+v.id.toString(16))); } else if (v === null) { /* handle null before checking for typeof == object */ pushstr(L, to_luastring("null")); diff --git a/src/lstate.js b/src/lstate.js index 461ad83..0c44f3c 100644 --- a/src/lstate.js +++ b/src/lstate.js @@ -18,7 +18,6 @@ const lobject = require('./lobject.js'); const ldo = require('./ldo.js'); const lapi = require('./lapi.js'); const ltable = require('./ltable.js'); -const lfunc = require('./lfunc.js'); const ltm = require('./ltm.js'); const EXTRA_STACK = 5; @@ -70,7 +69,6 @@ class lua_State { this.basehookcount = 0; this.allowhook = 1; this.hookcount = this.basehookcount; - this.openupval = null; this.nny = 1; this.status = LUA_OK; this.errfunc = 0; @@ -166,7 +164,6 @@ const lua_newthread = function(L) { }; const luaE_freethread = function(L, L1) { - lfunc.luaF_close(L1, L1.stack); freestack(L1); }; @@ -183,7 +180,6 @@ const lua_newstate = function() { }; const close_state = function(L) { - lfunc.luaF_close(L, L.stack); /* close all upvalues for this thread */ freestack(L); }; @@ -225,11 +225,11 @@ const luaV_execute = function(L) { } case OP_GETUPVAL: { let b = i.B; - lobject.setobj2s(L, ra, cl.upvals[b].v); + lobject.setobj2s(L, ra, cl.upvals[b]); break; } case OP_GETTABUP: { - let upval = cl.upvals[i.B].v; + let upval = cl.upvals[i.B]; let rc = RKC(L, base, k, i); luaV_gettable(L, upval, rc, ra); break; @@ -241,7 +241,7 @@ const luaV_execute = function(L) { break; } case OP_SETTABUP: { - let upval = cl.upvals[i.A].v; + let upval = cl.upvals[i.A]; let rb = RKB(L, base, k, i); let rc = RKC(L, base, k, i); settable(L, upval, rb, rc); @@ -249,7 +249,7 @@ const luaV_execute = function(L) { } case OP_SETUPVAL: { let uv = cl.upvals[i.B]; - uv.v.setfrom(L.stack[ra]); + uv.setfrom(L.stack[ra]); break; } case OP_SETTABLE: { @@ -973,8 +973,8 @@ const getcached = function(p, encup, stack, base) { 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) + let v = uv[i].instack ? stack[base + uv[i].idx] : encup[uv[i].idx]; + if (c.upvals[i] !== v) return null; /* wrong upvalue; cannot reuse closure */ } } @@ -996,7 +996,6 @@ const pushclosure = function(L, p, encup, base, ra) { ncl.upvals[i] = lfunc.luaF_findupval(L, base + uv[i].idx); else ncl.upvals[i] = encup[uv[i].idx]; - ncl.upvals[i].refcount++; } p.cache = ncl; /* save it on cache for reuse */ }; |