提交 b54af4c2 编写于 作者: J John Hamby 提交者: GitHub

Merge pull request #12601 from JohnHamby/FileIndex

Add a fileIndex parameter to CreatePayload for dynamic analysis.
......@@ -522,6 +522,14 @@
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
</Node>
<!-- Represents the index in the documents table of the source document containing a method definition.
Used by dynamic instrumentation to identify the source document containing a method. -->
<Node Name="BoundSourceDocumentIndex" Base="BoundExpression">
<!-- Non-null type is required for this node kind -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
<Field Name="Document" Type="Cci.DebugSourceDocument"/>
</Node>
<Node Name="BoundMethodInfo" Base="BoundExpression">
<!-- Non-null type is required for this node kind -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
......
......@@ -1967,6 +1967,21 @@ public override void Accept(OperationVisitor visitor)
return visitor.VisitNoneOperation(this, argument);
}
}
internal partial class BoundSourceDocumentIndex
{
protected override OperationKind ExpressionKind => OperationKind.None;
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
}
public override TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument)
{
return visitor.VisitNoneOperation(this, argument);
}
}
internal partial class BoundMethodInfo
{
......
......@@ -235,6 +235,11 @@ private void EmitExpressionCore(BoundExpression expression, bool used)
EmitMaximumMethodDefIndexExpression((BoundMaximumMethodDefIndex)expression);
break;
case BoundKind.SourceDocumentIndex:
Debug.Assert(used);
EmitSourceDocumentIndex((BoundSourceDocumentIndex)expression);
break;
case BoundKind.MethodInfo:
if (used)
{
......@@ -2723,6 +2728,13 @@ private void EmitInstrumentationPayloadRootToken(BoundInstrumentationPayloadRoot
_builder.EmitToken(_module.GetInstrumentationPayloadRoot(node.AnalysisKind, _module.Translate(node.Type, node.Syntax, _diagnostics), node.Syntax, _diagnostics), node.Syntax, _diagnostics);
}
private void EmitSourceDocumentIndex(BoundSourceDocumentIndex node)
{
Debug.Assert(node.Type.SpecialType == SpecialType.System_Int32);
_builder.EmitOpCode(ILOpCode.Ldtoken);
_builder.EmitSourceDocumentIndexToken(node.Document);
}
private void EmitMethodInfoExpression(BoundMethodInfo node)
{
_builder.EmitOpCode(ILOpCode.Ldtoken);
......
......@@ -1388,6 +1388,11 @@ public override BoundNode VisitInstrumentationPayloadRoot(BoundInstrumentationPa
return null;
}
public override BoundNode VisitSourceDocumentIndex(BoundSourceDocumentIndex node)
{
return null;
}
public override BoundNode VisitConversion(BoundConversion node)
{
if (node.ConversionKind == ConversionKind.MethodGroup)
......
......@@ -81,13 +81,14 @@ public override BoundStatement CreateBlockPrologue(BoundBlock original, out Loca
//
// var payload = PID.PayloadRootField[methodIndex];
// if (payload == null)
// payload = Instrumentation.CreatePayload(mvid, methodIndex, ref PID.PayloadRootField[methodIndex], payloadLength);
// payload = Instrumentation.CreatePayload(mvid, methodIndex, fileIndex, ref PID.PayloadRootField[methodIndex], payloadLength);
BoundStatement payloadInitialization = _methodBodyFactory.Assignment(_methodBodyFactory.Local(_methodPayload), _methodBodyFactory.ArrayAccess(_methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType), ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method))));
BoundExpression mvid = _methodBodyFactory.ModuleVersionId();
BoundExpression methodToken = _methodBodyFactory.MethodDefIndex(_method);
BoundExpression fileIndex = _methodBodyFactory.SourceDocumentIndex(GetSourceDocument(_methodBody.Syntax));
BoundExpression payloadSlot = _methodBodyFactory.ArrayAccess(_methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType), ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method)));
BoundStatement createPayloadCall = _methodBodyFactory.Assignment(_methodBodyFactory.Local(_methodPayload), _methodBodyFactory.Call(null, _createPayload, mvid, methodToken, payloadSlot, _methodBodyFactory.Literal(_dynamicAnalysisSpans.Length)));
BoundStatement createPayloadCall = _methodBodyFactory.Assignment(_methodBodyFactory.Local(_methodPayload), _methodBodyFactory.Call(null, _createPayload, mvid, methodToken, fileIndex, payloadSlot, _methodBodyFactory.Literal(_dynamicAnalysisSpans.Length)));
BoundExpression payloadNullTest = _methodBodyFactory.Binary(BinaryOperatorKind.ObjectEqual, _methodBodyFactory.SpecialType(SpecialType.System_Boolean), _methodBodyFactory.Local(_methodPayload), _methodBodyFactory.Null(_payloadType));
BoundStatement payloadIf = _methodBodyFactory.If(payloadNullTest, createPayloadCall);
......@@ -236,21 +237,30 @@ private BoundStatement CollectDynamicAnalysis(BoundStatement original, BoundStat
return statementFactory.StatementList(AddAnalysisPoint(SyntaxForSpan(original), statementFactory), rewritten);
}
private BoundStatement AddAnalysisPoint(CSharpSyntaxNode syntaxForSpan, SyntheticBoundNodeFactory statementFactory)
private Cci.DebugSourceDocument GetSourceDocument(CSharpSyntaxNode syntax)
{
// Add an entry in the spans array.
return GetSourceDocument(syntax, syntax.GetLocation().GetMappedLineSpan());
}
Location location = syntaxForSpan.GetLocation();
FileLinePositionSpan spanPosition = location.GetMappedLineSpan();
string path = spanPosition.Path;
private Cci.DebugSourceDocument GetSourceDocument(CSharpSyntaxNode syntax, FileLinePositionSpan span)
{
string path = span.Path;
// If the path for the syntax node is empty, try the path for the entire syntax tree.
if (path.Length == 0)
{
path = syntaxForSpan.SyntaxTree.FilePath;
path = syntax.SyntaxTree.FilePath;
}
return _debugDocumentProvider.Invoke(path, basePath: "");
}
private BoundStatement AddAnalysisPoint(CSharpSyntaxNode syntaxForSpan, SyntheticBoundNodeFactory statementFactory)
{
// Add an entry in the spans array.
FileLinePositionSpan spanPosition = syntaxForSpan.GetLocation().GetMappedLineSpan();
int spansIndex = _spansBuilder.Count;
_spansBuilder.Add(new SourceSpan(_debugDocumentProvider.Invoke(path, ""), spanPosition.StartLinePosition.Line, spanPosition.StartLinePosition.Character, spanPosition.EndLinePosition.Line, spanPosition.EndLinePosition.Character));
_spansBuilder.Add(new SourceSpan(GetSourceDocument(syntaxForSpan, spanPosition), spanPosition.StartLinePosition.Line, spanPosition.StartLinePosition.Character, spanPosition.EndLinePosition.Line, spanPosition.EndLinePosition.Character));
// Generate "_payload[pointIndex] = true".
......
......@@ -1014,6 +1014,18 @@ public BoundExpression MaximumMethodDefIndex()
{ WasCompilerGenerated = true };
}
/// <summary>
/// Synthesizes an expression that evaluates to the index of a source document in the table of debug source documents.
/// </summary>
public BoundExpression SourceDocumentIndex(Cci.DebugSourceDocument document)
{
return new BoundSourceDocumentIndex(
Syntax,
document,
SpecialType(Microsoft.CodeAnalysis.SpecialType.System_Int32))
{ WasCompilerGenerated = true };
}
public BoundExpression MethodInfo(MethodSymbol method)
{
// The least overridden virtual method is only called for value type receivers
......
......@@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.Runtime
{
public static class Instrumentation
{
public static bool[] CreatePayload(System.Guid mvid, int methodToken, ref bool[] payload, int payloadLength)
public static bool[] CreatePayload(System.Guid mvid, int methodToken, int fileIndex, ref bool[] payload, int payloadLength)
{
return payload;
}
......@@ -66,7 +66,7 @@ public void TestSpansPresentInResource()
var reader = DynamicAnalysisDataReader.TryCreateFromPE(peReader, "<DynamicAnalysisData>");
VerifyDocuments(reader, reader.Documents,
@"'C:\myproject\doc1.cs' 87-3F-1A-28-F7-34-C9-43-19-00-ED-0F-8F-2F-0D-EB-DD-32-D4-8E (SHA1)");
@"'C:\myproject\doc1.cs' B2-C1-91-21-17-72-39-D7-D8-C8-AC-3C-09-F6-3C-FF-B7-E5-97-8E (SHA1)");
Assert.Equal(10, reader.Methods.Length);
......@@ -200,7 +200,7 @@ public static void Main()
var reader = DynamicAnalysisDataReader.TryCreateFromPE(peReader, "<DynamicAnalysisData>");
VerifyDocuments(reader, reader.Documents,
@"'C:\myproject\doc1.cs' EE-A5-42-12-BD-ED-90-96-8D-12-54-DE-D0-F0-4F-EC-79-C6-2A-89 (SHA1)");
@"'C:\myproject\doc1.cs' 89-73-A7-64-40-88-BA-0A-21-33-05-5D-E7-22-9B-74-1C-6A-2C-DC (SHA1)");
Assert.Equal(5, reader.Methods.Length);
......
......@@ -50,6 +50,7 @@
</Content>
</ItemGroup>
<ItemGroup>
<Compile Include="CodeGen\ItemTokenMap.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="InternalUtilities\IncrementalHash.cs" />
<Compile Include="PEWriter\ExportedType.cs" />
......@@ -145,7 +146,6 @@
<Compile Include="CodeGen\ReferenceDependencyWalker.cs" />
<Compile Include="CodeGen\ScopeType.cs" />
<Compile Include="CodeGen\SequencePointList.cs" />
<Compile Include="CodeGen\StringTokenMap.cs" />
<Compile Include="CodeGen\SwitchIntegralJumpTableEmitter.cs" />
<Compile Include="CodeGen\SwitchIntegralJumpTableEmitter.SwitchBucket.cs" />
<Compile Include="CodeGen\SwitchStringJumpTableEmitter.cs" />
......
......@@ -66,6 +66,11 @@ internal void EmitModuleVersionIdStringToken()
this.GetCurrentWriter().WriteUInt32(Cci.MetadataWriter.ModuleVersionIdStringToken);
}
internal void EmitSourceDocumentIndexToken(Cci.DebugSourceDocument document)
{
this.GetCurrentWriter().WriteUInt32((module?.GetSourceDocumentIndexForIL(document) ?? 0xFFFF) | Cci.MetadataWriter.SourceDocumentIndex);
}
internal void EmitArrayBlockInitializer(ImmutableArray<byte> data, SyntaxNode syntaxNode, DiagnosticBag diagnostics)
{
// get helpers
......
......@@ -8,6 +8,7 @@ internal interface ITokenDeferral
{
uint GetFakeStringTokenForIL(string value);
uint GetFakeSymbolTokenForIL(Cci.IReference value, SyntaxNode syntaxNode, DiagnosticBag diagnostics);
uint GetSourceDocumentIndexForIL(Cci.DebugSourceDocument document);
Cci.IFieldReference GetFieldForData(ImmutableArray<byte> data, SyntaxNode syntaxNode, DiagnosticBag diagnostics);
Cci.IMethodReference GetInitArrayHelper();
......
// 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;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CodeGen
{
/// <summary>
/// Handles storage of strings referenced via tokens in metadata. When items are stored
/// they are uniquely "associated" with fake token, which is basically a sequential number.
/// IL gen will use these fake tokens during codegen and later, when actual token values
/// are known the method bodies will be patched.
/// To support these two scenarios we need two maps - Item-->uint, and uint-->Item. (the second is really just a list).
/// Handles storage of items referenced via tokens in metadata. When items are stored
/// they are uniquely "associated" with fake tokens, which are basically sequential numbers.
/// IL gen will use these fake tokens during codegen and later, when actual values
/// are known, the method bodies will be patched.
/// To support these two scenarios we need two maps - Item-->uint, and uint-->Item. (The second is really just a list).
/// </summary>
internal sealed class StringTokenMap
internal sealed class ItemTokenMap<T> where T: class
{
private readonly ConcurrentDictionary<string, uint> _itemToToken = new ConcurrentDictionary<string, uint>(ReferenceEqualityComparer.Instance);
private readonly ArrayBuilder<string> _items = new ArrayBuilder<string>();
private readonly ConcurrentDictionary<T, uint> _itemToToken = new ConcurrentDictionary<T, uint>(ReferenceEqualityComparer.Instance);
private readonly ArrayBuilder<T> _items = new ArrayBuilder<T>();
public uint GetOrAddTokenFor(string item)
public uint GetOrAddTokenFor(T item)
{
uint token;
// NOTE: cannot use GetOrAdd here since items and itemToToken must be in sync
......@@ -34,7 +31,7 @@ public uint GetOrAddTokenFor(string item)
return AddItem(item);
}
private uint AddItem(string item)
private uint AddItem(T item)
{
uint token;
......@@ -53,7 +50,7 @@ private uint AddItem(string item)
return token;
}
public string GetItem(uint token)
public T GetItem(uint token)
{
lock (_items)
{
......@@ -61,23 +58,12 @@ public string GetItem(uint token)
}
}
public IEnumerable<string> GetAllItems()
public IEnumerable<T> GetAllItems()
{
lock (_items)
{
return _items.ToArray();
}
}
//TODO: why is this is called twice during emit?
// should probably return ROA instead of IE and cache that in Module. (and no need to return count)
public IEnumerable<string> GetAllItemsAndCount(out int count)
{
lock (_items)
{
count = _items.Count;
return _items.ToArray();
}
}
}
}
......@@ -27,6 +27,7 @@ internal abstract class CommonPEModuleBuilder
internal abstract ImmutableDictionary<Cci.ITypeDefinition, ImmutableArray<Cci.ITypeDefinitionMember>> GetSynthesizedMembers();
internal abstract CommonEmbeddedTypesManager CommonEmbeddedTypesManagerOpt { get; }
internal abstract Cci.ITypeReference EncTranslateType(ITypeSymbol type, DiagnosticBag diagnostics);
internal abstract Cci.DebugSourceDocument GetSourceDocumentFromIndex(uint index);
}
/// <summary>
......@@ -53,7 +54,8 @@ internal abstract class PEModuleBuilder<TCompilation, TSourceModuleSymbol, TAsse
private readonly ConcurrentCache<ValueTuple<string, string>, string> _normalizedPathsCache = new ConcurrentCache<ValueTuple<string, string>, string>(16);
private readonly TokenMap<Cci.IReference> _referencesInILMap = new TokenMap<Cci.IReference>();
private readonly StringTokenMap _stringsInILMap = new StringTokenMap();
private readonly ItemTokenMap<string> _stringsInILMap = new ItemTokenMap<string>();
private readonly ItemTokenMap<Cci.DebugSourceDocument> _sourceDocumentsInILMap = new ItemTokenMap<Cci.DebugSourceDocument>();
private readonly ConcurrentDictionary<TMethodSymbol, Cci.IMethodBody> _methodBodyMap =
new ConcurrentDictionary<TMethodSymbol, Cci.IMethodBody>(ReferenceEqualityComparer.Instance);
......@@ -599,6 +601,16 @@ public uint GetFakeSymbolTokenForIL(Cci.IReference symbol, SyntaxNode syntaxNode
return token;
}
public uint GetSourceDocumentIndexForIL(Cci.DebugSourceDocument document)
{
return _sourceDocumentsInILMap.GetOrAddTokenFor(document);
}
internal override Cci.DebugSourceDocument GetSourceDocumentFromIndex(uint token)
{
return _sourceDocumentsInILMap.GetItem(token);
}
public Cci.IReference GetReferenceFromToken(uint token)
{
return _referencesInILMap.GetItem(token);
......
......@@ -117,7 +117,7 @@ private GuidHandle GetOrAddGuid(Guid guid)
_guidWriter.WriteBytes(guid.ToByteArray());
return result;
}
#endregion
#region Spans
......@@ -198,6 +198,11 @@ private void SerializeDeltaLinesAndColumns(BlobBuilder writer, SourceSpan span)
#region Documents
internal int GetOrAddDocument(DebugSourceDocument document)
{
return GetOrAddDocument(document, _documentIndex);
}
private int GetOrAddDocument(DebugSourceDocument document, Dictionary<DebugSourceDocument, int> index)
{
int documentRowId;
......
......@@ -3026,6 +3026,7 @@ private UserStringHandle ReserveUserString(int length, out Blob fixup)
internal const uint LiteralMethodDefinitionToken = 0x80000000;
internal const uint LiteralGreatestMethodDefinitionToken = 0x40000000;
internal const uint SourceDocumentIndex = 0x20000000;
internal const uint ModuleVersionIdStringToken = 0x80000000;
private void SubstituteFakeTokens(Blob blob, ImmutableArray<byte> methodBodyIL, ref UserStringHandle mvidStringHandle, ref Blob mvidStringFixup)
......@@ -3065,6 +3066,9 @@ private void SubstituteFakeTokens(Blob blob, ImmutableArray<byte> methodBodyIL,
case LiteralGreatestMethodDefinitionToken:
token = GreatestMethodDefIndex;
break;
case SourceDocumentIndex:
token = _dynamicAnalysisDataWriterOpt.GetOrAddDocument(((CommonPEModuleBuilder)module).GetSourceDocumentFromIndex((uint)(pseudoToken & 0x00ffffff)));
break;
default:
throw ExceptionUtilities.UnexpectedValue(tokenMask);
}
......
......@@ -2879,10 +2879,11 @@ static WellKnownMembers()
(byte)(MemberFlags.Method | MemberFlags.Static), // Flags
(byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.Microsoft_CodeAnalysis_Runtime_Instrumentation - WellKnownType.ExtSentinel), // DeclaringTypeId
0, // Arity
4, // Method Signature
5, // Method Signature
(byte)SignatureTypeCode.SZArray, (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Boolean,
(byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.System_Guid,
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32,
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32,
(byte)SignatureTypeCode.ByReference, (byte)SignatureTypeCode.SZArray, (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Boolean,
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32,
};
......
......@@ -2633,6 +2633,9 @@ EnteredRegion:
Return Nothing
End Function
Public Overrides Function VisitSourceDocumentIndex(node As BoundSourceDocumentIndex) As BoundNode
Return Nothing
End Function
#End Region
End Class
......
......@@ -285,6 +285,14 @@
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
</Node>
<!-- Represents the index in the documents table of the source document containing a method definition.
Used by dynamic instrumentation to identify the source document containing a method. -->
<Node Name="BoundSourceDocumentIndex" Base="BoundExpression">
<!-- Non-null type is required for this node kind -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
<Field Name="Document" Type="Cci.DebugSourceDocument"/>
</Node>
<Node Name="BoundUnaryOperator" Base="BoundExpression" HasValidate="true">
<!-- Type is required for this node type; may not be null -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
......
......@@ -2920,6 +2920,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Function
End Class
Partial Friend Class BoundSourceDocumentIndex
Protected Overrides Function ExpressionKind() As OperationKind
Return OperationKind.None
End Function
Public Overrides Sub Accept(visitor As OperationVisitor)
visitor.VisitNoneOperation(Me)
End Sub
Public Overrides Function Accept(Of TArgument, TResult)(visitor As OperationVisitor(Of TArgument, TResult), argument As TArgument) As TResult
Return visitor.VisitNoneOperation(Me, argument)
End Function
End Class
Friend Module Expression
Friend Function DeriveUnaryOperationKind(operatorKind As UnaryOperatorKind, operand As BoundExpression) As UnaryOperationKind
Select Case operand.Type.SpecialType
......
......@@ -194,6 +194,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
Debug.Assert(used)
EmitMaximumMethodDefIndexExpression(DirectCast(expression, BoundMaximumMethodDefIndex))
Case BoundKind.SourceDocumentIndex
Debug.Assert(used)
EmitSourceDocumentIndex(DirectCast(expression, BoundSourceDocumentIndex))
Case Else
' Code gen should not be invoked if there are errors.
' Debug.Assert(expression.Kind <> BoundKind.BadExpression AndAlso expression.Kind <> BoundKind.Parenthesized)
......@@ -2232,6 +2236,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
Private Sub EmitInstrumentationPayloadRootToken(node As BoundInstrumentationPayloadRoot)
_builder.EmitToken(_module.GetInstrumentationPayloadRoot(node.AnalysisKind, _module.Translate(node.Type, node.Syntax, _diagnostics), node.Syntax, _diagnostics), node.Syntax, _diagnostics)
End Sub
Private Sub EmitSourceDocumentIndex(node As BoundSourceDocumentIndex)
Debug.Assert(node.Type.SpecialType = SpecialType.System_Int32)
_builder.EmitOpCode(ILOpCode.Ldtoken)
_builder.EmitSourceDocumentIndexToken(node.Document)
End Sub
End Class
End Namespace
......@@ -86,14 +86,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
'
' Dim payload = PID.PayloadRootField(methodIndex)
' If payload Is Nothing Then
' payload = Instrumentation.CreatePayload(mvid, methodIndex, PID.PayloadRootField(methodIndex), payloadLength)
' payload = Instrumentation.CreatePayload(mvid, methodIndex, fileIndex, PID.PayloadRootField(methodIndex), payloadLength)
' End If
Dim payloadInitialization As BoundStatement = _methodBodyFactory.Assignment(_methodBodyFactory.Local(_methodPayload, isLValue:=True), _methodBodyFactory.ArrayAccess(_methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType, isLValue:=False), isLValue:=False, indices:=ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method))))
Dim mvid As BoundExpression = _methodBodyFactory.ModuleVersionId(isLValue:=False)
Dim methodToken As BoundExpression = _methodBodyFactory.MethodDefIndex(_method)
Dim fileIndex As BoundExpression = _methodBodyFactory.SourceDocumentIndex(GetSourceDocument(_methodBody.Syntax))
Dim payloadSlot As BoundExpression = _methodBodyFactory.ArrayAccess(_methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType, isLValue:=False), isLValue:=False, indices:=ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method)))
Dim createPayloadCall As BoundStatement = _methodBodyFactory.Assignment(_methodBodyFactory.Local(_methodPayload, isLValue:=True), _methodBodyFactory.Call(Nothing, _createPayload, mvid, methodToken, payloadSlot, _methodBodyFactory.Literal(_dynamicAnalysisSpans.Length)))
Dim createPayloadCall As BoundStatement = _methodBodyFactory.Assignment(_methodBodyFactory.Local(_methodPayload, isLValue:=True), _methodBodyFactory.Call(Nothing, _createPayload, mvid, methodToken, fileIndex, payloadSlot, _methodBodyFactory.Literal(_dynamicAnalysisSpans.Length)))
Dim payloadNullTest As BoundExpression = _methodBodyFactory.Binary(BinaryOperatorKind.Equals, _methodBodyFactory.SpecialType(SpecialType.System_Boolean), _methodBodyFactory.Local(_methodPayload, False), _methodBodyFactory.Null(_payloadType))
Dim payloadIf As BoundStatement = _methodBodyFactory.If(payloadNullTest, createPayloadCall)
......@@ -234,19 +235,28 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return If(rewritten IsNot Nothing, statementFactory.StatementList(analysisPoint, rewritten), analysisPoint)
End Function
Private Function GetSourceDocument(syntax As VisualBasicSyntaxNode) As Cci.DebugSourceDocument
Return GetSourceDocument(syntax, syntax.GetLocation().GetMappedLineSpan())
End Function
Private Function GetSourceDocument(syntax As VisualBasicSyntaxNode, span As FileLinePositionSpan) As Cci.DebugSourceDocument
Dim path As String = span.Path
' If the path for the syntax node is empty, try the path for the entire syntax tree.
If path.Length = 0 Then
path = syntax.SyntaxTree.FilePath
End If
Return _debugDocumentProvider.Invoke(path, basePath:="")
End Function
Private Function AddAnalysisPoint(syntaxForSpan As VisualBasicSyntaxNode, statementFactory As SyntheticBoundNodeFactory) As BoundStatement
' Add an entry in the spans array.
Dim location As Location = syntaxForSpan.GetLocation()
Dim spanPosition As FileLinePositionSpan = location.GetMappedLineSpan()
Dim path As String = spanPosition.Path
' If the path for the syntax node is empty, try the path for the entire syntax tree.
If path.Length = 0 Then
path = syntaxForSpan.SyntaxTree.FilePath
End If
Dim spansIndex As Integer = _spansBuilder.Count
_spansBuilder.Add(New SourceSpan(_debugDocumentProvider.Invoke(path, basePath:=""), spanPosition.StartLinePosition.Line, spanPosition.StartLinePosition.Character, spanPosition.EndLinePosition.Line, spanPosition.EndLinePosition.Character))
_spansBuilder.Add(New SourceSpan(GetSourceDocument(syntaxForSpan, spanPosition), spanPosition.StartLinePosition.Line, spanPosition.StartLinePosition.Character, spanPosition.EndLinePosition.Line, spanPosition.EndLinePosition.Character))
' Generate "_payload(pointIndex) = True".
......
......@@ -969,6 +969,15 @@ nextm:
Return boundNode
End Function
''' <summary>
''' Synthesizes an expression that evaluates to the index of a source document in the table of debug source documents.
''' </summary>
Public Function SourceDocumentIndex(document As Cci.DebugSourceDocument) As BoundExpression
Dim boundNode As New BoundSourceDocumentIndex(Syntax, document, SpecialType(Microsoft.CodeAnalysis.SpecialType.System_Int32))
boundNode.SetWasCompilerGenerated()
Return boundNode
End Function
Public Function Convert(type As TypeSymbol, arg As BoundExpression, Optional isChecked As Boolean = False) As BoundConversion
If arg.IsNothingLiteral() Then
Return Convert(type, arg, ConversionKind.WideningNothingLiteral, isChecked)
......
......@@ -20,7 +20,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.DynamicAnalysis.UnitTests
<![CDATA[
Namespace Microsoft.CodeAnalysis.Runtime
Public Class Instrumentation
Public Shared Function CreatePayload(mvid As System.Guid, methodToken As Integer, ByRef payload As Boolean(), payloadLength As Integer) As Boolean()
Public Shared Function CreatePayload(mvid As System.Guid, methodToken As Integer, fileIndex As Integer, ByRef payload As Boolean(), payloadLength As Integer) As Boolean()
Return payload
End Function
......
......@@ -24,16 +24,19 @@ Namespace Microsoft.CodeAnalysis.Runtime
Public Class Instrumentation
Private Shared _payloads As Boolean()()
Private Shared _fileIndices As Integer()
Private Shared _mvid As System.Guid
Public Shared Function CreatePayload(mvid As System.Guid, methodIndex As Integer, ByRef payload As Boolean(), payloadLength As Integer) As Boolean()
Public Shared Function CreatePayload(mvid As System.Guid, methodIndex As Integer, fileIndex As Integer, ByRef payload As Boolean(), payloadLength As Integer) As Boolean()
If _mvid <> mvid Then
_payloads = New Boolean(100)() {}
_fileIndices = New Integer(100) {}
_mvid = mvid
End If
If System.Threading.Interlocked.CompareExchange(payload, new Boolean(payloadLength - 1) {}, Nothing) Is Nothing Then
_payloads(methodIndex) = payload
_fileIndices(methodIndex) = fileIndex
Return payload
End If
......@@ -48,7 +51,8 @@ Namespace Microsoft.CodeAnalysis.Runtime
For i As Integer = 0 To _payloads.Length - 1
Dim payload As Boolean() = _payloads(i)
if payload IsNot Nothing
System.Console.WriteLine(i)
System.Console.WriteLine("Method " & i.ToString())
System.Console.WriteLine("File " & _fileIndices(i).ToString())
For j As Integer = 0 To payload.Length - 1
System.Console.WriteLine(payload(j))
payload(j) = False
......@@ -83,13 +87,16 @@ End Module
Dim expectedOutput As XCData = <![CDATA[
Flushing
1
Method 1
File 1
True
True
True
2
Method 2
File 1
True
5
Method 5
File 1
True
True
False
......@@ -101,6 +108,7 @@ True
True
True
True
True
]]>
Dim verifier As CompilationVerifier = CompileAndVerify(source, expectedOutput)
......@@ -109,28 +117,29 @@ True
"Program.TestMain",
<![CDATA[
{
// Code size 52 (0x34)
.maxstack 4
// Code size 57 (0x39)
.maxstack 5
.locals init (Boolean() V_0)
IL_0000: ldsfld "Boolean()() <PrivateImplementationDetails>.PayloadRoot0"
IL_0005: ldtoken "Sub Program.TestMain()"
IL_000a: ldelem.ref
IL_000b: stloc.0
IL_000c: ldloc.0
IL_000d: brtrue.s IL_002f
IL_000d: brtrue.s IL_0034
IL_000f: ldsfld "System.Guid <PrivateImplementationDetails>.MVID"
IL_0014: ldtoken "Sub Program.TestMain()"
IL_0019: ldsfld "Boolean()() <PrivateImplementationDetails>.PayloadRoot0"
IL_001e: ldtoken "Sub Program.TestMain()"
IL_0023: ldelema "Boolean()"
IL_0028: ldc.i4.1
IL_0029: call "Function Microsoft.CodeAnalysis.Runtime.Instrumentation.CreatePayload(System.Guid, Integer, ByRef Boolean(), Integer) As Boolean()"
IL_002e: stloc.0
IL_002f: ldloc.0
IL_0030: ldc.i4.0
IL_0031: ldc.i4.1
IL_0032: stelem.i1
IL_0033: ret
IL_0019: ldtoken Source Document 0
IL_001e: ldsfld "Boolean()() <PrivateImplementationDetails>.PayloadRoot0"
IL_0023: ldtoken "Sub Program.TestMain()"
IL_0028: ldelema "Boolean()"
IL_002d: ldc.i4.1
IL_002e: call "Function Microsoft.CodeAnalysis.Runtime.Instrumentation.CreatePayload(System.Guid, Integer, Integer, ByRef Boolean(), Integer) As Boolean()"
IL_0033: stloc.0
IL_0034: ldloc.0
IL_0035: ldc.i4.0
IL_0036: ldc.i4.1
IL_0037: stelem.i1
IL_0038: ret
}
]]>.Value)
......@@ -158,13 +167,16 @@ End Module
Dim expectedOutput As XCData = <![CDATA[
Flushing
8
Method 8
File 1
True
True
True
9
Method 9
File 1
True
12
Method 12
File 1
True
True
False
......@@ -176,6 +188,7 @@ True
True
True
True
True
]]>
' Explicitly define the "_MyType" pre-processor definition so that the "My" template code is added to
......@@ -187,6 +200,87 @@ True
CompileAndVerify(source, expectedOutput, TestOptions.ReleaseExe.WithParseOptions(parseOptions))
End Sub
<Fact>
Public Sub MultipleFilesCoverage()
Dim testSource As XElement = <file name="c.vb">
<![CDATA[
Module Program
Public Sub Main(args As String()) ' Method 1
TestMain()
Microsoft.CodeAnalysis.Runtime.Instrumentation.FlushPayload()
End Sub
Sub TestMain() ' Method 2
Called()
End Sub
End Module
]]>
</file>
Dim testSource1 As XElement = <file name="d.vb">
<![CDATA[
Module More
Sub Called() ' Method 3
Another()
Another()
End Sub
End Module
]]>
</file>
Dim testSource2 As XElement = <file name="e.vb">
<![CDATA[
Module EvenMore
Sub Another() ' Method 4
End Sub
End Module
]]>
</file>
Dim source As XElement = <compilation></compilation>
source.Add(testSource)
source.Add(testSource1)
source.Add(testSource2)
source.Add(InstrumentationHelperSource)
Dim expectedOutput As XCData = <![CDATA[
Flushing
Method 1
File 1
True
True
True
Method 2
File 1
True
True
Method 3
File 2
True
True
True
Method 4
File 3
True
Method 7
File 1
True
True
False
True
True
True
True
True
True
True
True
True
]]>
CompileAndVerify(source, expectedOutput)
End Sub
<Fact>
Public Sub MethodsOfGenericTypesCoverage()
Dim testSource As XElement = <file name="c.vb">
......@@ -230,25 +324,30 @@ End Module
Dim expectedOutput As XCData = <![CDATA[null
Hello
Flushing
1
Method 1
File 1
True
True
2
Method 2
File 1
True
True
True
True
3
Method 3
File 1
True
True
True
4
Method 4
File 1
True
True
True
True
True
7
Method 7
File 1
True
True
False
......@@ -260,6 +359,7 @@ True
True
True
True
True
]]>
Dim verifier As CompilationVerifier = CompileAndVerify(source, expectedOutput)
......@@ -268,8 +368,8 @@ True
"MyBox(Of T).GetValue",
<![CDATA[
{
// Code size 95 (0x5f)
.maxstack 4
// Code size 100 (0x64)
.maxstack 5
.locals init (T V_0, //GetValue
Boolean() V_1)
IL_0000: ldsfld "Boolean()() <PrivateImplementationDetails>.PayloadRoot0"
......@@ -277,43 +377,44 @@ True
IL_000a: ldelem.ref
IL_000b: stloc.1
IL_000c: ldloc.1
IL_000d: brtrue.s IL_002f
IL_000d: brtrue.s IL_0034
IL_000f: ldsfld "System.Guid <PrivateImplementationDetails>.MVID"
IL_0014: ldtoken "Function MyBox(Of T).GetValue() As T"
IL_0019: ldsfld "Boolean()() <PrivateImplementationDetails>.PayloadRoot0"
IL_001e: ldtoken "Function MyBox(Of T).GetValue() As T"
IL_0023: ldelema "Boolean()"
IL_0028: ldc.i4.4
IL_0029: call "Function Microsoft.CodeAnalysis.Runtime.Instrumentation.CreatePayload(System.Guid, Integer, ByRef Boolean(), Integer) As Boolean()"
IL_002e: stloc.1
IL_002f: ldloc.1
IL_0030: ldc.i4.0
IL_0031: ldc.i4.1
IL_0032: stelem.i1
IL_0033: ldloc.1
IL_0034: ldc.i4.2
IL_0035: ldc.i4.1
IL_0036: stelem.i1
IL_0037: ldarg.0
IL_0038: ldfld "MyBox(Of T)._value As T"
IL_003d: box "T"
IL_0042: brtrue.s IL_0052
IL_0044: ldloc.1
IL_0045: ldc.i4.1
IL_0046: ldc.i4.1
IL_0047: stelem.i1
IL_0048: ldloca.s V_0
IL_004a: initobj "T"
IL_0050: br.s IL_005d
IL_0052: ldloc.1
IL_0053: ldc.i4.3
IL_0054: ldc.i4.1
IL_0055: stelem.i1
IL_0056: ldarg.0
IL_0057: ldfld "MyBox(Of T)._value As T"
IL_005c: stloc.0
IL_005d: ldloc.0
IL_005e: ret
IL_0019: ldtoken Source Document 0
IL_001e: ldsfld "Boolean()() <PrivateImplementationDetails>.PayloadRoot0"
IL_0023: ldtoken "Function MyBox(Of T).GetValue() As T"
IL_0028: ldelema "Boolean()"
IL_002d: ldc.i4.4
IL_002e: call "Function Microsoft.CodeAnalysis.Runtime.Instrumentation.CreatePayload(System.Guid, Integer, Integer, ByRef Boolean(), Integer) As Boolean()"
IL_0033: stloc.1
IL_0034: ldloc.1
IL_0035: ldc.i4.0
IL_0036: ldc.i4.1
IL_0037: stelem.i1
IL_0038: ldloc.1
IL_0039: ldc.i4.2
IL_003a: ldc.i4.1
IL_003b: stelem.i1
IL_003c: ldarg.0
IL_003d: ldfld "MyBox(Of T)._value As T"
IL_0042: box "T"
IL_0047: brtrue.s IL_0057
IL_0049: ldloc.1
IL_004a: ldc.i4.1
IL_004b: ldc.i4.1
IL_004c: stelem.i1
IL_004d: ldloca.s V_0
IL_004f: initobj "T"
IL_0055: br.s IL_0062
IL_0057: ldloc.1
IL_0058: ldc.i4.3
IL_0059: ldc.i4.1
IL_005a: stelem.i1
IL_005b: ldarg.0
IL_005c: ldfld "MyBox(Of T)._value As T"
IL_0061: stloc.0
IL_0062: ldloc.0
IL_0063: ret
}
]]>.Value)
End Sub
......@@ -355,11 +456,13 @@ End Module
Dim expectedOutput As XCData = <![CDATA[OK
Flushing
1
Method 1
File 1
True
True
True
2
Method 2
File 1
True
True
True
......@@ -370,7 +473,8 @@ True
True
False
True
5
Method 5
File 1
True
True
False
......@@ -382,7 +486,7 @@ True
True
True
True
True
]]>
CompileAndVerify(source, expectedOutput)
......@@ -440,32 +544,38 @@ End Module
Dim expectedOutput As XCData = <![CDATA[GooGooGlueGooGoo
Flushing
1
Method 1
File 1
True
True
True
2
Method 2
File 1
True
True
3
Method 3
File 1
True
True
True
True
4
Method 4
File 1
True
True
True
False
True
5
Method 5
File 1
True
True
True
False
True
True
8
Method 8
File 1
True
True
False
......@@ -477,6 +587,7 @@ True
True
True
True
True
]]>
CompileAndVerify(source, expectedOutput)
......@@ -563,7 +674,8 @@ End Module
Dim expectedOutput As XCData = <![CDATA[
Flushing
1
Method 1
File 1
True
True
True
......@@ -579,7 +691,8 @@ True
False
True
True
2
Method 2
File 1
True
True
True
......@@ -595,7 +708,8 @@ True
True
True
True
3
Method 3
File 1
True
True
True
......@@ -606,14 +720,16 @@ True
True
True
True
4
Method 4
File 1
True
True
True
True
True
True
7
Method 7
File 1
True
True
False
......@@ -625,6 +741,7 @@ True
True
True
True
True
]]>
CompileAndVerify(source, expectedOutput)
......@@ -672,7 +789,8 @@ End Module
Dim expectedOutput As XCData = <![CDATA[
Flushing
1
Method 1
File 1
True
True
True
......@@ -683,11 +801,13 @@ False
False
True
True
2
Method 2
File 1
True
True
True
5
Method 5
File 1
True
True
False
......@@ -699,6 +819,7 @@ True
True
True
True
True
]]>
CompileAndVerify(source, expectedOutput)
......@@ -749,7 +870,8 @@ End Module
Dim expectedOutput As XCData = <![CDATA[
Flushing
1
Method 1
File 1
True
True
True
......@@ -765,11 +887,13 @@ False
True
True
False
2
Method 2
File 1
True
True
True
5
Method 5
File 1
True
True
False
......@@ -781,6 +905,7 @@ True
True
True
True
True
]]>
CompileAndVerify(source, expectedOutput)
......@@ -816,7 +941,8 @@ End Module
Dim expectedOutput As XCData = <![CDATA[
Flushing
1
Method 1
File 1
True
True
True
......@@ -825,11 +951,13 @@ True
False
True
True
2
Method 2
File 1
True
True
True
5
Method 5
File 1
True
True
False
......@@ -841,6 +969,7 @@ True
True
True
True
True
]]>
CompileAndVerify(source, expectedOutput)
......@@ -893,15 +1022,18 @@ End Module
Dim expectedOutput As XCData = <![CDATA[
Flushing
1
Method 1
File 1
True
True
True
2
Method 2
File 1
True
True
True
5
Method 5
File 1
True
True
False
......@@ -913,19 +1045,24 @@ True
True
True
True
9
True
Method 9
File 1
True
True
14
Method 14
File 1
True
15
Method 15
File 1
True
True
True
True
True
True
16
Method 16
File 1
True
True
]]>
......@@ -966,7 +1103,8 @@ End Module
Dim expectedOutput As XCData = <![CDATA[
Flushing
1
Method 1
File 1
True
True
True
......@@ -978,11 +1116,13 @@ False
True
True
True
2
Method 2
File 1
True
True
True
5
Method 5
File 1
True
True
False
......@@ -994,6 +1134,7 @@ True
True
True
True
True
]]>
CompileAndVerify(source, expectedOutput)
......@@ -1044,23 +1185,28 @@ End Module
Dim expectedOutput As XCData = <![CDATA[
Flushing
1
Method 1
File 1
True
True
True
True
2
Method 2
File 1
True
True
True
3
Method 3
File 1
True
8
Method 8
File 1
True
True
True
False
11
Method 11
File 1
True
True
False
......@@ -1072,6 +1218,7 @@ True
True
True
True
True
]]>
CompileAndVerify(source, expectedOutput)
......
......@@ -384,13 +384,20 @@ public void VisualizeHeader(StringBuilder sb, int codeSize, int maxStack, Immuta
uint pseudoToken = ReadUInt32(ilBytes, ref curIndex);
if (opCode.OperandType == OperandType.InlineTok)
{
// Check of an encoding of the maximum method token index value.
// Check for an encoding of the maximum method token index value.
if ((pseudoToken & 0xff000000) == 0x40000000)
{
sb.Append("Max Method Token Index");
break;
}
// Check for an encoding of a source document index.
if ((pseudoToken & 0xff000000) == 0x20000000)
{
sb.Append("Source Document " + (pseudoToken & 0x00ffffff).ToString());
break;
}
// Check for a raw token value, encoded with a 1 high-order bit.
if ((pseudoToken & 0x80000000) != 0 && pseudoToken != 0xffffffff)
{
......@@ -409,7 +416,7 @@ public void VisualizeHeader(StringBuilder sb, int codeSize, int maxStack, Immuta
{
sb.Append(' ');
uint pseudoToken = ReadUInt32(ilBytes, ref curIndex);
// Check for an encoding of that indices the current module's module version ID.
// Check for an encoding of the spelling of the current module's module version ID.
if (pseudoToken == 0x80000000)
{
sb.Append("##MVID##");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册