@@ -55,6 +55,12 @@ struct StmtNest
5555 };
5656 };
5757 StmtNest *pstmtOuter; // Enclosing statement.
58+
59+ OpCode GetNop () const
60+ {
61+ AnalysisAssert (isDeferred || pnodeStmt != nullptr );
62+ return isDeferred ? op : pnodeStmt->nop ;
63+ }
5864};
5965
6066struct BlockInfoStack
@@ -110,6 +116,7 @@ Parser::Parser(Js::ScriptContext* scriptContext, BOOL strictMode, PageAllocator
110116 m_errorCallback = nullptr ;
111117 m_uncertainStructure = FALSE ;
112118 m_reparsingLambdaParams = false ;
119+ m_inFIB = false ;
113120 currBackgroundParseItem = nullptr ;
114121 backgroundParseItems = nullptr ;
115122 fastScannedRegExpNodes = nullptr ;
@@ -722,59 +729,46 @@ ParseNodePtr Parser::CreateNodeT(charcount_t ichMin,charcount_t ichLim)
722729 return pnode;
723730}
724731
725- ParseNodePtr Parser::CreateDeclNode (OpCode nop, IdentPtr pid, SymbolType symbolType, bool errorOnRedecl)
732+ ParseNodePtr Parser::CreateDeclNode (OpCode nop, IdentPtr pid, SymbolType symbolType, bool errorOnRedecl, bool *isRedecl )
726733{
727734 ParseNodePtr pnode = CreateNode (nop);
728735
729736 pnode->sxVar .InitDeclNode (pid, NULL );
730737
731738 if (symbolType != STUnknown)
732739 {
733- pnode->sxVar .sym = AddDeclForPid (pnode, pid, symbolType, errorOnRedecl);
740+ pnode->sxVar .sym = AddDeclForPid (pnode, pid, symbolType, errorOnRedecl, isRedecl );
734741 }
735742
736743 return pnode;
737744}
738745
739- Symbol* Parser::AddDeclForPid (ParseNodePtr pnode, IdentPtr pid, SymbolType symbolType, bool errorOnRedecl)
746+ Symbol* Parser::AddDeclForPid (ParseNodePtr pnode, IdentPtr pid, SymbolType symbolType, bool errorOnRedecl, bool *isRedecl )
740747{
741748 Assert (pnode->IsVarLetOrConst ());
742749
743750 PidRefStack *refForUse = nullptr , *refForDecl = nullptr ;
744751
752+ if (isRedecl)
753+ {
754+ *isRedecl = false ;
755+ }
756+
745757 BlockInfoStack *blockInfo;
746758 bool fBlockScope = false ;
747759 if (pnode->nop != knopVarDecl || symbolType == STFunction)
748760 {
749761 Assert (m_pstmtCur);
750- if (m_pstmtCur->isDeferred )
762+ if (m_pstmtCur->GetNop () != knopBlock )
751763 {
752- // Deferred parsing: there's no pnodeStmt node, only an opcode on the Stmt struct.
753- if (m_pstmtCur->op != knopBlock)
754- {
755- // Let/const declared in a bare statement context.
756- Error (ERRDeclOutOfStmt);
757- }
758-
759- if (m_pstmtCur->pstmtOuter && m_pstmtCur->pstmtOuter ->op == knopSwitch)
760- {
761- // Let/const declared inside a switch block (requiring conservative use-before-decl check).
762- pnode->sxVar .isSwitchStmtDecl = true ;
763- }
764+ // Let/const declared in a bare statement context.
765+ Error (ERRDeclOutOfStmt);
764766 }
765- else
766- {
767- if (m_pstmtCur->pnodeStmt ->nop != knopBlock)
768- {
769- // Let/const declared in a bare statement context.
770- Error (ERRDeclOutOfStmt);
771- }
772767
773- if (m_pstmtCur->pstmtOuter && m_pstmtCur->pstmtOuter ->pnodeStmt ->nop == knopSwitch)
774- {
775- // Let/const declared inside a switch block (requiring conservative use-before-decl check).
776- pnode->sxVar .isSwitchStmtDecl = true ;
777- }
768+ if (m_pstmtCur->pstmtOuter && m_pstmtCur->pstmtOuter ->GetNop () == knopSwitch)
769+ {
770+ // Let/const declared inside a switch block (requiring conservative use-before-decl check).
771+ pnode->sxVar .isSwitchStmtDecl = true ;
778772 }
779773
780774 fBlockScope = pnode->nop != knopVarDecl ||
@@ -833,6 +827,10 @@ Symbol* Parser::AddDeclForPid(ParseNodePtr pnode, IdentPtr pid, SymbolType symbo
833827 Symbol *sym = refForDecl->GetSym ();
834828 if (sym != nullptr )
835829 {
830+ if (isRedecl)
831+ {
832+ *isRedecl = true ;
833+ }
836834 // Multiple declarations in the same scope. 3 possibilities: error, existing one wins, new one wins.
837835 switch (pnode->nop )
838836 {
@@ -901,6 +899,10 @@ Symbol* Parser::AddDeclForPid(ParseNodePtr pnode, IdentPtr pid, SymbolType symbo
901899 {
902900 Assert (blockInfo->pnodeBlock ->sxBlock .blockType == PnodeBlockType::Regular);
903901 scope = Anew (&m_nodeAllocator, Scope, &m_nodeAllocator, ScopeType_Block);
902+ if (this ->IsCurBlockInLoop ())
903+ {
904+ scope->SetIsBlockInLoop ();
905+ }
904906 blockInfo->pnodeBlock ->sxBlock .scope = scope;
905907 PushScope (scope);
906908 }
@@ -961,6 +963,23 @@ Symbol* Parser::AddDeclForPid(ParseNodePtr pnode, IdentPtr pid, SymbolType symbo
961963 return sym;
962964}
963965
966+ bool Parser::IsCurBlockInLoop () const
967+ {
968+ for (StmtNest *stmt = this ->m_pstmtCur ; stmt != nullptr ; stmt = stmt->pstmtOuter )
969+ {
970+ OpCode nop = stmt->GetNop ();
971+ if (ParseNode::Grfnop (nop) & fnopContinue)
972+ {
973+ return true ;
974+ }
975+ if (nop == knopFncDecl)
976+ {
977+ return false ;
978+ }
979+ }
980+ return false ;
981+ }
982+
964983void Parser::RestorePidRefForSym (Symbol *sym)
965984{
966985 IdentPtr pid = m_pscan->m_phtbl ->PidHashNameLen (sym->GetName ().GetBuffer (), sym->GetName ().GetLength ());
@@ -1369,9 +1388,9 @@ ParseNodePtr Parser::CreateModuleImportDeclNode(IdentPtr localName)
13691388 return declNode;
13701389}
13711390
1372- ParseNodePtr Parser::CreateVarDeclNode (IdentPtr pid, SymbolType symbolType, bool autoArgumentsObject, ParseNodePtr pnodeFnc, bool errorOnRedecl)
1391+ ParseNodePtr Parser::CreateVarDeclNode (IdentPtr pid, SymbolType symbolType, bool autoArgumentsObject, ParseNodePtr pnodeFnc, bool errorOnRedecl, bool *isRedecl )
13731392{
1374- ParseNodePtr pnode = CreateDeclNode (knopVarDecl, pid, symbolType, errorOnRedecl);
1393+ ParseNodePtr pnode = CreateDeclNode (knopVarDecl, pid, symbolType, errorOnRedecl, isRedecl );
13751394
13761395 // Append the variable to the end of the current variable list.
13771396 AssertMem (m_ppnodeVar);
@@ -4540,10 +4559,7 @@ ParseNodePtr Parser::ParseFncDecl(ushort flags, LPCOLESTR pNameHint, const bool
45404559
45414560 if (fDeclaration )
45424561 {
4543- AnalysisAssert (m_pstmtCur->isDeferred || m_pstmtCur->pnodeStmt != nullptr );
4544- noStmtContext =
4545- (m_pstmtCur->isDeferred && m_pstmtCur->op != knopBlock) ||
4546- (!m_pstmtCur->isDeferred && m_pstmtCur->pnodeStmt ->nop != knopBlock);
4562+ noStmtContext = m_pstmtCur->GetNop () != knopBlock;
45474563
45484564 if (noStmtContext)
45494565 {
@@ -4712,8 +4728,13 @@ ParseNodePtr Parser::ParseFncDecl(ushort flags, LPCOLESTR pNameHint, const bool
47124728 // level and we accomplish this by having each block scoped function
47134729 // declaration assign to both the block scoped "let" binding, as well
47144730 // as the function scoped "var" binding.
4715- ParseNodePtr vardecl = CreateVarDeclNode (pnodeFnc->sxFnc .pnodeName ->sxVar .pid , STVariable, false , nullptr , false );
4731+ bool isRedecl = false ;
4732+ ParseNodePtr vardecl = CreateVarDeclNode (pnodeFnc->sxFnc .pnodeName ->sxVar .pid , STVariable, false , nullptr , false , &isRedecl);
47164733 vardecl->sxVar .isBlockScopeFncDeclVar = true ;
4734+ if (isRedecl)
4735+ {
4736+ vardecl->sxVar .sym ->SetHasBlockFncVarRedecl ();
4737+ }
47174738 }
47184739 }
47194740
@@ -4906,7 +4927,6 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
49064927
49074928 uint uDeferSave = m_grfscr & fscrDeferFncParse;
49084929 if ((!fDeclaration && m_ppnodeExprScope) ||
4909- fFunctionInBlock ||
49104930 isEnclosedInParamScope ||
49114931 (flags & (fFncNoName | fFncLambda )))
49124932 {
@@ -4920,6 +4940,8 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
49204940 m_grfscr &= ~fscrDeferFncParse;
49214941 }
49224942
4943+ bool saveInFIB = this ->m_inFIB ;
4944+ this ->m_inFIB = fFunctionInBlock || this ->m_inFIB ;
49234945
49244946 bool isTopLevelDeferredFunc = false ;
49254947
@@ -4938,14 +4960,12 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
49384960
49394961 BOOL isDeferredFnc = IsDeferredFnc ();
49404962 AnalysisAssert (isDeferredFnc || pnodeFnc);
4963+ // These are the conditions that prohibit upfront deferral *and* redeferral.
49414964 isTopLevelDeferredFunc =
49424965 (!fLambda
49434966 && pnodeFnc
49444967 && DeferredParse (pnodeFnc->sxFnc .functionId )
49454968 && (!pnodeFnc->sxFnc .IsNested () || CONFIG_FLAG (DeferNested))
4946- // Don't defer if this is a function expression not contained in a statement or other expression.
4947- // Assume it will be called as part of this expression.
4948- && (!isLikelyIIFE || !topLevelStmt || PHASE_FORCE_RAW (Js::DeferParsePhase, m_sourceContextInfo->sourceContextId , pnodeFnc->sxFnc .functionId ))
49494969 && !m_InAsmMode
49504970 // Don't defer a module function wrapper because we need to do export resolution at parse time
49514971 && !fModule
@@ -4954,9 +4974,25 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
49544974 if (pnodeFnc)
49554975 {
49564976 pnodeFnc->sxFnc .SetCanBeDeferred (isTopLevelDeferredFunc && PnFnc::CanBeRedeferred (pnodeFnc->sxFnc .fncFlags ));
4977+ pnodeFnc->sxFnc .SetFIBPreventsDeferral (false );
49574978 }
4958- isTopLevelDeferredFunc = isTopLevelDeferredFunc && !isDeferredFnc;
49594979
4980+ if (this ->m_inFIB )
4981+ {
4982+ if (isTopLevelDeferredFunc)
4983+ {
4984+ // Block-scoping is the only non-heuristic reason for not deferring this function up front.
4985+ // So on creating the full FunctionBody at byte code gen time, verify that there is no
4986+ // block-scoped content visible to this function so it can remain a redeferral candidate.
4987+ pnodeFnc->sxFnc .SetFIBPreventsDeferral (true );
4988+ }
4989+ isTopLevelDeferredFunc = false ;
4990+ }
4991+
4992+ // These are heuristic conditions that prohibit upfront deferral but not redeferral.
4993+ isTopLevelDeferredFunc = isTopLevelDeferredFunc && !isDeferredFnc &&
4994+ (!isLikelyIIFE || !topLevelStmt || PHASE_FORCE_RAW (Js::DeferParsePhase, m_sourceContextInfo->sourceContextId , pnodeFnc->sxFnc .functionId ));
4995+ ;
49604996 if (!fLambda &&
49614997 !isDeferredFnc &&
49624998 !isLikelyIIFE &&
@@ -5392,7 +5428,7 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
53925428 {
53935429 m_grfscr |= uDeferSave;
53945430 }
5395-
5431+ m_inFIB = saveInFIB;
53965432
53975433 m_pscan->SetYieldIsKeyword (fPreviousYieldIsKeyword );
53985434 m_pscan->SetAwaitIsKeyword (fPreviousAwaitIsKeyword );
@@ -10012,21 +10048,14 @@ ParseNodePtr Parser::ParseStatement()
1001210048 }
1001310049 else
1001410050 {
10015- if (pstmt->isDeferred )
10051+ if (ParseNode::Grfnop ( pstmt->GetNop ()) & fnop )
1001610052 {
10017- if (ParseNode::Grfnop (pstmt->op ) & fnop)
10018- {
10019- goto LNeedTerminator;
10020- }
10021- }
10022- else
10023- {
10024- AnalysisAssert (pstmt->pnodeStmt );
10025- if (pstmt->pnodeStmt ->Grfnop () & fnop)
10053+ if (!pstmt->isDeferred )
1002610054 {
10055+ AnalysisAssert (pstmt->pnodeStmt );
1002710056 pstmt->pnodeStmt ->sxStmt .grfnop |= fnop;
10028- goto LNeedTerminator;
1002910057 }
10058+ goto LNeedTerminator;
1003010059 }
1003110060 }
1003210061 }
0 commit comments