@@ -968,84 +968,101 @@ Js::RegSlot ByteCodeGenerator::EnregisterStringTemplateCallsiteConstant(ParseNod
968
968
//
969
969
// Restore all outer func scope info when reparsing a deferred func.
970
970
//
971
- void ByteCodeGenerator::RestoreScopeInfo (Js::ParseableFunctionInfo* functionBody )
971
+ void ByteCodeGenerator::RestoreScopeInfo (Js::ScopeInfo *scopeInfo, FuncInfo * func )
972
972
{
973
- if (functionBody && functionBody-> GetScopeInfo () )
973
+ if (scopeInfo )
974
974
{
975
975
PROBE_STACK (scriptContext, Js::Constants::MinStackByteCodeVisitor);
976
976
977
- Js::ScopeInfo* scopeInfo = functionBody-> GetScopeInfo ();
978
- RestoreScopeInfo (scopeInfo-> GetParent ()); // Recursively restore outer func scope info
977
+ Js::ParseableFunctionInfo * pfi = scopeInfo-> GetFunctionInfo ()-> GetParseableFunctionInfo ();
978
+ bool newFunc = (func == nullptr || func-> byteCodeFunction != pfi);
979
979
980
- Js::ScopeInfo* paramScopeInfo = scopeInfo->GetParamScopeInfo ();
981
- Scope* paramScope = nullptr ;
982
- if (paramScopeInfo != nullptr )
980
+ if (newFunc)
983
981
{
984
- paramScope = paramScopeInfo->GetScope ();
985
- Assert (paramScope);
986
- if (!paramScopeInfo->GetCanMergeWithBodyScope ())
987
- {
988
- paramScope->SetCannotMergeWithBodyScope ();
989
- }
990
- // We need the funcInfo before continuing the restoration of the param scope, so wait for the funcInfo to be created.
991
- }
992
-
993
- Scope* bodyScope = scopeInfo->GetScope ();
994
-
995
- Assert (bodyScope);
996
- bodyScope->SetHasOwnLocalInClosure (scopeInfo->GetHasOwnLocalInClosure ());
997
-
998
- FuncInfo* func = Anew (alloc, FuncInfo, functionBody->GetDisplayName (), alloc, paramScope, bodyScope, nullptr , functionBody);
999
-
1000
- if (bodyScope->GetScopeType () == ScopeType_GlobalEvalBlock)
1001
- {
1002
- func->bodyScope = this ->currentScope ;
982
+ func = Anew (alloc, FuncInfo, pfi->GetDisplayName (), alloc, nullptr , nullptr , nullptr , pfi);
983
+ newFunc = true ;
1003
984
}
1004
- PushFuncInfo (_u (" RestoreScopeInfo" ), func);
1005
985
1006
- if (!functionBody->DoStackNestedFunc ())
1007
- {
1008
- func->hasEscapedUseNestedFunc = true ;
1009
- }
986
+ // Recursively restore enclosing scope info so outermost scopes/funcs are pushed first.
987
+ this ->RestoreScopeInfo (scopeInfo->GetParentScopeInfo (), func);
988
+ this ->RestoreOneScope (scopeInfo, func);
1010
989
1011
- Js::ScopeInfo* funcExprScopeInfo = scopeInfo->GetFuncExprScopeInfo ();
1012
- if (funcExprScopeInfo)
990
+ if (newFunc)
1013
991
{
1014
- Scope* funcExprScope = funcExprScopeInfo->GetScope ();
1015
- Assert (funcExprScope);
1016
- funcExprScope->SetFunc (func);
1017
- func->SetFuncExprScope (funcExprScope);
1018
- funcExprScopeInfo->GetScopeInfo (nullptr , this , func, funcExprScope);
1019
- }
1020
-
1021
- // Restore the param scope after the function expression scope
1022
- if (paramScope != nullptr )
1023
- {
1024
- paramScope->SetFunc (func);
1025
- paramScopeInfo->GetScopeInfo (nullptr , this , func, paramScope);
992
+ PushFuncInfo (_u (" RestoreScopeInfo" ), func);
993
+ if (!pfi->DoStackNestedFunc ())
994
+ {
995
+ func->hasEscapedUseNestedFunc = true ;
996
+ }
1026
997
}
1027
- scopeInfo->GetScopeInfo (nullptr , this , func, bodyScope);
1028
998
}
1029
999
else
1030
1000
{
1031
1001
Assert (this ->TopFuncInfo () == nullptr );
1032
1002
// funcBody is glo
1003
+ Assert (currentScope == nullptr );
1033
1004
currentScope = Anew (alloc, Scope, alloc, ScopeType_Global);
1034
1005
globalScope = currentScope;
1035
1006
1036
- FuncInfo *func = Anew (alloc, FuncInfo, Js::Constants::GlobalFunction,
1037
- alloc, nullptr , currentScope, nullptr , functionBody);
1038
- PushFuncInfo (_u (" RestoreScopeInfo" ), func);
1007
+ if (func == nullptr || !func->byteCodeFunction ->GetIsGlobalFunc ())
1008
+ {
1009
+ func = Anew (alloc, FuncInfo, Js::Constants::GlobalFunction,
1010
+ alloc, nullptr , nullptr /* currentScope*/ , nullptr , nullptr /* functionBody*/ );
1011
+ PushFuncInfo (_u (" RestoreScopeInfo" ), func);
1012
+ }
1013
+ func->SetBodyScope (currentScope);
1039
1014
}
1040
1015
}
1041
1016
1017
+ void ByteCodeGenerator::RestoreOneScope (Js::ScopeInfo * scopeInfo, FuncInfo * func)
1018
+ {
1019
+ TRACE_BYTECODE (_u (" \n Restore ScopeInfo: %s #symbols: %d %s\n " ),
1020
+ func->name , scopeInfo->GetSymbolCount (), scopeInfo->IsObject () ? _u (" isObject" ) : _u (" " ));
1021
+
1022
+ Scope * scope = scopeInfo->GetScope ();
1023
+
1024
+ scope->SetFunc (func);
1025
+
1026
+ switch (scope->GetScopeType ())
1027
+ {
1028
+ case ScopeType_Parameter:
1029
+ if (!scopeInfo->GetCanMergeWithBodyScope ())
1030
+ {
1031
+ scope->SetCannotMergeWithBodyScope ();
1032
+ }
1033
+ Assert (func->GetParamScope () == nullptr );
1034
+ func->SetParamScope (scope);
1035
+ break ;
1036
+
1037
+ case ScopeType_FuncExpr:
1038
+ Assert (func->GetFuncExprScope () == nullptr );
1039
+ func->SetFuncExprScope (scope);
1040
+ break ;
1041
+
1042
+ case ScopeType_FunctionBody:
1043
+ case ScopeType_GlobalEvalBlock:
1044
+ Assert (func->GetBodyScope () == nullptr || (func->GetBodyScope ()->GetScopeType () == ScopeType_Global && scope->GetScopeType () == ScopeType_GlobalEvalBlock));
1045
+ func->SetBodyScope (scope);
1046
+ func->SetHasCachedScope (scopeInfo->IsCached ());
1047
+ break ;
1048
+ }
1049
+
1050
+ Assert (!scopeInfo->IsCached () || scope == func->GetBodyScope ());
1051
+
1052
+ // scopeInfo->scope was created/saved during parsing.
1053
+ // We no longer need it by now.
1054
+ // Clear it to avoid GC false positive (arena memory later used by GC).
1055
+ scopeInfo->SetScope (nullptr );
1056
+ this ->PushScope (scope);
1057
+ }
1058
+
1042
1059
FuncInfo * ByteCodeGenerator::StartBindGlobalStatements (ParseNode *pnode)
1043
1060
{
1044
- if (parentScopeInfo && parentScopeInfo-> GetParent () && (!parentScopeInfo-> GetParent ()-> GetIsGlobalFunc () || parentScopeInfo-> GetParent ()-> IsEval ()) )
1061
+ if (parentScopeInfo)
1045
1062
{
1046
1063
Assert (CONFIG_FLAG (DeferNested));
1047
1064
trackEnvDepth = true ;
1048
- RestoreScopeInfo (parentScopeInfo-> GetParent () );
1065
+ RestoreScopeInfo (parentScopeInfo, nullptr );
1049
1066
trackEnvDepth = false ;
1050
1067
// "currentScope" is the parentFunc scope. This ensures the deferred func declaration
1051
1068
// symbol will bind to the func declaration symbol already available in parentFunc scope.
@@ -1211,7 +1228,7 @@ FuncInfo * ByteCodeGenerator::StartBindFunction(const char16 *name, uint nameLen
1211
1228
if (parsedFunctionBody->GetScopeInfo ())
1212
1229
{
1213
1230
// Propagate flags from the (real) parent function.
1214
- Js::ParseableFunctionInfo *parent = parsedFunctionBody->GetScopeInfo ()->GetParent ();
1231
+ Js::ParseableFunctionInfo *parent = parsedFunctionBody->GetScopeInfo ()->GetParseableFunctionInfo ();
1215
1232
if (parent)
1216
1233
{
1217
1234
if (parent->GetHasOrParentHasArguments ())
@@ -1632,7 +1649,8 @@ Symbol * ByteCodeGenerator::FindSymbol(Symbol **symRef, IdentPtr pid, bool forRe
1632
1649
1633
1650
bool didTransferToFncVarSym = false ;
1634
1651
1635
- if (!PHASE_OFF (Js::OptimizeBlockScopePhase, top->byteCodeFunction ) &&
1652
+ #pragma prefast(suppress:6237, "The right hand side condition does not have any side effects.")
1653
+ if (PHASE_ON (Js::OptimizeBlockScopePhase, top->byteCodeFunction ) &&
1636
1654
sym->GetIsBlockVar () &&
1637
1655
!sym->GetScope ()->IsBlockInLoop () &&
1638
1656
sym->GetSymbolType () == STFunction)
@@ -1755,7 +1773,7 @@ Symbol * ByteCodeGenerator::AddSymbolToScope(Scope *scope, const char16 *key, in
1755
1773
// on such compiles, so we essentially have to migrate the symbol to the new scope.
1756
1774
// We check fscrEvalCode, not fscrEval, because the same thing can happen in indirect eval,
1757
1775
// when fscrEval is not set.
1758
- Assert (scope->GetScopeType () == ScopeType_Global);
1776
+ Assert (scope->GetScopeType () == ScopeType_Global || scope-> GetScopeType () == ScopeType_GlobalEvalBlock );
1759
1777
scope->AddNewSymbol (sym);
1760
1778
}
1761
1779
@@ -1995,7 +2013,7 @@ void ByteCodeGenerator::Generate(__in ParseNode *pnode, uint32 grfscr, __in Byte
1995
2013
1996
2014
void ByteCodeGenerator::CheckDeferParseHasMaybeEscapedNestedFunc ()
1997
2015
{
1998
- if (!this ->parentScopeInfo || ( this -> parentScopeInfo -> GetParent () && this -> parentScopeInfo -> GetParent ()-> GetIsGlobalFunc ()) )
2016
+ if (!this ->parentScopeInfo )
1999
2017
{
2000
2018
return ;
2001
2019
}
@@ -2023,7 +2041,7 @@ void ByteCodeGenerator::CheckDeferParseHasMaybeEscapedNestedFunc()
2023
2041
else
2024
2042
{
2025
2043
// We have to wait until it is parsed before we populate the stack nested func parent.
2026
- FuncInfo * parentFunc = top->GetBodyScope ()->GetEnclosingFunc ();
2044
+ FuncInfo * parentFunc = top->GetParamScope () ? top-> GetParamScope ()-> GetEnclosingFunc () : top-> GetBodyScope ()->GetEnclosingFunc ();
2027
2045
if (!parentFunc->IsGlobalFunction ())
2028
2046
{
2029
2047
Assert (parentFunc->byteCodeFunction != rootFuncBody);
@@ -2040,6 +2058,11 @@ void ByteCodeGenerator::CheckDeferParseHasMaybeEscapedNestedFunc()
2040
2058
FuncInfo * funcInfo = i.Data ();
2041
2059
Assert (funcInfo->IsRestored ());
2042
2060
Js::ParseableFunctionInfo * parseableFunctionInfo = funcInfo->byteCodeFunction ;
2061
+ if (parseableFunctionInfo == nullptr )
2062
+ {
2063
+ Assert (funcInfo->GetBodyScope () && funcInfo->GetBodyScope ()->GetScopeType () == ScopeType_Global);
2064
+ return ;
2065
+ }
2043
2066
bool didStackNestedFunc = parseableFunctionInfo->DoStackNestedFunc ();
2044
2067
if (!didStackNestedFunc)
2045
2068
{
@@ -3247,6 +3270,7 @@ void AddFunctionsToScope(ParseNodePtr scope, ByteCodeGenerator * byteCodeGenerat
3247
3270
sym->GetScope () != sym->GetScope ()->GetFunc ()->GetParamScope ())
3248
3271
{
3249
3272
sym->SetIsBlockVar (true );
3273
+ sym->SetHasRealBlockVarRef (true );
3250
3274
}
3251
3275
}
3252
3276
});
@@ -3629,15 +3653,21 @@ void PostVisitBlock(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
3629
3653
return ;
3630
3654
}
3631
3655
3656
+ Scope *scope = pnode->sxBlock .scope ;
3657
+
3632
3658
if (pnode->sxBlock .GetCallsEval () || pnode->sxBlock .GetChildCallsEval () || (byteCodeGenerator->GetFlags () & (fscrEval | fscrImplicitThis | fscrImplicitParents)))
3633
3659
{
3634
- Scope *scope = pnode->sxBlock .scope ;
3635
3660
bool scopeIsEmpty = scope->IsEmpty ();
3636
3661
scope->SetIsObject ();
3637
3662
scope->SetCapturesAll (true );
3638
3663
scope->SetMustInstantiate (!scopeIsEmpty);
3639
3664
}
3640
3665
3666
+ if (scope->GetHasOwnLocalInClosure ())
3667
+ {
3668
+ byteCodeGenerator->ProcessScopeWithCapturedSym (scope);
3669
+ }
3670
+
3641
3671
byteCodeGenerator->PopScope ();
3642
3672
byteCodeGenerator->PopBlock ();
3643
3673
@@ -3686,6 +3716,11 @@ void PreVisitCatch(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
3686
3716
3687
3717
void PostVisitCatch (ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
3688
3718
{
3719
+ Scope *scope = pnode->sxCatch .scope ;
3720
+ if (scope->GetHasOwnLocalInClosure ())
3721
+ {
3722
+ byteCodeGenerator->ProcessScopeWithCapturedSym (scope);
3723
+ }
3689
3724
byteCodeGenerator->EndBindCatch ();
3690
3725
}
3691
3726
0 commit comments