Browse Source

Merge branch 'master' of https://github.com/icsharpcode/ILSpy into fix-1919

pull/1920/head
Siegfried Pammer 5 years ago
parent
commit
f7fc7a4311
  1. 78
      ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs
  2. 4
      ICSharpCode.Decompiler/DebugInfo/AsyncDebugInfo.cs
  3. 2
      ICSharpCode.Decompiler/DebugInfo/SequencePoint.cs
  4. 1
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
  5. 1
      ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs
  6. 30
      ICSharpCode.Decompiler/IL/ILReader.cs
  7. 10
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  8. 2
      ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj
  9. 29
      ILSpy.ReadyToRun/ReadyToRunLanguage.cs

78
ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs

@ -18,9 +18,11 @@ @@ -18,9 +18,11 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Util;
@ -108,6 +110,25 @@ namespace ICSharpCode.Decompiler.CSharp @@ -108,6 +110,25 @@ namespace ICSharpCode.Decompiler.CSharp
public override void VisitBlockStatement(BlockStatement blockStatement)
{
ILInstruction blockContainer = blockStatement.Annotations.OfType<ILInstruction>().FirstOrDefault();
if (blockContainer != null) {
StartSequencePoint(blockStatement.LBraceToken);
int intervalStart = blockContainer.ILRanges.First().Start;
// The end will be set to the first sequence point candidate location before the first statement of the function when the seqeunce point is adjusted
int intervalEnd = intervalStart + 1;
Interval interval = new Interval(intervalStart, intervalEnd);
List<Interval> intervals = new List<Interval>();
intervals.Add(interval);
current.Intervals.AddRange(intervals);
current.Function = blockContainer.Ancestors.OfType<ILFunction>().FirstOrDefault();
EndSequencePoint(blockStatement.LBraceToken.StartLocation, blockStatement.LBraceToken.EndLocation);
}
else {
// Ideally, we'd be able to address this case. Blocks that are not the top-level function block have no ILInstruction annotations. It isn't clear to me how to determine the il range.
// For now, do not add the opening brace sequence in this case.
}
foreach (var stmt in blockStatement.Statements) {
VisitAsSequencePoint(stmt);
}
@ -406,11 +427,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -406,11 +427,13 @@ namespace ICSharpCode.Decompiler.CSharp
}
list.Add(sequencePoint);
}
foreach (var (function, list) in dict.ToList()) {
// For each function, sort sequence points and fix overlaps+gaps
// For each function, sort sequence points and fix overlaps
var newList = new List<DebugInfo.SequencePoint>();
int pos = 0;
foreach (var sequencePoint in list.OrderBy(sp => sp.Offset).ThenBy(sp => sp.EndOffset)) {
IOrderedEnumerable<DebugInfo.SequencePoint> currFunctionSequencePoints = list.OrderBy(sp => sp.Offset).ThenBy(sp => sp.EndOffset);
foreach (DebugInfo.SequencePoint sequencePoint in currFunctionSequencePoints) {
if (sequencePoint.Offset < pos) {
// overlapping sequence point?
// delete previous sequence points that are after sequencePoint.Offset
@ -423,17 +446,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -423,17 +446,12 @@ namespace ICSharpCode.Decompiler.CSharp
newList[newList.Count - 1] = last;
}
}
} else if (sequencePoint.Offset > pos) {
// insert hidden sequence point in the gap.
var hidden = new DebugInfo.SequencePoint();
hidden.Offset = pos;
hidden.EndOffset = sequencePoint.Offset;
hidden.SetHidden();
newList.Add(hidden);
}
newList.Add(sequencePoint);
pos = sequencePoint.EndOffset;
}
// Add a hidden sequence point to account for the epilog of the function
if (pos < function.CodeSize) {
var hidden = new DebugInfo.SequencePoint();
hidden.Offset = pos;
@ -441,8 +459,48 @@ namespace ICSharpCode.Decompiler.CSharp @@ -441,8 +459,48 @@ namespace ICSharpCode.Decompiler.CSharp
hidden.SetHidden();
newList.Add(hidden);
}
List<int> sequencePointCandidates = function.SequencePointCandidates;
int currSPCandidateIndex = 0;
for (int i = 0; i < newList.Count - 1; i++) {
DebugInfo.SequencePoint currSequencePoint = newList[i];
DebugInfo.SequencePoint nextSequencePoint = newList[i + 1];
// Adjust the end offset of the current sequence point to the closest sequence point candidate
// but do not create an overlapping sequence point. Moving the start of the current sequence
// point is not required as it is 0 for the first sequence point and is moved during the last
// iteration for all others.
while (currSPCandidateIndex < sequencePointCandidates.Count &&
sequencePointCandidates[currSPCandidateIndex] < currSequencePoint.EndOffset) {
currSPCandidateIndex++;
}
if (currSPCandidateIndex < sequencePointCandidates.Count && sequencePointCandidates[currSPCandidateIndex] <= nextSequencePoint.Offset) {
currSequencePoint.EndOffset = sequencePointCandidates[currSPCandidateIndex];
}
// Adjust the start offset of the next sequence point to the closest previous sequence point candidate
// but do not create an overlapping sequence point.
while (currSPCandidateIndex < sequencePointCandidates.Count &&
sequencePointCandidates[currSPCandidateIndex] < nextSequencePoint.Offset) {
currSPCandidateIndex++;
}
if (currSPCandidateIndex < sequencePointCandidates.Count && sequencePointCandidates[currSPCandidateIndex - 1] >= currSequencePoint.EndOffset) {
nextSequencePoint.Offset = sequencePointCandidates[currSPCandidateIndex - 1];
currSPCandidateIndex--;
}
// Fill in any gaps with a hidden sequence point
if (currSequencePoint.EndOffset != nextSequencePoint.Offset) {
SequencePoint newSP = new SequencePoint() { Offset = currSequencePoint.EndOffset, EndOffset = nextSequencePoint.Offset };
newSP.SetHidden();
newList.Insert(++i, newSP);
}
}
dict[function] = newList;
}
}
return dict;
}
}

