提交 bc1585d8 编写于 作者: A Andy Gocke

Refactor out LambdaRewriter.Analysis visitors

Duplicate functionality of existing LambdaRewriter.Analysis visitors
with the new Scope tree visitors and assert that the same results are
produced.
上级 b07c0d43
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities; using Roslyn.Utilities;
using System.Linq;
namespace Microsoft.CodeAnalysis.CSharp namespace Microsoft.CodeAnalysis.CSharp
{ {
...@@ -40,7 +39,13 @@ public sealed class Scope ...@@ -40,7 +39,13 @@ public sealed class Scope
/// in this scope or nested scopes. "Declared" refers to the start of the variable /// in this scope or nested scopes. "Declared" refers to the start of the variable
/// lifetime (which, at this point in lowering, should be equivalent to lexical scope). /// lifetime (which, at this point in lowering, should be equivalent to lexical scope).
/// </summary> /// </summary>
public ArrayBuilder<Symbol> DeclaredVariables { get; } = ArrayBuilder<Symbol>.GetInstance(); /// <remarks>
/// It's important that this is a set and that enumeration order is deterministic. We loop
/// over this list to generate proxies and if we loop out of order this will cause
/// non-deterministic compilation, and if we generate duplicate proxies we'll generate
/// wasteful code in the best case and incorrect code in the worst.
/// </remarks>
public SetWithInsertionOrder<Symbol> DeclaredVariables { get; } = new SetWithInsertionOrder<Symbol>();
/// <summary> /// <summary>
/// The bound node representing this scope. This roughly corresponds to the bound /// The bound node representing this scope. This roughly corresponds to the bound
...@@ -54,7 +59,7 @@ public sealed class Scope ...@@ -54,7 +59,7 @@ public sealed class Scope
/// The closure that this scope is nested inside. Null if this scope is not nested /// The closure that this scope is nested inside. Null if this scope is not nested
/// inside a closure. /// inside a closure.
/// </summary> /// </summary>
public Closure ContainingClosure { get; } public Closure ContainingClosureOpt { get; }
public Scope(Scope parent, BoundNode boundNode, Closure containingClosure) public Scope(Scope parent, BoundNode boundNode, Closure containingClosure)
{ {
...@@ -62,7 +67,7 @@ public Scope(Scope parent, BoundNode boundNode, Closure containingClosure) ...@@ -62,7 +67,7 @@ public Scope(Scope parent, BoundNode boundNode, Closure containingClosure)
Parent = parent; Parent = parent;
BoundNode = boundNode; BoundNode = boundNode;
ContainingClosure = containingClosure; ContainingClosureOpt = containingClosure;
} }
public void Free() public void Free()
...@@ -78,7 +83,6 @@ public void Free() ...@@ -78,7 +83,6 @@ public void Free()
closure.Free(); closure.Free();
} }
Closures.Free(); Closures.Free();
DeclaredVariables.Free();
} }
public override string ToString() => BoundNode.Syntax.GetText().ToString(); public override string ToString() => BoundNode.Syntax.GetText().ToString();
...@@ -118,7 +122,7 @@ public void Free() ...@@ -118,7 +122,7 @@ public void Free()
/// Optimizes local functions such that if a local function only references other local functions /// Optimizes local functions such that if a local function only references other local functions
/// that capture no variables, we don't need to create capture environments for any of them. /// that capture no variables, we don't need to create capture environments for any of them.
/// </summary> /// </summary>
private void RemoveUnneededReferences() private void RemoveUnneededReferences(ParameterSymbol thisParam)
{ {
var methodGraph = new MultiDictionary<MethodSymbol, MethodSymbol>(); var methodGraph = new MultiDictionary<MethodSymbol, MethodSymbol>();
var capturesThis = new HashSet<MethodSymbol>(); var capturesThis = new HashSet<MethodSymbol>();
...@@ -132,7 +136,7 @@ private void RemoveUnneededReferences() ...@@ -132,7 +136,7 @@ private void RemoveUnneededReferences()
{ {
methodGraph.Add(localFunc, closure.OriginalMethodSymbol); methodGraph.Add(localFunc, closure.OriginalMethodSymbol);
} }
else if (capture == _topLevelMethod.ThisParameter) else if (capture == thisParam)
{ {
if (capturesThis.Add(closure.OriginalMethodSymbol)) if (capturesThis.Add(closure.OriginalMethodSymbol))
{ {
...@@ -168,7 +172,7 @@ private void RemoveUnneededReferences() ...@@ -168,7 +172,7 @@ private void RemoveUnneededReferences()
} }
if (capturesThis.Contains(closure.OriginalMethodSymbol)) if (capturesThis.Contains(closure.OriginalMethodSymbol))
{ {
closure.CapturedVariables.Add(_topLevelMethod.ThisParameter); closure.CapturedVariables.Add(thisParam);
} }
}); });
} }
...@@ -191,7 +195,7 @@ public static void VisitClosures(Scope scope, Action<Scope, Closure> action) ...@@ -191,7 +195,7 @@ public static void VisitClosures(Scope scope, Action<Scope, Closure> action)
/// <summary> /// <summary>
/// Builds a tree of <see cref="Scope"/> nodes corresponding to a given method. /// Builds a tree of <see cref="Scope"/> nodes corresponding to a given method.
/// <see cref="Build(BoundNode, Analysis)"/> visits the bound tree and translates /// <see cref="Build(BoundNode, MethodSymbol, HashSet{MethodSymbol})"/> visits the bound tree and translates
/// information from the bound tree about variable scope, declared variables, and /// information from the bound tree about variable scope, declared variables, and
/// variable captures into the resulting <see cref="Scope"/> tree. /// variable captures into the resulting <see cref="Scope"/> tree.
/// </summary> /// </summary>
...@@ -211,32 +215,53 @@ private class ScopeTreeBuilder : BoundTreeWalkerWithStackGuardWithoutRecursionOn ...@@ -211,32 +215,53 @@ private class ScopeTreeBuilder : BoundTreeWalkerWithStackGuardWithoutRecursionOn
/// </summary> /// </summary>
private readonly SmallDictionary<Symbol, Scope> _localToScope = new SmallDictionary<Symbol, Scope>(); private readonly SmallDictionary<Symbol, Scope> _localToScope = new SmallDictionary<Symbol, Scope>();
private readonly Analysis _analysis; private readonly MethodSymbol _topLevelMethod;
private ScopeTreeBuilder(Scope rootScope, Analysis analysis) private bool _sawClosure = false;
/// <summary>
/// If a local function is in the set, at some point in the code it is converted
/// to a delegate and should then not be optimized to a struct closure.
/// Also contains all lambdas (as they are converted to delegates implicitly).
/// </summary>
private readonly HashSet<MethodSymbol> _methodsConvertedToDelegates;
private ScopeTreeBuilder(
Scope rootScope,
MethodSymbol topLevelMethod,
HashSet<MethodSymbol> methodsConvertedToDelegates)
{ {
Debug.Assert(rootScope != null); Debug.Assert(rootScope != null);
Debug.Assert(analysis != null); Debug.Assert(topLevelMethod != null);
Debug.Assert(methodsConvertedToDelegates != null);
_currentScope = rootScope; _currentScope = rootScope;
_analysis = analysis; _topLevelMethod = topLevelMethod;
_methodsConvertedToDelegates = methodsConvertedToDelegates;
} }
public static Scope Build(BoundNode node, Analysis analysis) public static Scope Build(
BoundNode node,
MethodSymbol topLevelMethod,
HashSet<MethodSymbol> methodsConvertedToDelegates)
{ {
// This should be the top-level node // This should be the top-level node
Debug.Assert(node == FindNodeToAnalyze(node)); Debug.Assert(node == FindNodeToAnalyze(node));
Debug.Assert(topLevelMethod != null);
var rootScope = new Scope(parent: null, boundNode: node, containingClosure: null); var rootScope = new Scope(parent: null, boundNode: node, containingClosure: null);
var builder = new ScopeTreeBuilder(rootScope, analysis); var builder = new ScopeTreeBuilder(
rootScope,
topLevelMethod,
methodsConvertedToDelegates);
builder.Build(); builder.Build();
return rootScope; return builder._sawClosure ? rootScope : null;
} }
private void Build() private void Build()
{ {
// Set up the current method locals // Set up the current method locals
DeclareLocals(_currentScope, _analysis._topLevelMethod.Parameters); DeclareLocals(_currentScope, _topLevelMethod.Parameters);
Visit(_currentScope.BoundNode); Visit(_currentScope.BoundNode);
} }
...@@ -260,6 +285,11 @@ public override BoundNode VisitBlock(BoundBlock node) ...@@ -260,6 +285,11 @@ public override BoundNode VisitBlock(BoundBlock node)
public override BoundNode VisitCatchBlock(BoundCatchBlock node) public override BoundNode VisitCatchBlock(BoundCatchBlock node)
{ {
if (node.Locals.IsDefaultOrEmpty)
{
return base.VisitCatchBlock(node);
}
var oldScope = _currentScope; var oldScope = _currentScope;
_currentScope = CreateOrReuseScope(node, node.Locals); _currentScope = CreateOrReuseScope(node, node.Locals);
var result = base.VisitCatchBlock(node); var result = base.VisitCatchBlock(node);
...@@ -269,6 +299,11 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node) ...@@ -269,6 +299,11 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
public override BoundNode VisitSequence(BoundSequence node) public override BoundNode VisitSequence(BoundSequence node)
{ {
if (node.Locals.IsDefaultOrEmpty)
{
return base.VisitSequence(node);
}
var oldScope = _currentScope; var oldScope = _currentScope;
_currentScope = CreateOrReuseScope(node, node.Locals); _currentScope = CreateOrReuseScope(node, node.Locals);
var result = base.VisitSequence(node); var result = base.VisitSequence(node);
...@@ -296,7 +331,7 @@ public override BoundNode VisitLambda(BoundLambda node) ...@@ -296,7 +331,7 @@ public override BoundNode VisitLambda(BoundLambda node)
var oldInExpressionTree = _inExpressionTree; var oldInExpressionTree = _inExpressionTree;
_inExpressionTree |= node.Type.IsExpressionTree(); _inExpressionTree |= node.Type.IsExpressionTree();
_analysis.MethodsConvertedToDelegates.Add(node.Symbol.OriginalDefinition); _methodsConvertedToDelegates.Add(node.Symbol.OriginalDefinition);
var result = VisitClosure(node.Symbol, node.Body); var result = VisitClosure(node.Symbol, node.Body);
_inExpressionTree = oldInExpressionTree; _inExpressionTree = oldInExpressionTree;
...@@ -323,7 +358,7 @@ public override BoundNode VisitDelegateCreationExpression(BoundDelegateCreationE ...@@ -323,7 +358,7 @@ public override BoundNode VisitDelegateCreationExpression(BoundDelegateCreationE
// Use OriginalDefinition to strip generic type parameters // Use OriginalDefinition to strip generic type parameters
var method = node.MethodOpt.OriginalDefinition; var method = node.MethodOpt.OriginalDefinition;
AddIfCaptured(method); AddIfCaptured(method);
_analysis.MethodsConvertedToDelegates.Add(method); _methodsConvertedToDelegates.Add(method);
} }
return base.VisitDelegateCreationExpression(node); return base.VisitDelegateCreationExpression(node);
} }
...@@ -342,13 +377,13 @@ public override BoundNode VisitLocal(BoundLocal node) ...@@ -342,13 +377,13 @@ public override BoundNode VisitLocal(BoundLocal node)
public override BoundNode VisitBaseReference(BoundBaseReference node) public override BoundNode VisitBaseReference(BoundBaseReference node)
{ {
AddIfCaptured(_analysis._topLevelMethod.ThisParameter); AddIfCaptured(_topLevelMethod.ThisParameter);
return base.VisitBaseReference(node); return base.VisitBaseReference(node);
} }
public override BoundNode VisitThisReference(BoundThisReference node) public override BoundNode VisitThisReference(BoundThisReference node)
{ {
var thisParam = _analysis._topLevelMethod.ThisParameter; var thisParam = _topLevelMethod.ThisParameter;
if (thisParam != null) if (thisParam != null)
{ {
AddIfCaptured(thisParam); AddIfCaptured(thisParam);
...@@ -373,6 +408,8 @@ private BoundNode VisitClosure(MethodSymbol closureSymbol, BoundBlock body) ...@@ -373,6 +408,8 @@ private BoundNode VisitClosure(MethodSymbol closureSymbol, BoundBlock body)
{ {
Debug.Assert((object)closureSymbol != null); Debug.Assert((object)closureSymbol != null);
_sawClosure |= true;
// Closure is declared (lives) in the parent scope, but its // Closure is declared (lives) in the parent scope, but its
// variables are in a nested scope // variables are in a nested scope
var closure = new Closure(closureSymbol); var closure = new Closure(closureSymbol);
...@@ -426,11 +463,11 @@ private void AddIfCaptured(Symbol symbol) ...@@ -426,11 +463,11 @@ private void AddIfCaptured(Symbol symbol)
closure.CapturedVariables.Add(symbol); closure.CapturedVariables.Add(symbol);
// Also mark captured in enclosing scopes // Also mark captured in enclosing scopes
while (scope.ContainingClosure == closure) while (scope.ContainingClosureOpt == closure)
{ {
scope = scope.Parent; scope = scope.Parent;
} }
closure = scope.ContainingClosure; closure = scope.ContainingClosureOpt;
} }
// Also record where the captured variable lives // Also record where the captured variable lives
......
...@@ -28,11 +28,6 @@ internal sealed partial class Analysis : BoundTreeWalkerWithStackGuardWithoutRec ...@@ -28,11 +28,6 @@ internal sealed partial class Analysis : BoundTreeWalkerWithStackGuardWithoutRec
/// </summary> /// </summary>
private bool _inExpressionLambda; private bool _inExpressionLambda;
/// <summary>
/// Set to true of any lambda expressions were seen in the analyzed method body.
/// </summary>
public bool SeenLambda { get; private set; }
/// <summary> /// <summary>
/// For each scope that defines variables, identifies the nearest enclosing scope that defines variables. /// For each scope that defines variables, identifies the nearest enclosing scope that defines variables.
/// </summary> /// </summary>
...@@ -116,12 +111,15 @@ public static Analysis Analyze(BoundNode node, MethodSymbol method) ...@@ -116,12 +111,15 @@ public static Analysis Analyze(BoundNode node, MethodSymbol method)
{ {
var analysis = new Analysis(method); var analysis = new Analysis(method);
analysis.Analyze(node); analysis.Analyze(node);
return analysis; return analysis.ScopeTree == null ? null : analysis;
} }
private void Analyze(BoundNode node) private void Analyze(BoundNode node)
{ {
ScopeTree = ScopeTreeBuilder.Build(node, this); ScopeTree = ScopeTreeBuilder.Build(
node,
_topLevelMethod,
MethodsConvertedToDelegates);
_currentScope = FindNodeToAnalyze(node); _currentScope = FindNodeToAnalyze(node);
Debug.Assert(!_inExpressionLambda); Debug.Assert(!_inExpressionLambda);
...@@ -181,9 +179,9 @@ private static BoundNode FindNodeToAnalyze(BoundNode node) ...@@ -181,9 +179,9 @@ private static BoundNode FindNodeToAnalyze(BoundNode node)
/// <summary> /// <summary>
/// Create the optimized plan for the location of lambda methods and whether scopes need access to parent scopes /// Create the optimized plan for the location of lambda methods and whether scopes need access to parent scopes
/// </summary> /// </summary>
internal void ComputeLambdaScopesAndFrameCaptures() internal void ComputeLambdaScopesAndFrameCaptures(ParameterSymbol thisParam)
{ {
RemoveUnneededReferences(); RemoveUnneededReferences(thisParam);
LambdaScopes = new Dictionary<MethodSymbol, BoundNode>(ReferenceEqualityComparer.Instance); LambdaScopes = new Dictionary<MethodSymbol, BoundNode>(ReferenceEqualityComparer.Instance);
NeedsParentFrame = new HashSet<BoundNode>(); NeedsParentFrame = new HashSet<BoundNode>();
...@@ -284,7 +282,76 @@ void RecordClosureScope(Scope innermost, Scope outermost, Closure closure) ...@@ -284,7 +282,76 @@ void RecordClosureScope(Scope innermost, Scope outermost, Closure closure)
} }
} }
} }
}
}
/// <summary>
/// Walk up the scope tree looking for a variable declaration.
/// </summary>
public static Scope GetVariableDeclarationScope(Scope startingScope, Symbol variable)
{
if (variable is ParameterSymbol p && p.IsThis)
{
return null;
}
var currentScope = startingScope;
while (currentScope != null)
{
if (variable.Kind == SymbolKind.Parameter || variable.Kind == SymbolKind.Local)
{
if (currentScope.DeclaredVariables.Contains(variable))
{
return currentScope;
}
}
else
{
if (currentScope.Closures.Contains(c => variable == c.OriginalMethodSymbol))
{
return currentScope;
}
}
currentScope = currentScope.Parent;
}
return null;
}
/// <summary>
/// Find the parent <see cref="Scope"/> of the <see cref="Scope"/> corresponding to
/// the given <see cref="BoundNode"/>.
/// </summary>
public static Scope GetScopeParent(Scope treeRoot, BoundNode scopeNode)
{
var correspondingScope = GetScopeWithMatchingBoundNode(treeRoot, scopeNode);
return correspondingScope.Parent;
}
/// <summary>
/// Finds a <see cref="Scope" /> with a matching <see cref="BoundNode"/>
/// as the one given.
/// </summary>
public static Scope GetScopeWithMatchingBoundNode(Scope treeRoot, BoundNode node)
{
return Helper(treeRoot) ?? throw ExceptionUtilities.Unreachable;
Scope Helper(Scope currentScope)
{
if (currentScope.BoundNode == node)
{
return currentScope;
}
foreach (var nestedScope in currentScope.NestedScopes)
{
var found = Helper(nestedScope);
if (found != null)
{
return found;
}
}
return null;
} }
} }
...@@ -488,7 +555,6 @@ public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatemen ...@@ -488,7 +555,6 @@ public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatemen
private BoundNode VisitLambdaOrFunction(IBoundLambdaOrFunction node) private BoundNode VisitLambdaOrFunction(IBoundLambdaOrFunction node)
{ {
Debug.Assert((object)node.Symbol != null); Debug.Assert((object)node.Symbol != null);
SeenLambda = true;
var oldParent = _currentParent; var oldParent = _currentParent;
var oldBlock = _currentScope; var oldBlock = _currentScope;
_currentParent = node.Symbol; _currentParent = node.Symbol;
......
...@@ -228,13 +228,8 @@ protected override bool NeedsProxy(Symbol localOrParameter) ...@@ -228,13 +228,8 @@ protected override bool NeedsProxy(Symbol localOrParameter)
Debug.Assert(compilationState.ModuleBuilderOpt != null); Debug.Assert(compilationState.ModuleBuilderOpt != null);
var analysis = Analysis.Analyze(loweredBody, method); var analysis = Analysis.Analyze(loweredBody, method);
if (!analysis.SeenLambda) if (analysis == null)
{ {
// Unreachable anonymous functions are ignored by the analyzer.
// No closures or lambda methods are generated.
// E.g.
// int y = 0;
// var b = false && (from z in new X(y) select f(z + y))
return loweredBody; return loweredBody;
} }
...@@ -252,7 +247,7 @@ protected override bool NeedsProxy(Symbol localOrParameter) ...@@ -252,7 +247,7 @@ protected override bool NeedsProxy(Symbol localOrParameter)
diagnostics, diagnostics,
assignLocals); assignLocals);
analysis.ComputeLambdaScopesAndFrameCaptures(); analysis.ComputeLambdaScopesAndFrameCaptures(thisParameter);
rewriter.MakeFrames(closureDebugInfoBuilder); rewriter.MakeFrames(closureDebugInfoBuilder);
// First, lower everything but references (calls, delegate conversions) // First, lower everything but references (calls, delegate conversions)
...@@ -341,8 +336,14 @@ private void MakeFrames(ArrayBuilder<ClosureDebugInfo> closureDebugInfo) ...@@ -341,8 +336,14 @@ private void MakeFrames(ArrayBuilder<ClosureDebugInfo> closureDebugInfo)
foreach (var captured in capturedVars) foreach (var captured in capturedVars)
{ {
if (!_analysis.VariableScope.TryGetValue(captured, out BoundNode captureScope)) var declarationScope = Analysis.GetVariableDeclarationScope(scope, captured);
if (_analysis.VariableScope.TryGetValue(captured, out BoundNode captureScope))
{ {
Debug.Assert(declarationScope.BoundNode == captureScope);
}
else
{
Debug.Assert(declarationScope == null);
continue; continue;
} }
...@@ -357,7 +358,7 @@ private void MakeFrames(ArrayBuilder<ClosureDebugInfo> closureDebugInfo) ...@@ -357,7 +358,7 @@ private void MakeFrames(ArrayBuilder<ClosureDebugInfo> closureDebugInfo)
continue; continue;
} }
LambdaFrame frame = GetFrameForScope(captureScope, closureDebugInfo); LambdaFrame frame = GetFrameForScope(declarationScope, closureDebugInfo);
if (captured.Kind != SymbolKind.Method && !proxies.ContainsKey(captured)) if (captured.Kind != SymbolKind.Method && !proxies.ContainsKey(captured))
{ {
...@@ -450,26 +451,28 @@ private void MakeFrames(ArrayBuilder<ClosureDebugInfo> closureDebugInfo) ...@@ -450,26 +451,28 @@ private void MakeFrames(ArrayBuilder<ClosureDebugInfo> closureDebugInfo)
return result; return result;
} }
private LambdaFrame GetFrameForScope(BoundNode scope, ArrayBuilder<ClosureDebugInfo> closureDebugInfo) private LambdaFrame GetFrameForScope(Analysis.Scope scope, ArrayBuilder<ClosureDebugInfo> closureDebugInfo)
{ {
var scopeBoundNode = scope.BoundNode;
LambdaFrame frame; LambdaFrame frame;
if (!_frames.TryGetValue(scope, out frame)) if (!_frames.TryGetValue(scopeBoundNode, out frame))
{ {
var syntax = scope.Syntax; var syntax = scopeBoundNode.Syntax;
Debug.Assert(syntax != null); Debug.Assert(syntax != null);
DebugId methodId = GetTopLevelMethodId(); DebugId methodId = GetTopLevelMethodId();
DebugId closureId = GetClosureId(syntax, closureDebugInfo); DebugId closureId = GetClosureId(syntax, closureDebugInfo);
var canBeStruct = !_analysis.ScopesThatCantBeStructs.Contains(scope); var canBeStruct = !_analysis.ScopesThatCantBeStructs.Contains(scopeBoundNode);
var containingMethod = _analysis.ScopeOwner[scope]; var containingMethod = scope.ContainingClosureOpt?.OriginalMethodSymbol ?? _topLevelMethod;
Debug.Assert(containingMethod == _analysis.ScopeOwner[scopeBoundNode]);
if (_substitutedSourceMethod != null && containingMethod == _topLevelMethod) if (_substitutedSourceMethod != null && containingMethod == _topLevelMethod)
{ {
containingMethod = _substitutedSourceMethod; containingMethod = _substitutedSourceMethod;
} }
frame = new LambdaFrame(_topLevelMethod, containingMethod, canBeStruct, syntax, methodId, closureId); frame = new LambdaFrame(_topLevelMethod, containingMethod, canBeStruct, syntax, methodId, closureId);
_frames.Add(scope, frame); _frames.Add(scopeBoundNode, frame);
CompilationState.ModuleBuilderOpt.AddSynthesizedDefinition(ContainingType, frame); CompilationState.ModuleBuilderOpt.AddSynthesizedDefinition(ContainingType, frame);
if (frame.Constructor != null) if (frame.Constructor != null)
...@@ -701,14 +704,20 @@ private BoundNode IntroduceFrame(BoundNode node, LambdaFrame frame, Func<ArrayBu ...@@ -701,14 +704,20 @@ private BoundNode IntroduceFrame(BoundNode node, LambdaFrame frame, Func<ArrayBu
// Capture any parameters of this block. This would typically occur // Capture any parameters of this block. This would typically occur
// at the top level of a method or lambda with captured parameters. // at the top level of a method or lambda with captured parameters.
// TODO: speed up the following by computing it in analysis. // TODO: speed up the following by computing it in analysis.
var scope = Analysis.GetScopeWithMatchingBoundNode(_analysis.ScopeTree, node);
var variablesInThisScope = ArrayBuilder<Symbol>.GetInstance();
foreach (var variable in _analysis.CapturedVariables.Keys) foreach (var variable in _analysis.CapturedVariables.Keys)
{ {
BoundNode varNode; if (variable.Kind != SymbolKind.Method &&
if (!_analysis.VariableScope.TryGetValue(variable, out varNode) || varNode != node) _analysis.VariableScope.TryGetValue(variable, out var varNode) &&
varNode == node)
{ {
continue; variablesInThisScope.Add(variable);
} }
}
Debug.Assert(variablesInThisScope.SequenceEqual(scope.DeclaredVariables));
foreach (var variable in variablesInThisScope)
{
InitVariableProxy(syntax, variable, framePointer, prologue); InitVariableProxy(syntax, variable, framePointer, prologue);
} }
...@@ -1360,7 +1369,8 @@ private DebugId GetLambdaId(SyntaxNode syntax, ClosureKind closureKind, int clos ...@@ -1360,7 +1369,8 @@ private DebugId GetLambdaId(SyntaxNode syntax, ClosureKind closureKind, int clos
// strictly need `this`. // strictly need `this`.
if (_analysis.CanTakeRefParameters(node.Symbol)) if (_analysis.CanTakeRefParameters(node.Symbol))
{ {
lambdaScope = _analysis.ScopeParent[node.Body]; lambdaScope = Analysis.GetScopeParent(_analysis.ScopeTree, node.Body)?.BoundNode;
Debug.Assert(lambdaScope == _analysis.ScopeParent[node.Body]);
_ = _frames.TryGetValue(lambdaScope, out containerAsFrame); _ = _frames.TryGetValue(lambdaScope, out containerAsFrame);
structClosures = GetStructClosures(containerAsFrame, lambdaScope); structClosures = GetStructClosures(containerAsFrame, lambdaScope);
} }
...@@ -1468,12 +1478,18 @@ private ImmutableArray<TypeSymbol> GetStructClosures(LambdaFrame containerAsFram ...@@ -1468,12 +1478,18 @@ private ImmutableArray<TypeSymbol> GetStructClosures(LambdaFrame containerAsFram
bool FindParentFrame(ref LambdaFrame container, ref BoundNode scope) bool FindParentFrame(ref LambdaFrame container, ref BoundNode scope)
{ {
while (_analysis.ScopeParent.TryGetValue(scope, out scope)) var temp = Analysis.GetScopeParent(_analysis.ScopeTree, scope)?.BoundNode;
Debug.Assert(temp == null || _analysis.ScopeParent.TryGetValue(scope, out var tempScope) && tempScope == temp);
scope = temp;
while (scope != null)
{ {
if (_frames.TryGetValue(scope, out container)) if (_frames.TryGetValue(scope, out container))
{ {
return true; return true;
} }
temp = Analysis.GetScopeParent(_analysis.ScopeTree, scope)?.BoundNode;
Debug.Assert(temp == null || _analysis.ScopeParent.TryGetValue(scope, out tempScope) && tempScope == temp);
scope = temp;
} }
return false; return false;
} }
...@@ -1552,8 +1568,9 @@ private BoundNode RewriteLambdaConversion(BoundLambda node) ...@@ -1552,8 +1568,9 @@ private BoundNode RewriteLambdaConversion(BoundLambda node)
// NOTE: We require "lambdaScope != null". // NOTE: We require "lambdaScope != null".
// We do not want to introduce a field into an actual user's class (not a synthetic frame). // We do not want to introduce a field into an actual user's class (not a synthetic frame).
Debug.Assert(Analysis.GetScopeParent(_analysis.ScopeTree, node.Body).BoundNode == _analysis.ScopeParent[node.Body]);
var shouldCacheInLoop = lambdaScope != null && var shouldCacheInLoop = lambdaScope != null &&
lambdaScope != _analysis.ScopeParent[node.Body] && lambdaScope != Analysis.GetScopeParent(_analysis.ScopeTree, node.Body).BoundNode &&
InLoopOrLambda(node.Syntax, lambdaScope.Syntax); InLoopOrLambda(node.Syntax, lambdaScope.Syntax);
if (shouldCacheForStaticMethod || shouldCacheInLoop) if (shouldCacheForStaticMethod || shouldCacheInLoop)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册