提交 8fd67124 编写于 作者: A Andrew Casey

Introduce a hoisted local scope abstraction

Since hoisted locals are fields, they are in scope throughout the entire
method body.  However, from the user's perspective, they are still locals,
so we attempt to retain their original scopes during debugging.
Unfortunately, C# and VB use different mechanisms for doing so.  In order
to make the code more consistent, and to simplify consumption of the new
PDB format (which is more similar to C#), we introduce an abstract type
InScopeHoistedLocals that represents the set of in-scope hoisted locals in
a consistent way in both languages (and both PDB formats).
上级 522f532a
......@@ -67,6 +67,7 @@
<Compile Include="Binders\EEMethodBinder.cs" />
<Compile Include="Binders\WithTypeArgumentsBinder.cs" />
<Compile Include="Binders\PlaceholderLocalBinder.cs" />
<Compile Include="CSharpInScopeHoistedLocals.cs" />
<Compile Include="SymUnmanagedReaderExtensions.cs" />
<Compile Include="CompilationContext.cs" />
<Compile Include="CompilationExtensions.cs" />
......@@ -118,4 +119,4 @@
<Import Project="..\..\..\..\..\build\VSL.Imports.Closed.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
internal sealed class CSharpInScopeHoistedLocals : InScopeHoistedLocals
{
private readonly ImmutableSortedSet<int> _indices;
public CSharpInScopeHoistedLocals(ImmutableSortedSet<int> indices)
{
_indices = indices;
}
public override bool IsInScope(string fieldName)
{
int index;
if (GeneratedNames.TryParseSlotIndex(fieldName, out index))
{
return _indices.Contains(index);
}
else
{
Debug.Assert(false, $"Expected hoisted local field name, found '{fieldName}'");
return true;
}
}
}
}
......@@ -49,7 +49,7 @@ internal sealed class CompilationContext
MetadataDecoder metadataDecoder,
MethodSymbol currentFrame,
ImmutableArray<LocalSymbol> locals,
ImmutableSortedSet<int> inScopeHoistedLocalIndices,
InScopeHoistedLocals inScopeHoistedLocals,
MethodDebugInfo methodDebugInfo,
CSharpSyntaxNode syntax)
{
......@@ -88,7 +88,7 @@ internal sealed class CompilationContext
GetDisplayClassVariables(
currentFrame,
_locals,
inScopeHoistedLocalIndices,
inScopeHoistedLocals,
out displayClassVariableNamesInOrder,
out _displayClassVariables,
out _hoistedParameterNames);
......@@ -1053,7 +1053,7 @@ private static DkmClrCompilationResultFlags GetLocalResultFlags(LocalSymbol loca
private static void GetDisplayClassVariables(
MethodSymbol method,
ImmutableArray<LocalSymbol> locals,
ImmutableSortedSet<int> inScopeHoistedLocalIndices,
InScopeHoistedLocals inScopeHoistedLocals,
out ImmutableArray<string> displayClassVariableNamesInOrder,
out ImmutableDictionary<string, DisplayClassVariable> displayClassVariables,
out ImmutableHashSet<string> hoistedParameterNames)
......@@ -1133,7 +1133,7 @@ private static DkmClrCompilationResultFlags GetLocalResultFlags(LocalSymbol loca
displayClassVariableNamesInOrderBuilder,
displayClassVariablesBuilder,
parameterNames,
inScopeHoistedLocalIndices,
inScopeHoistedLocals,
instance,
pooledHoistedParameterNames);
}
......@@ -1220,7 +1220,7 @@ private static DkmClrCompilationResultFlags GetLocalResultFlags(LocalSymbol loca
ArrayBuilder<string> displayClassVariableNamesInOrderBuilder,
Dictionary<string, DisplayClassVariable> displayClassVariablesBuilder,
HashSet<string> parameterNames,
ImmutableSortedSet<int> inScopeHoistedLocalIndices,
InScopeHoistedLocals inScopeHoistedLocals,
DisplayClassInstanceAndFields instance,
HashSet<string> hoistedParameterNames)
{
......@@ -1252,8 +1252,7 @@ private static DkmClrCompilationResultFlags GetLocalResultFlags(LocalSymbol loca
// Filter out hoisted locals that are known to be out-of-scope at the current IL offset.
// Hoisted locals with invalid indices will be included since more information is better
// than less in error scenarios.
int slotIndex;
if (GeneratedNames.TryParseSlotIndex(fieldName, out slotIndex) && !inScopeHoistedLocalIndices.Contains(slotIndex))
if (!inScopeHoistedLocals.IsInScope(fieldName))
{
continue;
}
......
......@@ -32,7 +32,7 @@ internal sealed class EvaluationContext : EvaluationContextBase
private readonly MetadataDecoder _metadataDecoder;
private readonly MethodSymbol _currentFrame;
private readonly ImmutableArray<LocalSymbol> _locals;
private readonly ImmutableSortedSet<int> _inScopeHoistedLocalIndices;
private readonly InScopeHoistedLocals _inScopeHoistedLocals;
private readonly MethodDebugInfo _methodDebugInfo;
private EvaluationContext(
......@@ -42,10 +42,10 @@ internal sealed class EvaluationContext : EvaluationContextBase
MetadataDecoder metadataDecoder,
MethodSymbol currentFrame,
ImmutableArray<LocalSymbol> locals,
ImmutableSortedSet<int> inScopeHoistedLocalIndices,
InScopeHoistedLocals inScopeHoistedLocals,
MethodDebugInfo methodDebugInfo)
{
Debug.Assert(inScopeHoistedLocalIndices != null);
Debug.Assert(inScopeHoistedLocals != null);
this.MetadataBlocks = metadataBlocks;
this.MethodContextReuseConstraints = methodContextReuseConstraints;
......@@ -53,7 +53,7 @@ internal sealed class EvaluationContext : EvaluationContextBase
_metadataDecoder = metadataDecoder;
_currentFrame = currentFrame;
_locals = locals;
_inScopeHoistedLocalIndices = inScopeHoistedLocalIndices;
_inScopeHoistedLocals = inScopeHoistedLocals;
_methodDebugInfo = methodDebugInfo;
}
......@@ -93,7 +93,7 @@ internal sealed class EvaluationContext : EvaluationContextBase
metadataDecoder,
currentFrame,
default(ImmutableArray<LocalSymbol>),
ImmutableSortedSet<int>.Empty,
InScopeHoistedLocals.Empty,
default(MethodDebugInfo));
}
......@@ -149,7 +149,7 @@ internal sealed class EvaluationContext : EvaluationContextBase
var localNames = containingScopes.GetLocalNames();
var inScopeHoistedLocalIndices = ImmutableSortedSet<int>.Empty;
var inScopeHoistedLocals = InScopeHoistedLocals.Empty;
var methodDebugInfo = default(MethodDebugInfo);
if (typedSymReader != null)
......@@ -158,7 +158,8 @@ internal sealed class EvaluationContext : EvaluationContextBase
{
// TODO (https://github.com/dotnet/roslyn/issues/702): switch on the type of typedSymReader and call the appropriate helper.
methodDebugInfo = typedSymReader.GetMethodDebugInfo(methodToken, methodVersion, localNames.FirstOrDefault());
inScopeHoistedLocalIndices = methodDebugInfo.GetInScopeHoistedLocalIndices(ilOffset, ref methodContextReuseConstraints);
var inScopeHoistedLocalIndices = methodDebugInfo.GetInScopeHoistedLocalIndices(ilOffset, ref methodContextReuseConstraints);
inScopeHoistedLocals = new CSharpInScopeHoistedLocals(inScopeHoistedLocalIndices);
}
catch (InvalidOperationException)
{
......@@ -186,7 +187,7 @@ internal sealed class EvaluationContext : EvaluationContextBase
metadataDecoder,
currentFrame,
locals,
inScopeHoistedLocalIndices,
inScopeHoistedLocals,
methodDebugInfo);
}
......@@ -197,7 +198,7 @@ internal CompilationContext CreateCompilationContext(CSharpSyntaxNode syntax)
_metadataDecoder,
_currentFrame,
_locals,
_inScopeHoistedLocalIndices,
_inScopeHoistedLocals,
_methodDebugInfo,
syntax);
}
......
......@@ -39,6 +39,7 @@
<Compile Include="FrameDecoder.cs" />
<Compile Include="InstructionDecoder.cs" />
<Compile Include="LanguageInstructionDecoder.cs" />
<Compile Include="PDB\InScopeHoistedLocals.cs" />
<Compile Include="PDB\HoisedLocalScopeRecord.cs" />
<Compile Include="PDB\ExternAliasRecord.cs" />
<Compile Include="PDB\MethodDebugInfo.cs" />
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
internal abstract class InScopeHoistedLocals
{
public static readonly InScopeHoistedLocals Empty = new EmptyInScopeHoistedLocals();
public abstract bool IsInScope(string fieldName);
private sealed class EmptyInScopeHoistedLocals : InScopeHoistedLocals
{
public override bool IsInScope(string fieldName)
{
return false;
}
}
}
}
......@@ -78,6 +78,7 @@
<Compile Include="Binders\SuppressObsoleteDiagnosticsBinder.vb" />
<Compile Include="CompilationContext.vb" />
<Compile Include="CompilationExtensions.vb" />
<Compile Include="VisualBasicInScopeHoistedLocalsByName.vb" />
<Compile Include="EETypeNameDecoder.vb" />
<Compile Include="SymUnmanagedReaderExtensions.vb" />
<Compile Include="InternalsVisibleTo.vb" />
......@@ -141,4 +142,4 @@
<Import Project="..\..\..\..\..\build\VSL.Imports.Closed.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
......@@ -46,7 +46,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
metadataDecoder As MetadataDecoder,
currentFrame As MethodSymbol,
locals As ImmutableArray(Of LocalSymbol),
hoistedLocalFieldNames As ImmutableHashSet(Of String),
inScopeHoistedLocals As InScopeHoistedLocals,
methodDebugInfo As MethodDebugInfo,
syntax As ExecutableStatementSyntax)
......@@ -93,7 +93,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
If _methodNotType Then
_locals = locals
Dim displayClassVariableNamesInOrder As ImmutableArray(Of String) = Nothing
GetDisplayClassVariables(currentFrame, locals, hoistedLocalFieldNames, displayClassVariableNamesInOrder, _displayClassVariables, _hoistedParameterNames)
GetDisplayClassVariables(currentFrame, locals, inScopeHoistedLocals, displayClassVariableNamesInOrder, _displayClassVariables, _hoistedParameterNames)
Debug.Assert(displayClassVariableNamesInOrder.Length = _displayClassVariables.Count)
_localsForBinding = GetLocalsForBinding(locals, displayClassVariableNamesInOrder, _displayClassVariables)
Else
......@@ -947,7 +947,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Private Shared Sub GetDisplayClassVariables(
method As MethodSymbol,
locals As ImmutableArray(Of LocalSymbol),
hoistedLocalFieldNames As ImmutableHashSet(Of String),
inScopeHoistedLocals As InScopeHoistedLocals,
<Out> ByRef displayClassVariableNamesInOrder As ImmutableArray(Of String),
<Out> ByRef displayClassVariables As ImmutableDictionary(Of String, DisplayClassVariable),
<Out> ByRef hoistedParameterNames As ImmutableHashSet(Of String))
......@@ -1017,7 +1017,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
displayClassVariableNamesInOrderBuilder,
displayClassVariablesBuilder,
parameterNames,
hoistedLocalFieldNames,
inScopeHoistedLocals,
instance,
pooledHoistedParameterNames)
Next
......@@ -1136,7 +1136,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
displayClassVariableNamesInOrder As ArrayBuilder(Of String),
displayClassVariablesBuilder As Dictionary(Of String, DisplayClassVariable),
parameterNames As HashSet(Of String),
hoistedLocalFieldNames As ImmutableHashSet(Of String),
inScopeHoistedLocals As InScopeHoistedLocals,
instance As DisplayClassInstanceAndFields,
hoistedParameterNames As HashSet(Of String))
......@@ -1165,7 +1165,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
variableKind = DisplayClassVariableKind.Local
variableName = Nothing
Dim unusedIndex As Integer = Nothing
If Not hoistedLocalFieldNames.Contains(fieldName) OrElse Not GeneratedNames.TryParseStateMachineHoistedUserVariableName(fieldName, variableName, unusedIndex) Then
If Not inScopeHoistedLocals.IsInScope(fieldName) OrElse Not GeneratedNames.TryParseStateMachineHoistedUserVariableName(fieldName, variableName, unusedIndex) Then
Continue For
End If
ElseIf IsHoistedMeFieldName(fieldName) Then
......
......@@ -35,7 +35,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Private ReadOnly _metadataDecoder As MetadataDecoder
Private ReadOnly _currentFrame As MethodSymbol
Private ReadOnly _locals As ImmutableArray(Of LocalSymbol)
Private ReadOnly _hoistedLocalFieldNames As ImmutableHashSet(Of String)
Private ReadOnly _inScopeHoistedLocals As InScopeHoistedLocals
Private ReadOnly _methodDebugInfo As MethodDebugInfo
Private Sub New(
......@@ -45,7 +45,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
metadataDecoder As MetadataDecoder,
currentFrame As MethodSymbol,
locals As ImmutableArray(Of LocalSymbol),
hoistedLocalFieldNames As ImmutableHashSet(Of String),
inScopeHoistedLocals As InScopeHoistedLocals,
methodDebugInfo As MethodDebugInfo)
Me.MetadataBlocks = metadataBlocks
......@@ -54,7 +54,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
_metadataDecoder = metadataDecoder
_currentFrame = currentFrame
_locals = locals
_hoistedLocalFieldNames = hoistedLocalFieldNames
_inScopeHoistedLocals = inScopeHoistedLocals
_methodDebugInfo = methodDebugInfo
End Sub
......@@ -94,7 +94,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
metadataDecoder,
currentFrame,
locals:=Nothing,
hoistedLocalFieldNames:=Nothing,
inScopeHoistedLocals:=Nothing,
methodDebugInfo:=Nothing)
End Function
......@@ -149,8 +149,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Dim currentFrame = compilation.GetMethod(moduleVersionId, methodHandle)
Debug.Assert(currentFrame IsNot Nothing)
Dim metadataDecoder = New MetadataDecoder(DirectCast(currentFrame.ContainingModule, PEModuleSymbol), currentFrame)
Dim hoistedLocalFieldNames As ImmutableHashSet(Of String) = Nothing
Dim localNames = GetLocalNames(containingScopes, hoistedLocalFieldNames)
Dim inScopeHoistedLocalNames As ImmutableHashSet(Of String) = Nothing
Dim localNames = GetLocalNames(containingScopes, inScopeHoistedLocalNames)
Dim localInfo = metadataDecoder.GetLocalInfo(localSignatureToken)
Dim localBuilder = ArrayBuilder(Of LocalSymbol).GetInstance()
GetLocals(localBuilder, currentFrame, localNames, localInfo)
......@@ -160,13 +160,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Dim locals = localBuilder.ToImmutableAndFree()
Dim methodDebugInfo As MethodDebugInfo
Dim inScopeHoistedLocals As InScopeHoistedLocals
If IsDteeEntryPoint(currentFrame) Then
methodDebugInfo = SynthesizeMethodDebugInfoForDtee(lazyAssemblyReaders.Value)
Debug.Assert(inScopeHoistedLocalNames.Count = 0)
inScopeHoistedLocals = InScopeHoistedLocals.Empty
ElseIf typedSymReader IsNot Nothing Then
' TODO (https://github.com/dotnet/roslyn/issues/702): Switch on the type of typedSymReader and call the appropriate helper.
methodDebugInfo = typedSymReader.GetMethodDebugInfo(methodToken, methodVersion)
InScopeHoistedLocals = New VisualBasicInScopeHoistedLocalsByName(inScopeHoistedLocalNames)
Else
methodDebugInfo = Nothing
InScopeHoistedLocals = InScopeHoistedLocals.Empty
End If
Return New EvaluationContext(
......@@ -176,24 +181,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
metadataDecoder,
currentFrame,
locals,
hoistedLocalFieldNames,
InScopeHoistedLocals,
methodDebugInfo)
End Function
Private Shared Function GetLocalNames(scopes As ArrayBuilder(Of ISymUnmanagedScope), <Out> ByRef hoistedLocalFieldNames As ImmutableHashSet(Of String)) As ImmutableArray(Of String)
Private Shared Function GetLocalNames(scopes As ArrayBuilder(Of ISymUnmanagedScope), <Out> ByRef inScopeHoistedLocalNames As ImmutableHashSet(Of String)) As ImmutableArray(Of String)
Dim localNames = ArrayBuilder(Of String).GetInstance()
Dim hoistedLocalFieldNamesBuilder As ImmutableHashSet(Of String).Builder = Nothing
Dim inScopeHoistedLocalsBuilder As ImmutableHashSet(Of String).Builder = Nothing
For Each localName In scopes.GetLocalNames()
If localName IsNot Nothing AndAlso localName.StartsWith(StringConstants.StateMachineHoistedUserVariablePrefix, StringComparison.Ordinal) Then
If hoistedLocalFieldNamesBuilder Is Nothing Then
hoistedLocalFieldNamesBuilder = ImmutableHashSet.CreateBuilder(Of String)()
If inScopeHoistedLocalsBuilder Is Nothing Then
inScopeHoistedLocalsBuilder = ImmutableHashSet.CreateBuilder(Of String)()
End If
hoistedLocalFieldNamesBuilder.Add(localName)
inScopeHoistedLocalsBuilder.Add(localName)
Else
localNames.Add(localName)
End If
Next
hoistedLocalFieldNames = If(hoistedLocalFieldNamesBuilder Is Nothing, ImmutableHashSet(Of String).Empty, hoistedLocalFieldNamesBuilder.ToImmutable())
inScopeHoistedLocalNames = If(inScopeHoistedLocalsBuilder Is Nothing, ImmutableHashSet(Of String).Empty, inScopeHoistedLocalsBuilder.ToImmutable())
Return localNames.ToImmutableAndFree()
End Function
......@@ -302,7 +307,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
_metadataDecoder,
_currentFrame,
_locals,
_hoistedLocalFieldNames,
_inScopeHoistedLocals,
_methodDebugInfo,
syntax)
End Function
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Collections.Immutable
Imports Microsoft.CodeAnalysis.ExpressionEvaluator
Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Friend NotInheritable Class VisualBasicInScopeHoistedLocalsByName
Inherits InScopeHoistedLocals
Private ReadOnly _fieldNames As ImmutableHashSet(Of String)
Public Sub New(fieldNames As ImmutableHashSet(Of String))
_fieldNames = fieldNames
End Sub
Public Overrides Function IsInScope(fieldName As String) As Boolean
Return _fieldNames.Contains(fieldName)
End Function
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册