4
ICSharpCode.Decompiler/DebugInfo/AsyncDebugInfo.cs

@ -5,7 +5,7 @@ using System.Reflection.Metadata.Ecma335; @@ -5,7 +5,7 @@ using System.Reflection.Metadata.Ecma335;
namespace ICSharpCode.Decompiler.DebugInfo
{
readonly struct AsyncDebugInfo
public readonly struct AsyncDebugInfo
{
public readonly int CatchHandlerOffset;
public readonly ImmutableArray<Await> Awaits;
@ -28,7 +28,7 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -28,7 +28,7 @@ namespace ICSharpCode.Decompiler.DebugInfo
}
}
internal BlobBuilder BuildBlob(MethodDefinitionHandle moveNext)
public BlobBuilder BuildBlob(MethodDefinitionHandle moveNext)
{
BlobBuilder blob = new BlobBuilder();
blob.WriteUInt32((uint)CatchHandlerOffset);

2
ICSharpCode.Decompiler/DebugInfo/SequencePoint.cs

@ -25,7 +25,7 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -25,7 +25,7 @@ namespace ICSharpCode.Decompiler.DebugInfo
/// A sequence point read from a PDB file or produced by the decompiler.
/// </summary>
[DebuggerDisplay("SequencePoint IL_{Offset,h}-IL_{EndOffset,h}, {StartLine}:{StartColumn}-{EndLine}:{EndColumn}, IsHidden={IsHidden}")]
public struct SequencePoint
public class SequencePoint
{
/// <summary>
/// IL start offset.

1
ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs

@ -819,6 +819,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -819,6 +819,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
function.Body = mainTryCatch.TryBlock;
function.AsyncReturnType = underlyingReturnType;
function.MoveNextMethod = moveNextFunction.Method;
function.SequencePointCandidates = moveNextFunction.SequencePointCandidates;
function.CodeSize = moveNextFunction.CodeSize;
function.IsIterator = IsAsyncEnumerator;
moveNextFunction.Variables.Clear();

1
ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs

@ -532,6 +532,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -532,6 +532,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
ILFunction moveNextFunction = CreateILAst(moveNextMethod, context);
function.MoveNextMethod = moveNextFunction.Method;
function.SequencePointCandidates = moveNextFunction.SequencePointCandidates;
function.CodeSize = moveNextFunction.CodeSize;
// Copy-propagate temporaries holding a copy of 'this'.

30
ICSharpCode.Decompiler/IL/ILReader.cs

@ -50,6 +50,10 @@ namespace ICSharpCode.Decompiler.IL @@ -50,6 +50,10 @@ namespace ICSharpCode.Decompiler.IL
public DebugInfo.IDebugInfoProvider DebugInfo { get; set; }
public List<string> Warnings { get; } = new List<string>();
// List of candidate locations for sequence points. Includes empty il stack locations, any nop instructions, and the instruction following
// a call instruction.
public List<int> SequencePointCandidates { get; private set; }
/// <summary>
/// Creates a new ILReader instance.
/// </summary>
@ -63,6 +67,7 @@ namespace ICSharpCode.Decompiler.IL @@ -63,6 +67,7 @@ namespace ICSharpCode.Decompiler.IL
this.module = module;
this.compilation = module.Compilation;
this.metadata = module.metadata;
this.SequencePointCandidates = new List<int>();
}
GenericContext genericContext;
@ -84,7 +89,7 @@ namespace ICSharpCode.Decompiler.IL @@ -84,7 +89,7 @@ namespace ICSharpCode.Decompiler.IL
UnionFind<ILVariable> unionFind;
List<(ILVariable, ILVariable)> stackMismatchPairs;
IEnumerable<ILVariable> stackVariables;
void Init(MethodDefinitionHandle methodDefinitionHandle, MethodBodyBlock body, GenericContext genericContext)
{
if (body == null)
@ -382,6 +387,7 @@ namespace ICSharpCode.Decompiler.IL @@ -382,6 +387,7 @@ namespace ICSharpCode.Decompiler.IL
int start = reader.Offset;
StoreStackForOffset(start, ref currentStack);
currentInstructionStart = start;
bool startedWithEmptyStack = currentStack.IsEmpty;
ILInstruction decodedInstruction;
try {
decodedInstruction = DecodeInstruction();
@ -400,6 +406,10 @@ namespace ICSharpCode.Decompiler.IL @@ -400,6 +406,10 @@ namespace ICSharpCode.Decompiler.IL
currentStack = ImmutableStack<ILVariable>.Empty;
}
}
if (IsSequencePointInstruction(decodedInstruction) || startedWithEmptyStack) {
this.SequencePointCandidates.Add(decodedInstruction.StartILOffset);
}
}
var visitor = new CollectStackVariablesVisitor(unionFind);
@ -410,6 +420,20 @@ namespace ICSharpCode.Decompiler.IL @@ -410,6 +420,20 @@ namespace ICSharpCode.Decompiler.IL
InsertStackAdjustments();
}
private bool IsSequencePointInstruction(ILInstruction instruction)
{
if (instruction.OpCode == OpCode.Nop ||
(this.instructionBuilder.Count > 0 &&
this.instructionBuilder.Last().OpCode == OpCode.Call ||
this.instructionBuilder.Last().OpCode == OpCode.CallIndirect ||
this.instructionBuilder.Last().OpCode == OpCode.CallVirt)) {
return true;
} else {
return false;
}
}
void InsertStackAdjustments()
{
if (stackMismatchPairs.Count == 0)
@ -509,6 +533,10 @@ namespace ICSharpCode.Decompiler.IL @@ -509,6 +533,10 @@ namespace ICSharpCode.Decompiler.IL
function.Warnings.Add("Discarded unreachable code: "
+ string.Join(", ", removedBlocks.Select(b => $"IL_{b.StartILOffset:x4}")));
}
this.SequencePointCandidates.Sort();
function.SequencePointCandidates = this.SequencePointCandidates;
function.Warnings.AddRange(Warnings);
return function;
}

