Skip to content

Commit 2e4f40a

Browse files
committed
[MERGE #1438 @pleath] Enhance parse-time escape detection
Merge pull request #1438 from pleath:8416430 Enhance the parse-time escape-detection I added the other day by detecting 'function e(){...}; return e;'.
2 parents 9187edf + 15044e7 commit 2e4f40a

File tree

3 files changed

+48
-8
lines changed

3 files changed

+48
-8
lines changed

lib/Parser/Hash.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,22 @@ struct Ident
206206
return prevRef;
207207
}
208208

209+
PidRefStack * TopDecl(int maxBlockId) const
210+
{
211+
for (PidRefStack *pidRef = m_pidRefStack; pidRef; pidRef = pidRef->prev)
212+
{
213+
if (pidRef->id > maxBlockId)
214+
{
215+
continue;
216+
}
217+
if (pidRef->sym != nullptr)
218+
{
219+
return pidRef;
220+
}
221+
}
222+
return nullptr;
223+
}
224+
209225
PidRefStack * FindOrAddPidRef(ArenaAllocator *alloc, int scopeId, Js::LocalFunctionId funcId)
210226
{
211227
// If the stack is empty, or we are pushing to the innermost scope already,

lib/Parser/Parse.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8019,18 +8019,42 @@ bool Parser::ParseOptionalExpr(ParseNodePtr* pnode, bool fUnaryOrParen, int oplM
80198019
return false;
80208020
}
80218021

8022-
ParseNodePtr pnodeT = ParseExpr<buildAST>(oplMin, pfCanAssign, fAllowIn, fAllowEllipsis, nullptr /*pNameHint*/, nullptr /*pHintLength*/, nullptr /*pShortNameOffset*/, pToken, fUnaryOrParen);
8022+
IdentToken token;
8023+
ParseNodePtr pnodeT = ParseExpr<buildAST>(oplMin, pfCanAssign, fAllowIn, fAllowEllipsis, nullptr /*pNameHint*/, nullptr /*pHintLength*/, nullptr /*pShortNameOffset*/, &token, fUnaryOrParen);
80238024
// Detect nested function escapes of the pattern "return function(){...}" or "yield function(){...}".
80248025
// Doing so in the parser allows us to disable stack-nested-functions in common cases where an escape
80258026
// is not detected at byte code gen time because of deferred parsing.
8026-
if (m_currentNodeFunc && pnodeT && pnodeT->nop == knopFncDecl)
8027+
if (m_currentNodeFunc)
80278028
{
8028-
if (m_sourceContextInfo ?
8029-
!PHASE_OFF_RAW(Js::DisableStackFuncOnDeferredEscapePhase, m_sourceContextInfo->sourceContextId, m_currentNodeFunc->sxFnc.functionId) :
8030-
!PHASE_OFF1(Js::DisableStackFuncOnDeferredEscapePhase))
8029+
ParseNodePtr pnodeEnclosingFunc = nullptr;
8030+
if (pnodeT && pnodeT->nop == knopFncDecl)
80318031
{
8032-
m_currentNodeFunc->sxFnc.SetNestedFuncEscapes();
8032+
pnodeEnclosingFunc = m_currentNodeFunc;
80338033
}
8034+
else if (token.pid)
8035+
{
8036+
// Allow detect "function() { function f(){...}; return f; }".
8037+
PidRefStack *pidRefDecl = token.pid->TopDecl(GetCurrentBlockInfo()->pnodeBlock->sxBlock.blockId);
8038+
if (pidRefDecl && pidRefDecl->sym->GetSymbolType() == STFunction)
8039+
{
8040+
// This may be conservative if the function object we're returning actually encloses the current function.
8041+
// But being precise for such a case doesn't seem worth the extra bookkeeping.
8042+
pnodeEnclosingFunc = m_currentNodeFunc;
8043+
}
8044+
}
8045+
if (pnodeEnclosingFunc)
8046+
{
8047+
if (m_sourceContextInfo ?
8048+
!PHASE_OFF_RAW(Js::DisableStackFuncOnDeferredEscapePhase, m_sourceContextInfo->sourceContextId, pnodeEnclosingFunc->sxFnc.functionId) :
8049+
!PHASE_OFF1(Js::DisableStackFuncOnDeferredEscapePhase))
8050+
{
8051+
pnodeEnclosingFunc->sxFnc.SetNestedFuncEscapes();
8052+
}
8053+
}
8054+
}
8055+
if (pToken)
8056+
{
8057+
*pToken = token;
80348058
}
80358059
*pnode = pnodeT;
80368060
return true;

test/stackfunc/rlexe.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@
284284
<default>
285285
<files>funcname_escape.js</files>
286286
<baseline>funcname_escape.deferparse.baseline</baseline>
287-
<compile-flags>-testtrace:stackfunc -off:simpleJit -Force:Deferparse -on:stackfunc</compile-flags>
287+
<compile-flags>-testtrace:stackfunc -off:simpleJit -Force:Deferparse -on:stackfunc -off:disablestackfuncondeferredescape</compile-flags>
288288
<tags>exclude_fre,exclude_dynapogo</tags>
289289
</default>
290290
</test>
@@ -511,7 +511,7 @@
511511
<default>
512512
<files>box_callparam.js</files>
513513
<baseline>box_callparam.deferparse.baseline</baseline>
514-
<compile-flags>-testtrace:stackfunc -off:simpleJit -on:stackfunc -force:deferparse -off:cachescopeinfonames </compile-flags>
514+
<compile-flags>-testtrace:stackfunc -off:simpleJit -on:stackfunc -force:deferparse -off:cachescopeinfonames -off:disablestackfuncondeferredescape </compile-flags>
515515
<tags>exclude_fre,exclude_dynapogo</tags>
516516
</default>
517517
</test>

0 commit comments

Comments
 (0)