@@ -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 ;
0 commit comments