diff options
author | Benoit Giannangeli <giann008@gmail.com> | 2017-05-22 10:51:55 +0200 |
---|---|---|
committer | Benoit Giannangeli <giann008@gmail.com> | 2017-05-22 10:51:55 +0200 |
commit | 25e2110a5eac0a2e6c7b4d502ffbd53fc61af301 (patch) | |
tree | 7e0ccc2dd0a03b36fc2ecee1887765b24bf3ac6a /src/ldo.js | |
parent | 18271b4169631ce8f10c10c0776d9bfb40bd691f (diff) | |
parent | 5b764695bdc939784fd448fe6ba16ed3a9f44b19 (diff) | |
download | fengari-25e2110a5eac0a2e6c7b4d502ffbd53fc61af301.tar.gz fengari-25e2110a5eac0a2e6c7b4d502ffbd53fc61af301.tar.bz2 fengari-25e2110a5eac0a2e6c7b4d502ffbd53fc61af301.zip |
Merge remote-tracking branch 'daurnimator/stack'
Diffstat (limited to 'src/ldo.js')
-rw-r--r-- | src/ldo.js | 63 |
1 files changed, 61 insertions, 2 deletions
@@ -13,6 +13,7 @@ const lparser = require('./lparser.js'); const lstate = require('./lstate.js'); const lstring = require('./lstring.js'); const ltm = require('./ltm.js'); +const luaconf = require('./luaconf.js'); const lundump = require('./lundump.js'); const lvm = require('./lvm.js'); const lzio = require('./lzio.js'); @@ -38,6 +39,56 @@ const seterrorobj = function(L, errcode, oldtop) { L.top = oldtop + 1; }; +const ERRORSTACKSIZE = luaconf.LUAI_MAXSTACK + 200; + +const luaD_reallocstack = function(L, newsize) { + assert(newsize <= luaconf.LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); + assert(L.stack_last == L.stack.length - lstate.EXTRA_STACK); + L.stack.length = newsize; + L.stack_last = newsize - lstate.EXTRA_STACK; +}; + +const luaD_growstack = function(L, n) { + let size = L.stack.length; + if (size > luaconf.LUAI_MAXSTACK) + luaD_throw(L, TS.LUA_ERRERR); + else { + let needed = L.top + n + lstate.EXTRA_STACK; + let newsize = 2 * size; + if (newsize > luaconf.LUAI_MAXSTACK) newsize = luaconf.LUAI_MAXSTACK; + if (newsize < needed) newsize = needed; + if (newsize > luaconf.LUAI_MAXSTACK) { /* stack overflow? */ + luaD_reallocstack(L, ERRORSTACKSIZE); + ldebug.luaG_runerror(L, "stack overflow"); + } + else + luaD_reallocstack(L, newsize); + } +}; + +const luaD_checkstack = function(L, n) { + if (L.stack_last - L.top <= n) + luaD_growstack(L, n); +}; + +const stackinuse = function(L) { + let lim = L.top; + for (let ci = L.ci; ci !== null; ci = ci.previous) { + if (lim < ci.top) lim = ci.top; + } + assert(lim <= L.stack_last); + return lim + 1; /* part of stack in use */ +}; + +const luaD_shrinkstack = function(L) { + let inuse = stackinuse(L); + let goodsize = inuse + Math.floor(inuse / 8) + 2*lstate.EXTRA_STACK; + if (goodsize > luaconf.LUAI_MAXSTACK) + goodsize = luaconf.LUAI_MAXSTACK; /* respect stack limit */ + if (inuse <= (luaconf.LUAI_MAXSTACK - lstate.EXTRA_STACK) && goodsize < L.stack.length) + luaD_reallocstack(L, goodsize); +}; + /* ** Prepares a function call: checks the stack, creates a new CallInfo ** entry, fills in the relevant information, calls hook if needed. @@ -53,11 +104,13 @@ const luaD_precall = function(L, off, nresults) { case CT.LUA_TLCF: { let f = func.type === CT.LUA_TCCL ? func.value.f : func.value; + luaD_checkstack(L, defs.LUA_MINSTACK); let ci = lstate.luaE_extendCI(L); ci.funcOff = off; ci.nresults = nresults; ci.func = func; ci.top = L.top + defs.LUA_MINSTACK; + assert(ci.top <= L.stack_last); ci.callstatus = 0; if (L.hookmask & defs.LUA_MASKCALL) luaD_hook(L, defs.LUA_HOOKCALL, -1); @@ -71,11 +124,11 @@ const luaD_precall = function(L, off, nresults) { return true; } case CT.LUA_TLCL: { + let base; let p = func.value.p; let n = L.top - off - 1; let fsize = p.maxstacksize; - let base; - + luaD_checkstack(L, fsize); if (p.is_vararg) { base = adjust_varargs(L, p, n); } else { @@ -169,6 +222,7 @@ const luaD_hook = function(L, event, line) { ar.currentline = line; ar.i_ci = ci; ci.top = L.top + defs.LUA_MINSTACK; + assert(ci.top <= L.stack_last); L.allowhook = 0; /* cannot call hooks inside a hook */ ci.callstatus |= lstate.CIST_HOOKED; hook(L, ar); @@ -388,6 +442,7 @@ const recover = function(L, status) { L.ci = ci; L.allowhook = ci.callstatus & lstate.CIST_OAH; /* restore original 'allowhook' */ L.nny = 0; /* should be zero to be yieldable */ + luaD_shrinkstack(L); L.errfunc = ci.c_old_errfunc; return 1; /* continue running the coroutine */ }; @@ -531,6 +586,7 @@ const luaD_pcall = function(L, func, u, old_top, ef) { L.ci = old_ci; L.allowhook = old_allowhooks; L.nny = old_nny; + luaD_shrinkstack(L); } L.errfunc = old_errfunc; @@ -594,12 +650,15 @@ module.exports.SParser = SParser; module.exports.adjust_varargs = adjust_varargs; module.exports.luaD_call = luaD_call; module.exports.luaD_callnoyield = luaD_callnoyield; +module.exports.luaD_checkstack = luaD_checkstack; +module.exports.luaD_growstack = luaD_growstack; module.exports.luaD_hook = luaD_hook; module.exports.luaD_pcall = luaD_pcall; module.exports.luaD_poscall = luaD_poscall; module.exports.luaD_precall = luaD_precall; module.exports.luaD_protectedparser = luaD_protectedparser; module.exports.luaD_rawrunprotected = luaD_rawrunprotected; +module.exports.luaD_reallocstack = luaD_reallocstack; module.exports.luaD_throw = luaD_throw; module.exports.lua_isyieldable = lua_isyieldable; module.exports.lua_resume = lua_resume; |