10
ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs

@ -20,6 +20,7 @@ using System; @@ -20,6 +20,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Collections.Immutable;
using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.TypeSystem;
@ -113,7 +114,7 @@ namespace ICSharpCode.Decompiler.IL @@ -113,7 +114,7 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
internal TypeSystem.Implementation.LocalFunctionMethod ReducedMethod;
internal DebugInfo.AsyncDebugInfo AsyncDebugInfo;
public DebugInfo.AsyncDebugInfo AsyncDebugInfo;
int ctorCallStart = int.MinValue;
@ -169,6 +170,13 @@ namespace ICSharpCode.Decompiler.IL @@ -169,6 +170,13 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public readonly IReadOnlyList<IParameter> Parameters;
/// <summary>
/// List of candidate locations for sequence points. Includes any offset
/// where the stack is empty, nop instructions, and the instruction following
/// a call instruction
/// </summary>
public List<int> SequencePointCandidates { get; set; }
/// <summary>
/// Constructs a new ILFunction from the given metadata and with the given ILAst body.
/// </summary>

2
ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj

@ -57,7 +57,7 @@ @@ -57,7 +57,7 @@
<ItemGroup>
<PackageReference Include="Iced" Version="1.4.0" />
<PackageReference Include="ILCompiler.Reflection.ReadyToRun" Version="1.0.5-alpha" />
<PackageReference Include="ILCompiler.Reflection.ReadyToRun" Version="1.0.6-alpha" />
</ItemGroup>
<Import Sdk="Microsoft.NET.Sdk" Project="Sdk.targets" />

