Last Comment Bug 784839 - reuse CallObjects when nested functions don't escape
: reuse CallObjects when nested functions don't escape
Status: NEW
Product: Core
Classification: Components
Component: JavaScript Engine (show other bugs)
: unspecified
: All All
: -- normal with 2 votes (vote)
: ---
Assigned To: Nobody; OK to take it and work on it
Depends on:
  Show dependency treegraph
Reported: 2012-08-22 15:19 PDT by Luke Wagner [:luke]
Modified: 2014-07-24 11:07 PDT (History)
3 users (show)
See Also:
Crash Signature:
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---


Description Luke Wagner [:luke] 2012-08-22 15:19:53 PDT
Given a function:

  function outer(x) {
    function inner() { return x }

we mark outer as 'heavyweight' since it contains a nested function that accesses the formal parameter 'x'.  However, since 'inner' doesn't escape, we shouldn't need to allocate a CallObject every time we call 'outer'.

This is the same observation as the "Algol display optimization" that was removed in pieces over the last two years.  The original approach used a frontend (parser) analysis and required complexity in the rest of the VM as well as special support in the jits.

With the new scope machinery I think we could use a simpler strategy to achieve the same effect:
 - when we analyze a heavyweight function, we check if any of the nested functions escape using the SSA we already have. if none of the nested functions escape, set a JSScript flag "canReuseScopeAfterEpilogue"
 - add a 'CallObject *JSScript::freeScope' field, initially NULL
 - in the heavyweight prologue when canReuseScopeAfterEpilogue, create a CallObject if freeScope is NULL, otherwise, reuse the one in freeScope and set freeScope to NULL
 - in the heavyweight epilogue where canReuseScopeAfterEpilogue, set freeScope = fp->scopeChain.

Thus, the only real change would be small modifications to StackFrame::prologue/epilogue (and their jit equivalents).

A few details:
 - we'd need a reliable way to know "this heavyweight function is only heavyweight b/c of nested functions". (I think it's (heavyweight && !bindingsAccessedDynamically && !funHasExtensibleScope), but I could be wrong; it'd be nice to stop with the name "heavyweight" and use flags with more specific meanings.)
 - we'd need a reliable way to find all nested functions (is that just all functions in script->objects?  perhaps instead we'd scan the bytecode for JSOP_LAMBDA?)
 - it would be nice to leverage an existing escape analysis based on IM which took advantage of inlining (there isn't one yet, but there may be one day).  Going further: if IM inlined all nested functions, there would be no need for a CallObject at all and all ALIASEDVAR opcodes could be turned into LOCAL opcodes...

(I'm not planning to do this anytime soon, just filing to collect use cases if they arise.)

Note You need to log in before you can comment on or make changes to this bug.