29
ILSpy.ReadyToRun/ReadyToRunLanguage.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Reflection.Metadata;
@ -73,17 +74,13 @@ namespace ICSharpCode.ILSpy.ReadyToRun @@ -73,17 +74,13 @@ namespace ICSharpCode.ILSpy.ReadyToRun
Debug.Assert(reader.Machine == Machine.I386);
bitness = 32;
}
foreach (ReadyToRunMethod readyToRunMethod in reader.Methods) {
if (readyToRunMethod.MethodHandle == method.MetadataToken) {
// TODO: Indexing
foreach (RuntimeFunction runtimeFunction in readyToRunMethod.RuntimeFunctions) {
WriteCommentLine(output, readyToRunMethod.SignatureString);
byte[] code = new byte[runtimeFunction.Size];
for (int i = 0; i < runtimeFunction.Size; i++) {
code[i] = reader.Image[reader.GetOffset(runtimeFunction.StartAddress) + i];
foreach (List<ReadyToRunMethod> readyToRunMethodList in reader.Methods.Values) {
foreach (ReadyToRunMethod readyToRunMethod in readyToRunMethodList) {
if (readyToRunMethod.MethodHandle == method.MetadataToken) {
// TODO: Indexing
foreach (RuntimeFunction runtimeFunction in readyToRunMethod.RuntimeFunctions) {
Disassemble(output, reader, readyToRunMethod, runtimeFunction, bitness, (ulong)runtimeFunction.StartAddress);
}
Disassemble(output, code, bitness, (ulong)runtimeFunction.StartAddress);
output.WriteLine();
}
}
}
@ -95,8 +92,14 @@ namespace ICSharpCode.ILSpy.ReadyToRun @@ -95,8 +92,14 @@ namespace ICSharpCode.ILSpy.ReadyToRun
output.WriteLine("; " + comment);
}
private void Disassemble(ITextOutput output, byte[] codeBytes, int bitness, ulong address)
private void Disassemble(ITextOutput output, ReadyToRunReader reader, ReadyToRunMethod readyToRunMethod, RuntimeFunction runtimeFunction, int bitness, ulong address)
{
WriteCommentLine(output, readyToRunMethod.SignatureString);
byte[] codeBytes = new byte[runtimeFunction.Size];
for (int i = 0; i < runtimeFunction.Size; i++) {
codeBytes[i] = reader.Image[reader.GetOffset(runtimeFunction.StartAddress) + i];
}
// TODO: Decorate the disassembly with Unwind, GC and debug info
var codeReader = new ByteArrayCodeReader(codeBytes);
var decoder = Decoder.Create(bitness, codeReader);
@ -120,11 +123,11 @@ namespace ICSharpCode.ILSpy.ReadyToRun @@ -120,11 +123,11 @@ namespace ICSharpCode.ILSpy.ReadyToRun
formatter.Options.FirstOperandCharIndex = 10;
var tempOutput = new StringBuilderFormatterOutput();
foreach (var instr in instructions) {
int byteBaseIndex = (int)(instr.IP - address);
formatter.Format(instr, tempOutput);
output.Write(instr.IP.ToString("X16"));
output.Write(" ");
int instrLen = instr.ByteLength;
int byteBaseIndex = (int)(instr.IP - address);
for (int i = 0; i < instrLen; i++)
output.Write(codeBytes[byteBaseIndex + i].ToString("X2"));
int missingBytes = 10 - instrLen;
@ -133,6 +136,7 @@ namespace ICSharpCode.ILSpy.ReadyToRun @@ -133,6 +136,7 @@ namespace ICSharpCode.ILSpy.ReadyToRun
output.Write(" ");
output.WriteLine(tempOutput.ToStringAndReset());
}
output.WriteLine();
}
private ReadyToRunReaderCacheEntry GetReader(LoadedAssembly assembly, PEFile module)
@ -142,7 +146,6 @@ namespace ICSharpCode.ILSpy.ReadyToRun @@ -142,7 +146,6 @@ namespace ICSharpCode.ILSpy.ReadyToRun
if (!readyToRunReaders.TryGetValue(module, out result)) {
result = new ReadyToRunReaderCacheEntry();
try {
// TODO: avoid eager parsing
result.readyToRunReader = new ReadyToRunReader(new ReadyToRunAssemblyResolver(assembly), module.Metadata, module.Reader, module.FileName);
if (result.readyToRunReader.Machine != Machine.Amd64 && result.readyToRunReader.Machine != Machine.I386) {
result.failureReason = $"Architecture {result.readyToRunReader.Machine} is not currently supported.";

Loading…
Cancel
Save