Browse Source

Merge pull request #1937 from icsharpcode/pdbgen-enhancements

PDB Generator Enhancements
pull/1968/head
Siegfried Pammer 5 years ago committed by GitHub
parent
commit
90571b3658
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 48
      ICSharpCode.Decompiler/CSharp/Annotations.cs
  2. 5
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 1
      ICSharpCode.Decompiler/CSharp/OutputVisitor/TextWriterTokenWriter.cs
  4. 85
      ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs
  5. 115
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  6. 21
      ICSharpCode.Decompiler/CSharp/Transforms/CombineQueryExpressions.cs
  7. 86
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceQueryExpressions.cs
  8. 30
      ICSharpCode.Decompiler/CSharp/TranslatedStatement.cs
  9. 57
      ICSharpCode.Decompiler/DebugInfo/DebugInfoGenerator.cs
  10. 24
      ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs
  11. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  12. 4
      ICSharpCode.Decompiler/IL/BlockBuilder.cs
  13. 4
      ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs
  14. 4
      ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs
  15. 1
      ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs
  16. 2
      ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs
  17. 2
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  18. 12
      ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs
  19. 6
      ILSpy/Metadata/DebugTables/CustomDebugInformationTableTreeNode.cs
  20. 37
      ILSpy/Metadata/DebugTables/StateMachineMethodTableTreeNode.cs

48
ICSharpCode.Decompiler/CSharp/Annotations.cs

@ -63,6 +63,24 @@ namespace ICSharpCode.Decompiler.CSharp @@ -63,6 +63,24 @@ namespace ICSharpCode.Decompiler.CSharp
return new ExpressionWithILInstruction(expression);
}
internal static TranslatedStatement WithILInstruction(this Statement statement, ILInstruction instruction)
{
statement.AddAnnotation(instruction);
return new TranslatedStatement(statement);
}
internal static TranslatedStatement WithILInstruction(this Statement statement, IEnumerable<ILInstruction> instructions)
{
foreach (var inst in instructions)
statement.AddAnnotation(inst);
return new TranslatedStatement(statement);
}
internal static TranslatedStatement WithoutILInstruction(this Statement statement)
{
return new TranslatedStatement(statement);
}
internal static TranslatedExpression WithILInstruction(this ExpressionWithResolveResult expression, ILInstruction instruction)
{
expression.Expression.AddAnnotation(instruction);
@ -271,4 +289,34 @@ namespace ICSharpCode.Decompiler.CSharp @@ -271,4 +289,34 @@ namespace ICSharpCode.Decompiler.CSharp
this.ConversionResolveResult = conversionResolveResult;
}
}
/// <summary>
/// Annotates a QueryGroupClause with the ILFunctions of each (implicit lambda) expression.
/// </summary>
public class QueryGroupClauseAnnotation
{
public readonly ILFunction KeyLambda;
public readonly ILFunction ProjectionLambda;
public QueryGroupClauseAnnotation(ILFunction key, ILFunction projection)
{
this.KeyLambda = key;
this.ProjectionLambda = projection;
}
}
/// <summary>
/// Annotates a QueryJoinClause with the ILFunctions of each (implicit lambda) expression.
/// </summary>
public class QueryJoinClauseAnnotation
{
public readonly ILFunction OnLambda;
public readonly ILFunction EqualsLambda;
public QueryJoinClauseAnnotation(ILFunction on, ILFunction equals)
{
this.OnLambda = on;
this.EqualsLambda = equals;
}
}
}

5
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1178,7 +1178,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1178,7 +1178,10 @@ namespace ICSharpCode.Decompiler.CSharp
if (countOffsetInst == byteOffsetInst) {
return EnsureIntegerType(byteOffsetExpr);
} else {
return EnsureIntegerType(Translate(countOffsetInst));
TranslatedExpression expr = Translate(countOffsetInst);
// Keep original ILInstruction as annotation
expr.Expression.RemoveAnnotations<ILInstruction>();
return EnsureIntegerType(expr.WithILInstruction(byteOffsetInst));
}
}

1
ICSharpCode.Decompiler/CSharp/OutputVisitor/TextWriterTokenWriter.cs

@ -336,6 +336,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -336,6 +336,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
number += ".0";
}
textWriter.Write(number);
column += number.Length;
Length += number.Length;
} else if (value is IFormattable) {
StringBuilder b = new StringBuilder();

85
ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs

@ -29,6 +29,33 @@ namespace ICSharpCode.Decompiler.CSharp @@ -29,6 +29,33 @@ namespace ICSharpCode.Decompiler.CSharp
/// <summary>
/// Given a SyntaxTree that was output from the decompiler, constructs the list of sequence points.
/// </summary>
// Each statement / expression AST node is annotated with the ILInstruction(s) it was constructed from.
// Each ILInstruction has a list of IL offsets corresponding to the original IL range(s). Note that the ILAst
// instructions form a tree.
//
// This visitor constructs a list of sequence points from the syntax tree by visiting each node,
// calling
// 1. StartSequencePoint(AstNode)
// 2. AddToSequencePoint(AstNode) (possibly multiple times)
// 3. EndSequencePoint(TextLocation, TextLocation)
// on each node.
//
// The VisitAsSequencePoint(AstNode) method encapsulates the steps above.
//
// The state we record for each sequence point is decribed in StatePerSequencePoint:
// 1. primary AST node
// 2. IL range intervals
// 3. parent ILFunction (either a method or lambda)
//
// For each statement (at least) one sequence point is created and all expressions and their IL ranges
// are added to it. Currently the debugger seems not to support breakpoints at an expression level, so
// we stop at the statement level and add all sub-expressions to the same sequence point.
//
// LambdaExpression is one exception: we create new sequence points for the expression/statements of the lambda,
// note however, that these are added to a different ILFunction.
//
// AddToSequencePoint(AstNode) handles the list of ILInstructions and visits each ILInstruction and its descendants.
// We do not descend into nested ILFunctions as these create their own list of sequence points.
class SequencePointBuilder : DepthFirstAstVisitor
{
struct StatePerSequencePoint
@ -94,7 +121,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -94,7 +121,7 @@ namespace ICSharpCode.Decompiler.CSharp
public override void VisitForStatement(ForStatement forStatement)
{
// Every element of a for-statement is it's own sequence point.
// Every element of a for-statement is its own sequence point.
foreach (var init in forStatement.Initializers) {
VisitAsSequencePoint(init);
}
@ -133,6 +160,60 @@ namespace ICSharpCode.Decompiler.CSharp @@ -133,6 +160,60 @@ namespace ICSharpCode.Decompiler.CSharp
VisitAsSequencePoint(lambdaExpression.Body);
}
public override void VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause)
{
AddToSequencePoint(queryContinuationClause);
VisitAsSequencePoint(queryContinuationClause.PrecedingQuery);
}
public override void VisitQueryFromClause(QueryFromClause queryFromClause)
{
if (queryFromClause.Parent.FirstChild != queryFromClause) {
AddToSequencePoint(queryFromClause);
VisitAsSequencePoint(queryFromClause.Expression);
} else {
base.VisitQueryFromClause(queryFromClause);
}
}
public override void VisitQueryGroupClause(QueryGroupClause queryGroupClause)
{
AddToSequencePoint(queryGroupClause);
VisitAsSequencePoint(queryGroupClause.Projection);
VisitAsSequencePoint(queryGroupClause.Key);
}
public override void VisitQueryJoinClause(QueryJoinClause queryJoinClause)
{
AddToSequencePoint(queryJoinClause);
VisitAsSequencePoint(queryJoinClause.OnExpression);
VisitAsSequencePoint(queryJoinClause.EqualsExpression);
}
public override void VisitQueryLetClause(QueryLetClause queryLetClause)
{
AddToSequencePoint(queryLetClause);
VisitAsSequencePoint(queryLetClause.Expression);
}
public override void VisitQueryOrdering(QueryOrdering queryOrdering)
{
AddToSequencePoint(queryOrdering);
VisitAsSequencePoint(queryOrdering.Expression);
}
public override void VisitQuerySelectClause(QuerySelectClause querySelectClause)
{
AddToSequencePoint(querySelectClause);
VisitAsSequencePoint(querySelectClause.Expression);
}
public override void VisitQueryWhereClause(QueryWhereClause queryWhereClause)
{
AddToSequencePoint(queryWhereClause);
VisitAsSequencePoint(queryWhereClause.Condition);
}
public override void VisitUsingStatement(UsingStatement usingStatement)
{
StartSequencePoint(usingStatement);
@ -275,7 +356,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -275,7 +356,7 @@ namespace ICSharpCode.Decompiler.CSharp
internal static bool HasUsableILRange(ILInstruction inst)
{
if (inst.HasILRange)
if (inst.ILRangeIsEmpty)
return false;
return !(inst is BlockContainer || inst is Block);
}

115
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -31,7 +31,7 @@ using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching; @@ -31,7 +31,7 @@ using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
namespace ICSharpCode.Decompiler.CSharp
{
sealed class StatementBuilder : ILVisitor<Statement>
sealed class StatementBuilder : ILVisitor<TranslatedStatement>
{
internal readonly ExpressionBuilder exprBuilder;
readonly ILFunction currentFunction;
@ -64,16 +64,17 @@ namespace ICSharpCode.Decompiler.CSharp @@ -64,16 +64,17 @@ namespace ICSharpCode.Decompiler.CSharp
public BlockStatement ConvertAsBlock(ILInstruction inst)
{
Statement stmt = Convert(inst);
Statement stmt = Convert(inst).WithILInstruction(inst);
return stmt as BlockStatement ?? new BlockStatement { stmt };
}
protected override Statement Default(ILInstruction inst)
protected override TranslatedStatement Default(ILInstruction inst)
{
return new ExpressionStatement(exprBuilder.Translate(inst));
return new ExpressionStatement(exprBuilder.Translate(inst))
.WithILInstruction(inst);
}
protected internal override Statement VisitIsInst(IsInst inst)
protected internal override TranslatedStatement VisitIsInst(IsInst inst)
{
// isinst on top-level (unused result) can be translated in general
// (even for value types) by using "is" instead of "as"
@ -88,34 +89,35 @@ namespace ICSharpCode.Decompiler.CSharp @@ -88,34 +89,35 @@ namespace ICSharpCode.Decompiler.CSharp
)
.WithRR(new ResolveResult(exprBuilder.compilation.FindType(KnownTypeCode.Boolean)))
.WithILInstruction(inst)
);
)
.WithILInstruction(inst);
}
protected internal override Statement VisitStLoc(StLoc inst)
protected internal override TranslatedStatement VisitStLoc(StLoc inst)
{
var expr = exprBuilder.Translate(inst);
// strip top-level ref on ref re-assignment
if (expr.Expression is DirectionExpression dirExpr) {
expr = expr.UnwrapChild(dirExpr.Expression);
}
return new ExpressionStatement(expr);
return new ExpressionStatement(expr).WithILInstruction(inst);
}
protected internal override Statement VisitNop(Nop inst)
protected internal override TranslatedStatement VisitNop(Nop inst)
{
var stmt = new EmptyStatement();
if (inst.Comment != null) {
stmt.AddChild(new Comment(inst.Comment), Roles.Comment);
}
return stmt;
return stmt.WithILInstruction(inst);
}
protected internal override Statement VisitIfInstruction(IfInstruction inst)
protected internal override TranslatedStatement VisitIfInstruction(IfInstruction inst)
{
var condition = exprBuilder.TranslateCondition(inst.Condition);
var trueStatement = Convert(inst.TrueInst);
var falseStatement = inst.FalseInst.OpCode == OpCode.Nop ? null : Convert(inst.FalseInst);
return new IfElseStatement(condition, trueStatement, falseStatement);
return new IfElseStatement(condition, trueStatement, falseStatement).WithILInstruction(inst);
}
IEnumerable<ConstantResolveResult> CreateTypedCaseLabel(long i, IType type, List<(string Key, int Value)> map = null)
@ -150,9 +152,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -150,9 +152,9 @@ namespace ICSharpCode.Decompiler.CSharp
yield return new ConstantResolveResult(type, value);
}
protected internal override Statement VisitSwitchInstruction(SwitchInstruction inst)
protected internal override TranslatedStatement VisitSwitchInstruction(SwitchInstruction inst)
{
return TranslateSwitch(null, inst);
return TranslateSwitch(null, inst).WithILInstruction(inst);
}
SwitchStatement TranslateSwitch(BlockContainer switchContainer, SwitchInstruction inst)
@ -283,18 +285,19 @@ namespace ICSharpCode.Decompiler.CSharp @@ -283,18 +285,19 @@ namespace ICSharpCode.Decompiler.CSharp
/// <summary>Maps blocks to cases.</summary>
Dictionary<Block, ConstantResolveResult> caseLabelMapping;
protected internal override Statement VisitBranch(Branch inst)
protected internal override TranslatedStatement VisitBranch(Branch inst)
{
if (inst.TargetBlock == continueTarget) {
continueCount++;
return new ContinueStatement();
return new ContinueStatement().WithILInstruction(inst);
}
if (caseLabelMapping != null && caseLabelMapping.TryGetValue(inst.TargetBlock, out var label)) {
if (label == null)
return new GotoDefaultStatement();
return new GotoCaseStatement() { LabelExpression = exprBuilder.ConvertConstantValue(label, allowImplicitConversion: true) };
return new GotoDefaultStatement().WithILInstruction(inst);
return new GotoCaseStatement() { LabelExpression = exprBuilder.ConvertConstantValue(label, allowImplicitConversion: true) }
.WithILInstruction(inst);
}
return new GotoStatement(inst.TargetLabel);
return new GotoStatement(inst.TargetLabel).WithILInstruction(inst);
}
/// <summary>Target container that a 'break;' statement would break out of</summary>
@ -302,45 +305,45 @@ namespace ICSharpCode.Decompiler.CSharp @@ -302,45 +305,45 @@ namespace ICSharpCode.Decompiler.CSharp
/// <summary>Dictionary from BlockContainer to label name for 'goto of_container';</summary>
readonly Dictionary<BlockContainer, string> endContainerLabels = new Dictionary<BlockContainer, string>();
protected internal override Statement VisitLeave(Leave inst)
protected internal override TranslatedStatement VisitLeave(Leave inst)
{
if (inst.TargetContainer == breakTarget)
return new BreakStatement();
return new BreakStatement().WithILInstruction(inst);
if (inst.TargetContainer == currentReturnContainer) {
if (currentIsIterator)
return new YieldBreakStatement();
return new YieldBreakStatement().WithILInstruction(inst);
else if (!inst.Value.MatchNop()) {
var expr = exprBuilder.Translate(inst.Value, typeHint: currentResultType)
.ConvertTo(currentResultType, exprBuilder, allowImplicitConversion: true);
return new ReturnStatement(expr);
return new ReturnStatement(expr).WithILInstruction(inst);
} else
return new ReturnStatement();
return new ReturnStatement().WithILInstruction(inst);
}
if (!endContainerLabels.TryGetValue(inst.TargetContainer, out string label)) {
label = "end_" + inst.TargetLabel;
endContainerLabels.Add(inst.TargetContainer, label);
}
return new GotoStatement(label);
return new GotoStatement(label).WithILInstruction(inst);
}
protected internal override Statement VisitThrow(Throw inst)
protected internal override TranslatedStatement VisitThrow(Throw inst)
{
return new ThrowStatement(exprBuilder.Translate(inst.Argument));
return new ThrowStatement(exprBuilder.Translate(inst.Argument)).WithILInstruction(inst);
}
protected internal override Statement VisitRethrow(Rethrow inst)
protected internal override TranslatedStatement VisitRethrow(Rethrow inst)
{
return new ThrowStatement();
return new ThrowStatement().WithILInstruction(inst);
}
protected internal override Statement VisitYieldReturn(YieldReturn inst)
protected internal override TranslatedStatement VisitYieldReturn(YieldReturn inst)
{
var elementType = currentFunction.ReturnType.GetElementTypeFromIEnumerable(typeSystem, true, out var isGeneric);
var expr = exprBuilder.Translate(inst.Value, typeHint: elementType)
.ConvertTo(elementType, exprBuilder, allowImplicitConversion: true);
return new YieldReturnStatement {
Expression = expr
};
}.WithILInstruction(inst);
}
TryCatchStatement MakeTryCatch(ILInstruction tryBlock)
@ -354,7 +357,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -354,7 +357,7 @@ namespace ICSharpCode.Decompiler.CSharp
return tryCatch;
}
protected internal override Statement VisitTryCatch(TryCatch inst)
protected internal override TranslatedStatement VisitTryCatch(TryCatch inst)
{
var tryCatch = new TryCatchStatement();
tryCatch.TryBlock = ConvertAsBlock(inst.TryBlock);
@ -375,17 +378,17 @@ namespace ICSharpCode.Decompiler.CSharp @@ -375,17 +378,17 @@ namespace ICSharpCode.Decompiler.CSharp
catchClause.Body = ConvertAsBlock(handler.Body);
tryCatch.CatchClauses.Add(catchClause);
}
return tryCatch;
return tryCatch.WithILInstruction(inst);
}
protected internal override Statement VisitTryFinally(TryFinally inst)
protected internal override TranslatedStatement VisitTryFinally(TryFinally inst)
{
var tryCatch = MakeTryCatch(inst.TryBlock);
tryCatch.FinallyBlock = ConvertAsBlock(inst.FinallyBlock);
return tryCatch;
return tryCatch.WithILInstruction(inst);
}
protected internal override Statement VisitTryFault(TryFault inst)
protected internal override TranslatedStatement VisitTryFault(TryFault inst)
{
var tryCatch = new TryCatchStatement();
tryCatch.TryBlock = ConvertAsBlock(inst.TryBlock);
@ -393,27 +396,27 @@ namespace ICSharpCode.Decompiler.CSharp @@ -393,27 +396,27 @@ namespace ICSharpCode.Decompiler.CSharp
faultBlock.InsertChildAfter(null, new Comment("try-fault"), Roles.Comment);
faultBlock.Add(new ThrowStatement());
tryCatch.CatchClauses.Add(new CatchClause { Body = faultBlock });
return tryCatch;
return tryCatch.WithILInstruction(inst);
}
protected internal override Statement VisitLockInstruction(LockInstruction inst)
protected internal override TranslatedStatement VisitLockInstruction(LockInstruction inst)
{
return new LockStatement {
Expression = exprBuilder.Translate(inst.OnExpression),
EmbeddedStatement = ConvertAsBlock(inst.Body)
};
}.WithILInstruction(inst);
}
#region foreach construction
static readonly InvocationExpression getEnumeratorPattern = new InvocationExpression(new MemberReferenceExpression(new AnyNode("collection").ToExpression(), "GetEnumerator"));
static readonly InvocationExpression moveNextConditionPattern = new InvocationExpression(new MemberReferenceExpression(new NamedNode("enumerator", new IdentifierExpression(Pattern.AnyString)), "MoveNext"));
protected internal override Statement VisitUsingInstruction(UsingInstruction inst)
protected internal override TranslatedStatement VisitUsingInstruction(UsingInstruction inst)
{
var resource = exprBuilder.Translate(inst.ResourceExpression).Expression;
var transformed = TransformToForeach(inst, resource);
if (transformed != null)
return transformed;
return transformed.WithILInstruction(inst);
AstNode usingInit = resource;
var var = inst.Variable;
KnownTypeCode knownTypeCode;
@ -451,7 +454,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -451,7 +454,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
},
};
}.WithILInstruction(inst);
} else {
if (var.LoadCount > 0 || var.AddressCount > 0) {
var type = settings.AnonymousTypes && var.Type.ContainsAnonymousType() ? new SimpleType("var") : exprBuilder.ConvertType(var.Type);
@ -463,7 +466,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -463,7 +466,7 @@ namespace ICSharpCode.Decompiler.CSharp
ResourceAcquisition = usingInit,
IsAsync = inst.IsAsync,
EmbeddedStatement = ConvertAsBlock(inst.Body)
};
}.WithILInstruction(inst);
}
}
@ -814,7 +817,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -814,7 +817,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
#endregion
protected internal override Statement VisitPinnedRegion(PinnedRegion inst)
protected internal override TranslatedStatement VisitPinnedRegion(PinnedRegion inst)
{
var fixedStmt = new FixedStatement();
fixedStmt.Type = exprBuilder.ConvertType(inst.Variable.Type);
@ -831,10 +834,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -831,10 +834,10 @@ namespace ICSharpCode.Decompiler.CSharp
}
fixedStmt.Variables.Add(new VariableInitializer(inst.Variable.Name, initExpr).WithILVariable(inst.Variable));
fixedStmt.EmbeddedStatement = Convert(inst.Body);
return fixedStmt;
return fixedStmt.WithILInstruction(inst);
}
protected internal override Statement VisitBlock(Block block)
protected internal override TranslatedStatement VisitBlock(Block block)
{
if (block.Kind != BlockKind.ControlFlow)
return Default(block);
@ -845,10 +848,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -845,10 +848,10 @@ namespace ICSharpCode.Decompiler.CSharp
}
if (block.FinalInstruction.OpCode != OpCode.Nop)
blockStatement.Add(Convert(block.FinalInstruction));
return blockStatement;
return blockStatement.WithILInstruction(block);
}
protected internal override Statement VisitBlockContainer(BlockContainer container)
protected internal override TranslatedStatement VisitBlockContainer(BlockContainer container)
{
if (container.Kind != ContainerKind.Normal && container.EntryPoint.IncomingEdgeCount > 1) {
var oldContinueTarget = continueTarget;
@ -859,13 +862,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -859,13 +862,12 @@ namespace ICSharpCode.Decompiler.CSharp
continueTarget = oldContinueTarget;
continueCount = oldContinueCount;
breakTarget = oldBreakTarget;
return loop;
return loop.WithILInstruction(container);
} else if (container.EntryPoint.Instructions.Count == 1 && container.EntryPoint.Instructions[0] is SwitchInstruction switchInst) {
return TranslateSwitch(container, switchInst);
return TranslateSwitch(container, switchInst).WithILInstruction(container);
} else {
var blockStmt = ConvertBlockContainer(container, false);
blockStmt.AddAnnotation(container);
return blockStmt;
return blockStmt.WithILInstruction(container);
}
}
@ -1015,6 +1017,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1015,6 +1017,7 @@ namespace ICSharpCode.Decompiler.CSharp
stmt.Modifiers |= Modifiers.Static;
}
stmt.AddAnnotation(new MemberResolveResult(null, function.ReducedMethod));
stmt.WithILInstruction(function);
return stmt;
}
}
@ -1069,7 +1072,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1069,7 +1072,7 @@ namespace ICSharpCode.Decompiler.CSharp
&& container == leave.TargetContainer;
}
protected internal override Statement VisitInitblk(Initblk inst)
protected internal override TranslatedStatement VisitInitblk(Initblk inst)
{
var stmt = new ExpressionStatement(
exprBuilder.CallUnsafeIntrinsic(
@ -1084,10 +1087,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1084,10 +1087,10 @@ namespace ICSharpCode.Decompiler.CSharp
)
);
stmt.InsertChildAfter(null, new Comment(" IL initblk instruction"), Roles.Comment);
return stmt;
return stmt.WithILInstruction(inst);
}
protected internal override Statement VisitCpblk(Cpblk inst)
protected internal override TranslatedStatement VisitCpblk(Cpblk inst)
{
var stmt = new ExpressionStatement(
exprBuilder.CallUnsafeIntrinsic(
@ -1102,7 +1105,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1102,7 +1105,7 @@ namespace ICSharpCode.Decompiler.CSharp
)
);
stmt.InsertChildAfter(null, new Comment(" IL cpblk instruction"), Roles.Comment);
return stmt;
return stmt.WithILInstruction(inst);
}
}
}

21
ICSharpCode.Decompiler/CSharp/Transforms/CombineQueryExpressions.cs

@ -43,25 +43,26 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -43,25 +43,26 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
TypeArguments = { new AnyNode("targetType") }
}};
void CombineQueries(AstNode node, Dictionary<string, object> letIdentifiers)
void CombineQueries(AstNode node, Dictionary<string, object> fromOrLetIdentifiers)
{
AstNode next;
for (AstNode child = node.FirstChild; child != null; child = next) {
// store referece to next child before transformation
// store reference to next child before transformation
next = child.NextSibling;
CombineQueries(child, letIdentifiers);
CombineQueries(child, fromOrLetIdentifiers);
}
QueryExpression query = node as QueryExpression;
if (query != null) {
QueryFromClause fromClause = (QueryFromClause)query.Clauses.First();
QueryExpression innerQuery = fromClause.Expression as QueryExpression;
if (innerQuery != null) {
if (TryRemoveTransparentIdentifier(query, fromClause, innerQuery, letIdentifiers)) {
RemoveTransparentIdentifierReferences(query, letIdentifiers);
if (TryRemoveTransparentIdentifier(query, fromClause, innerQuery, fromOrLetIdentifiers)) {
RemoveTransparentIdentifierReferences(query, fromOrLetIdentifiers);
} else {
QueryContinuationClause continuation = new QueryContinuationClause();
continuation.PrecedingQuery = innerQuery.Detach();
continuation.Identifier = fromClause.Identifier;
continuation.CopyAnnotationsFrom(fromClause);
fromClause.ReplaceWith(continuation);
}
} else {
@ -119,8 +120,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -119,8 +120,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
foreach (var expr in match.Get<Expression>("expr")) {
switch (expr) {
case IdentifierExpression identifier:
// nothing to add
continue;
letClauses[identifier.Identifier] = identifier.Annotation<ILVariableResolveResult>();
break;
case MemberReferenceExpression member:
AddQueryLetClause(member.MemberName, member);
break;
@ -148,10 +149,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -148,10 +149,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// <summary>
/// Removes all occurrences of transparent identifiers
/// </summary>
void RemoveTransparentIdentifierReferences(AstNode node, Dictionary<string, object> letClauses)
void RemoveTransparentIdentifierReferences(AstNode node, Dictionary<string, object> fromOrLetIdentifiers)
{
foreach (AstNode child in node.Children) {
RemoveTransparentIdentifierReferences(child, letClauses);
RemoveTransparentIdentifierReferences(child, fromOrLetIdentifiers);
}
MemberReferenceExpression mre = node as MemberReferenceExpression;
if (mre != null) {
@ -161,7 +162,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -161,7 +162,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
mre.TypeArguments.MoveTo(newIdent.TypeArguments);
newIdent.CopyAnnotationsFrom(mre);
newIdent.RemoveAnnotations<Semantics.MemberResolveResult>(); // remove the reference to the property of the anonymous type
if (letClauses.TryGetValue(mre.MemberName, out var annotation))
if (fromOrLetIdentifiers.TryGetValue(mre.MemberName, out var annotation))
newIdent.AddAnnotation(annotation);
mre.ReplaceWith(newIdent);
return;

86
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceQueryExpressions.cs

@ -76,7 +76,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -76,7 +76,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
node.ReplaceWith(query);
AstNode next;
for (AstNode child = (query ?? node).FirstChild; child != null; child = next) {
// store referece to next child before transformation
// store reference to next child before transformation
next = child.NextSibling;
DecompileQueries(child);
}
@ -95,12 +95,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -95,12 +95,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return null;
if (!IsComplexQuery(mre))
return null;
ParameterDeclaration parameter;
Expression body;
if (MatchSimpleLambda(invocation.Arguments.Single(), out parameter, out body)) {
Expression expr = invocation.Arguments.Single();
if (MatchSimpleLambda(expr, out ParameterDeclaration parameter, out Expression body)) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(parameter, mre.Target.Detach()));
query.Clauses.Add(new QuerySelectClause { Expression = WrapExpressionInParenthesesIfNecessary(body.Detach(), parameter.Name) });
query.Clauses.Add(new QuerySelectClause { Expression = WrapExpressionInParenthesesIfNecessary(body.Detach(), parameter.Name) }.CopyAnnotationsFrom(expr));
return query;
}
return null;
@ -108,21 +107,24 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -108,21 +107,24 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
case "GroupBy":
{
if (invocation.Arguments.Count == 2) {
ParameterDeclaration parameter1, parameter2;
Expression keySelector, elementSelector;
if (MatchSimpleLambda(invocation.Arguments.ElementAt(0), out parameter1, out keySelector)
&& MatchSimpleLambda(invocation.Arguments.ElementAt(1), out parameter2, out elementSelector)
&& parameter1.Name == parameter2.Name)
{
Expression keyLambda = invocation.Arguments.ElementAt(0);
Expression projectionLambda = invocation.Arguments.ElementAt(1);
if (MatchSimpleLambda(keyLambda, out ParameterDeclaration parameter1, out Expression keySelector)
&& MatchSimpleLambda(projectionLambda, out ParameterDeclaration parameter2, out Expression elementSelector)
&& parameter1.Name == parameter2.Name) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(parameter1, mre.Target.Detach()));
query.Clauses.Add(new QueryGroupClause { Projection = elementSelector.Detach(), Key = keySelector.Detach() });
var queryGroupClause = new QueryGroupClause {
Projection = elementSelector.Detach(),
Key = keySelector.Detach()
};
queryGroupClause.AddAnnotation(new QueryGroupClauseAnnotation(keyLambda.Annotation<IL.ILFunction>(), projectionLambda.Annotation<IL.ILFunction>()));
query.Clauses.Add(queryGroupClause);
return query;
}
} else if (invocation.Arguments.Count == 1) {
ParameterDeclaration parameter;
Expression keySelector;
if (MatchSimpleLambda(invocation.Arguments.Single(), out parameter, out keySelector)) {
Expression lambda = invocation.Arguments.Single();
if (MatchSimpleLambda(lambda, out ParameterDeclaration parameter, out Expression keySelector)) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(parameter, mre.Target.Detach()));
query.Clauses.Add(new QueryGroupClause { Projection = new IdentifierExpression(parameter.Name).CopyAnnotationsFrom(parameter), Key = keySelector.Detach() });
@ -135,9 +137,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -135,9 +137,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
if (invocation.Arguments.Count != 2)
return null;
ParameterDeclaration parameter;
Expression collectionSelector;
if (!MatchSimpleLambda(invocation.Arguments.ElementAt(0), out parameter, out collectionSelector))
var fromExpressionLambda = invocation.Arguments.ElementAt(0);
if (!MatchSimpleLambda(fromExpressionLambda, out ParameterDeclaration parameter, out Expression collectionSelector))
return null;
if (IsNullConditional(collectionSelector))
return null;
@ -148,7 +149,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -148,7 +149,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (p1.Name == parameter.Name) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(p1, mre.Target.Detach()));
query.Clauses.Add(MakeFromClause(p2, collectionSelector.Detach()));
query.Clauses.Add(MakeFromClause(p2, collectionSelector.Detach()).CopyAnnotationsFrom(fromExpressionLambda));
query.Clauses.Add(new QuerySelectClause { Expression = WrapExpressionInParenthesesIfNecessary(((Expression)lambda.Body).Detach(), parameter.Name) });
return query;
}
@ -161,12 +162,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -161,12 +162,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return null;
if (!IsComplexQuery(mre))
return null;
ParameterDeclaration parameter;
Expression body;
if (MatchSimpleLambda(invocation.Arguments.Single(), out parameter, out body)) {
Expression expr = invocation.Arguments.Single();
if (MatchSimpleLambda(expr, out ParameterDeclaration parameter, out Expression body)) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(parameter, mre.Target.Detach()));
query.Clauses.Add(new QueryWhereClause { Condition = body.Detach() });
query.Clauses.Add(new QueryWhereClause { Condition = body.Detach() }.CopyAnnotationsFrom(expr));
return query;
}
return null;
@ -180,31 +180,30 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -180,31 +180,30 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return null;
if (!IsComplexQuery(mre))
return null;
ParameterDeclaration parameter;
Expression orderExpression;
if (MatchSimpleLambda(invocation.Arguments.Single(), out parameter, out orderExpression)) {
var lambda = invocation.Arguments.Single();
if (MatchSimpleLambda(lambda, out ParameterDeclaration parameter, out Expression orderExpression)) {
if (ValidateThenByChain(invocation, parameter.Name)) {
QueryOrderClause orderClause = new QueryOrderClause();
InvocationExpression tmp = invocation;
while (mre.MemberName == "ThenBy" || mre.MemberName == "ThenByDescending") {
// insert new ordering at beginning
orderClause.Orderings.InsertAfter(
null, new QueryOrdering {
Expression = orderExpression.Detach(),
Direction = (mre.MemberName == "ThenBy" ? QueryOrderingDirection.None : QueryOrderingDirection.Descending)
});
tmp = (InvocationExpression)mre.Target;
}.CopyAnnotationsFrom(lambda));
InvocationExpression tmp = (InvocationExpression)mre.Target;
mre = (MemberReferenceExpression)tmp.Target;
MatchSimpleLambda(tmp.Arguments.Single(), out parameter, out orderExpression);
lambda = tmp.Arguments.Single();
MatchSimpleLambda(lambda, out parameter, out orderExpression);
}
// insert new ordering at beginning
orderClause.Orderings.InsertAfter(
null, new QueryOrdering {
Expression = orderExpression.Detach(),
Direction = (mre.MemberName == "OrderBy" ? QueryOrderingDirection.None : QueryOrderingDirection.Descending)
});
}.CopyAnnotationsFrom(lambda));
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(parameter, mre.Target.Detach()));
query.Clauses.Add(orderClause);
@ -222,11 +221,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -222,11 +221,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
Expression source2 = invocation.Arguments.ElementAt(0);
if (IsNullConditional(source2))
return null;
ParameterDeclaration element1, element2;
Expression key1, key2;
if (!MatchSimpleLambda(invocation.Arguments.ElementAt(1), out element1, out key1))
Expression outerLambda = invocation.Arguments.ElementAt(1);
if (!MatchSimpleLambda(outerLambda, out ParameterDeclaration element1, out Expression key1))
return null;
if (!MatchSimpleLambda(invocation.Arguments.ElementAt(2), out element2, out key2))
Expression innerLambda = invocation.Arguments.ElementAt(2);
if (!MatchSimpleLambda(innerLambda, out ParameterDeclaration element2, out Expression key2))
return null;
LambdaExpression lambda = invocation.Arguments.ElementAt(3) as LambdaExpression;
if (lambda != null && lambda.Parameters.Count == 2 && lambda.Body is Expression) {
@ -243,8 +242,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -243,8 +242,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (mre.MemberName == "GroupJoin") {
joinClause.IntoIdentifier = p2.Name; // into p2.Name
}
joinClause.AddAnnotation(new QueryJoinClauseAnnotation(outerLambda.Annotation<IL.ILFunction>(), innerLambda.Annotation<IL.ILFunction>()));
query.Clauses.Add(joinClause);
query.Clauses.Add(new QuerySelectClause { Expression = ((Expression)lambda.Body).Detach() });
query.Clauses.Add(new QuerySelectClause { Expression = ((Expression)lambda.Body).Detach() }.CopyAnnotationsFrom(lambda));
return query;
}
}
@ -314,12 +314,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -314,12 +314,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
if (invocation == null || invocation.Arguments.Count != 1)
return false;
MemberReferenceExpression mre = invocation.Target as MemberReferenceExpression;
if (mre == null)
if (!(invocation.Target is MemberReferenceExpression mre))
return false;
ParameterDeclaration parameter;
Expression body;
if (!MatchSimpleLambda(invocation.Arguments.Single(), out parameter, out body))
if (!MatchSimpleLambda(invocation.Arguments.Single(), out ParameterDeclaration parameter, out _))
return false;
if (parameter.Name != expectedParameterName)
return false;
@ -335,8 +332,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -335,8 +332,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// <summary>Matches simple lambdas of the form "a => b"</summary>
bool MatchSimpleLambda(Expression expr, out ParameterDeclaration parameter, out Expression body)
{
var lambda = expr as LambdaExpression;
if (lambda != null && lambda.Parameters.Count == 1 && lambda.Body is Expression) {
if (expr is LambdaExpression lambda && lambda.Parameters.Count == 1 && lambda.Body is Expression) {
ParameterDeclaration p = lambda.Parameters.Single();
if (p.ParameterModifier == ParameterModifier.None) {
parameter = p;

30
ICSharpCode.Decompiler/CSharp/TranslatedStatement.cs

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.IL;
namespace ICSharpCode.Decompiler.CSharp
{
[DebuggerDisplay("{Statement}")]
struct TranslatedStatement
{
public readonly Statement Statement;
public IEnumerable<ILInstruction> ILInstructions {
get { return Statement.Annotations.OfType<ILInstruction>(); }
}
internal TranslatedStatement(Statement statement)
{
Debug.Assert(statement != null);
this.Statement = statement;
}
public static implicit operator Statement(TranslatedStatement statement)
{
return statement.Statement;
}
}
}

57
ICSharpCode.Decompiler/DebugInfo/DebugInfoGenerator.cs

@ -133,12 +133,67 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -133,12 +133,67 @@ namespace ICSharpCode.Decompiler.DebugInfo
HandleMethod(anonymousMethodExpression);
}
public override void VisitQueryFromClause(QueryFromClause queryFromClause)
{
if (queryFromClause.Parent.FirstChild != queryFromClause) {
HandleMethod(queryFromClause);
} else {
base.VisitQueryFromClause(queryFromClause);
}
}
public override void VisitQueryGroupClause(QueryGroupClause queryGroupClause)
{
var annotation = queryGroupClause.Annotation<QueryGroupClauseAnnotation>();
if (annotation == null) {
base.VisitQueryGroupClause(queryGroupClause);
return;
}
HandleMethod(queryGroupClause.Projection, annotation.ProjectionLambda);
HandleMethod(queryGroupClause.Key, annotation.KeyLambda);
}
public override void VisitQueryJoinClause(QueryJoinClause queryJoinClause)
{
var annotation = queryJoinClause.Annotation<QueryJoinClauseAnnotation>();
if (annotation == null) {
base.VisitQueryJoinClause(queryJoinClause);
return;
}
HandleMethod(queryJoinClause.OnExpression, annotation.OnLambda);
HandleMethod(queryJoinClause.EqualsExpression, annotation.EqualsLambda);
}
public override void VisitQueryLetClause(QueryLetClause queryLetClause)
{
HandleMethod(queryLetClause);
}
public override void VisitQueryOrdering(QueryOrdering queryOrdering)
{
HandleMethod(queryOrdering);
}
public override void VisitQuerySelectClause(QuerySelectClause querySelectClause)
{
HandleMethod(querySelectClause);
}
public override void VisitQueryWhereClause(QueryWhereClause queryWhereClause)
{
HandleMethod(queryWhereClause);
}
void HandleMethod(AstNode node)
{
HandleMethod(node, node.Annotation<ILFunction>());
}
void HandleMethod(AstNode node, ILFunction function)
{
// Look into method body, e.g. in order to find lambdas
VisitChildren(node);
var function = node.Annotation<ILFunction>();
if (function == null || function.Method == null || function.Method.MetadataToken.IsNil)
return;
this.functions.Add(function);

24
ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs

@ -31,7 +31,6 @@ using System.Text; @@ -31,7 +31,6 @@ using System.Text;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.TypeSystem;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
@ -58,7 +57,7 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -58,7 +57,7 @@ namespace ICSharpCode.Decompiler.DebugInfo
var emptyList = new List<SequencePoint>();
var localScopes = new List<(MethodDefinitionHandle Method, ImportScopeInfo Import, int Offset, int Length, HashSet<ILVariable> Locals)>();
var stateMachineMethods = new List<(MethodDefinitionHandle MoveNextMethod, MethodDefinitionHandle KickoffMethod)>();
var customDocumentDebugInfo = new List<(DocumentHandle Parent, GuidHandle Guid, BlobHandle Blob)>();
var customDebugInfo = new List<(EntityHandle Parent, GuidHandle Guid, BlobHandle Blob)>();
var customMethodDebugInfo = new List<(MethodDefinitionHandle Parent, GuidHandle Guid, BlobHandle Blob)>();
var globalImportScope = metadata.AddImportScope(default, default);
@ -97,7 +96,7 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -97,7 +96,7 @@ namespace ICSharpCode.Decompiler.DebugInfo
language: metadata.GetOrAddGuid(KnownGuids.CSharpLanguageGuid));
// Add embedded source to the PDB
customDocumentDebugInfo.Add((document,
customDebugInfo.Add((document,
metadata.GetOrAddGuid(KnownGuids.EmbeddedSource),
sourceBlob));
@ -115,6 +114,11 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -115,6 +114,11 @@ namespace ICSharpCode.Decompiler.DebugInfo
(MethodDefinitionHandle)function.MoveNextMethod.MetadataToken,
(MethodDefinitionHandle)function.Method.MetadataToken
));
customDebugInfo.Add((
function.MoveNextMethod.MetadataToken,
metadata.GetOrAddGuid(KnownGuids.StateMachineHoistedLocalScopes),
metadata.GetOrAddBlob(BuildStateMachineHoistedLocalScopes(function))
));
}
if (function.IsAsync) {
customMethodDebugInfo.Add((methodHandle,
@ -165,8 +169,8 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -165,8 +169,8 @@ namespace ICSharpCode.Decompiler.DebugInfo
foreach (var row in customMethodDebugInfo) {
metadata.AddCustomDebugInformation(row.Parent, row.Guid, row.Blob);
}
customDocumentDebugInfo.SortBy(row => MetadataTokens.GetRowNumber(row.Parent));
foreach (var row in customDocumentDebugInfo) {
customDebugInfo.SortBy(row => MetadataTokens.GetRowNumber(row.Parent));
foreach (var row in customDebugInfo) {
metadata.AddCustomDebugInformation(row.Parent, row.Guid, row.Blob);
}
@ -198,6 +202,16 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -198,6 +202,16 @@ namespace ICSharpCode.Decompiler.DebugInfo
}
}
static BlobBuilder BuildStateMachineHoistedLocalScopes(ILFunction function)
{
var builder = new BlobBuilder();
foreach (var variable in function.Variables.Where(v => v.StateMachineField != null).OrderBy(v => MetadataTokens.GetRowNumber(v.StateMachineField.MetadataToken))) {
builder.WriteUInt32(0);
builder.WriteUInt32((uint)function.CodeSize);
}
return builder;
}
static BlobHandle WriteSourceToBlob(MetadataBuilder metadata, string sourceText, out byte[] sourceCheckSum)
{
var builder = new BlobBuilder();

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -63,6 +63,7 @@ @@ -63,6 +63,7 @@
<Compile Include="CSharp\CSharpLanguageVersion.cs" />
<Compile Include="CSharp\RequiredNamespaceCollector.cs" />
<Compile Include="CSharp\SequencePointBuilder.cs" />
<Compile Include="CSharp\TranslatedStatement.cs" />
<Compile Include="DebugInfo\KnownGuids.cs" />
<Compile Include="Disassembler\DisassemblerSignatureTypeProvider.cs" />
<Compile Include="Documentation\XmlDocumentationElement.cs" />

4
ICSharpCode.Decompiler/IL/BlockBuilder.cs

@ -137,7 +137,7 @@ namespace ICSharpCode.Decompiler.IL @@ -137,7 +137,7 @@ namespace ICSharpCode.Decompiler.IL
// this container is skipped (i.e. the loop will execute again)
// set ILRange to the last instruction offset inside the block.
if (start >= currentContainer.EndILOffset) {
Debug.Assert(currentBlock.HasILRange);
Debug.Assert(currentBlock.ILRangeIsEmpty);
currentBlock.AddILRange(new Interval(currentBlock.StartILOffset, start));
}
}
@ -190,7 +190,7 @@ namespace ICSharpCode.Decompiler.IL @@ -190,7 +190,7 @@ namespace ICSharpCode.Decompiler.IL
{
if (currentBlock == null)
return;
Debug.Assert(currentBlock.HasILRange);
Debug.Assert(currentBlock.ILRangeIsEmpty);
currentBlock.SetILRange(new Interval(currentBlock.StartILOffset, currentILOffset));
if (fallthrough) {
if (currentBlock.Instructions.LastOrDefault() is SwitchInstruction switchInst && switchInst.Sections.Last().Body.MatchNop()) {

4
ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs

@ -442,11 +442,11 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -442,11 +442,11 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// some compilers merge the leave instructions for different arguments using stack variables
// these get split and inlined, but the ILRange of the value remains a better indicator of the actual location
if (inst is Leave leave && !leave.Value.MatchNop()) {
isEmpty = leave.Value.HasILRange;
isEmpty = leave.Value.ILRangeIsEmpty;
return leave.Value.StartILOffset;
}
isEmpty = inst.HasILRange;
isEmpty = inst.ILRangeIsEmpty;
return inst.StartILOffset;
}

4
ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs

@ -166,7 +166,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -166,7 +166,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
context.Step("Replace branch to leave with leave", branch);
// Replace branches to 'leave' instruction with the leave instruction
var leave2 = leave.Clone();
if (!branch.HasILRange) // use the ILRange of the branch if possible
if (!branch.ILRangeIsEmpty) // use the ILRange of the branch if possible
leave2.AddILRange(branch);
branch.ReplaceWith(leave2);
}
@ -221,7 +221,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -221,7 +221,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
block.Instructions.RemoveRange(block.Instructions.Count - 3, 2);
}
if (block.HasILRange)
if (block.ILRangeIsEmpty)
block.AddILRange(targetBlock);
block.Instructions.Remove(br);

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.CodeSize = moveNextFunction.CodeSize;
// Copy-propagate temporaries holding a copy of 'this'.
// This is necessary because the old (pre-Roslyn) C# compiler likes to store 'this' in temporary variables.

2
ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs

@ -181,7 +181,7 @@ namespace ICSharpCode.Decompiler.IL @@ -181,7 +181,7 @@ namespace ICSharpCode.Decompiler.IL
base.CheckInvariant(phase);
Debug.Assert(Blocks.Count > 0 && EntryPoint == Blocks[0]);
Debug.Assert(!IsConnected || EntryPoint?.IncomingEdgeCount >= 1);
Debug.Assert(EntryPoint == null || Parent is ILFunction || !HasILRange);
Debug.Assert(EntryPoint == null || Parent is ILFunction || !ILRangeIsEmpty);
Debug.Assert(Blocks.All(b => b.HasFlag(InstructionFlags.EndPointUnreachable)));
Debug.Assert(Blocks.All(b => b.Kind == BlockKind.ControlFlow)); // this also implies that the blocks don't use FinalInstruction
Debug.Assert(TopologicalSort(deleteUnreachableBlocks: true).Count == Blocks.Count, "Container should not have any unreachable blocks");

2
ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

@ -253,7 +253,7 @@ namespace ICSharpCode.Decompiler.IL @@ -253,7 +253,7 @@ namespace ICSharpCode.Decompiler.IL
public int EndILOffset => ILRange.End;
public bool HasILRange => ILRange.IsEmpty;
public bool ILRangeIsEmpty => ILRange.IsEmpty;
public IEnumerable<Interval> ILRanges => new[] { ILRange };

12
ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs

@ -101,6 +101,18 @@ namespace ICSharpCode.Decompiler.Metadata @@ -101,6 +101,18 @@ namespace ICSharpCode.Decompiler.Metadata
return sb.ToString();
}
public static string ToHexString(this BlobReader reader)
{
StringBuilder sb = new StringBuilder(reader.Length * 3);
for (int i = 0; i < reader.Length; i++) {
if (i == 0)
sb.AppendFormat("{0:X2}", reader.ReadByte());
else
sb.AppendFormat("-{0:X2}", reader.ReadByte());
}
return sb.ToString();
}
public static IEnumerable<TypeDefinitionHandle> GetTopLevelTypeDefinitions(this MetadataReader reader)
{
foreach (var handle in reader.TypeDefinitions) {

6
ILSpy/Metadata/DebugTables/CustomDebugInformationTableTreeNode.cs

@ -120,7 +120,7 @@ namespace ICSharpCode.ILSpy.Metadata @@ -120,7 +120,7 @@ namespace ICSharpCode.ILSpy.Metadata
return "Edit And Continue Lambda And Closure Map (C# / VB) [" + guid + "]";
}
if (KnownGuids.EmbeddedSource == guid) {
return "State Machine Hoisted Local Scopes (C# / VB) [" + guid + "]";
return "Embedded Source (C# / VB) [" + guid + "]";
}
if (KnownGuids.SourceLink == guid) {
return "Source Link (C# / VB) [" + guid + "]";
@ -138,7 +138,9 @@ namespace ICSharpCode.ILSpy.Metadata @@ -138,7 +138,9 @@ namespace ICSharpCode.ILSpy.Metadata
public string ValueTooltip {
get {
return null;
if (debugInfo.Value.IsNil)
return "<nil>";
return metadata.GetBlobReader(debugInfo.Value).ToHexString();
}
}

37
ILSpy/Metadata/DebugTables/StateMachineMethodTableTreeNode.cs

@ -52,10 +52,11 @@ namespace ICSharpCode.ILSpy.Metadata @@ -52,10 +52,11 @@ namespace ICSharpCode.ILSpy.Metadata
var list = new List<StateMachineMethodEntry>();
StateMachineMethodEntry scrollTargetEntry = default;
var length = metadata.GetTableRowCount(TableIndex.StateMachineMethod);
byte* ptr = metadata.MetadataPointer;
var reader = new BlobReader(metadata.MetadataPointer, metadata.MetadataLength);
reader.Offset = +metadata.GetTableMetadataOffset(TableIndex.StateMachineMethod);
for (int rid = 1; rid <= length; rid++) {
StateMachineMethodEntry entry = new StateMachineMethodEntry(module, ptr, isEmbedded, rid);
StateMachineMethodEntry entry = new StateMachineMethodEntry(module, ref reader, isEmbedded, rid);
if (scrollTarget == rid) {
scrollTargetEntry = entry;
}
@ -73,54 +74,43 @@ namespace ICSharpCode.ILSpy.Metadata @@ -73,54 +74,43 @@ namespace ICSharpCode.ILSpy.Metadata
return true;
}
readonly struct StateMachineMethod
{
public readonly MethodDefinitionHandle MoveNextMethod;
public readonly MethodDefinitionHandle KickoffMethod;
public unsafe StateMachineMethod(byte* ptr, int methodDefSize)
{
MoveNextMethod = MetadataTokens.MethodDefinitionHandle(Helpers.GetValue(ptr, methodDefSize));
KickoffMethod = MetadataTokens.MethodDefinitionHandle(Helpers.GetValue(ptr + methodDefSize, methodDefSize));
}
}
unsafe struct StateMachineMethodEntry
struct StateMachineMethodEntry
{
readonly int? offset;
readonly PEFile module;
readonly MetadataReader metadata;
readonly StateMachineMethod stateMachineMethod;
readonly MethodDefinitionHandle moveNextMethod;
readonly MethodDefinitionHandle kickoffMethod;
public int RID { get; }
public object Offset => offset == null ? "n/a" : (object)offset;
[StringFormat("X8")]
public int MoveNextMethod => MetadataTokens.GetToken(stateMachineMethod.MoveNextMethod);
public int MoveNextMethod => MetadataTokens.GetToken(moveNextMethod);
public string MoveNextMethodTooltip {
get {
ITextOutput output = new PlainTextOutput();
var context = new GenericContext(default(TypeDefinitionHandle), module);
((EntityHandle)stateMachineMethod.MoveNextMethod).WriteTo(module, output, context);
((EntityHandle)moveNextMethod).WriteTo(module, output, context);
return output.ToString();
}
}
[StringFormat("X8")]
public int KickoffMethod => MetadataTokens.GetToken(stateMachineMethod.KickoffMethod);
public int KickoffMethod => MetadataTokens.GetToken(kickoffMethod);
public string KickoffMethodTooltip {
get {
ITextOutput output = new PlainTextOutput();
var context = new GenericContext(default(TypeDefinitionHandle), module);
((EntityHandle)stateMachineMethod.KickoffMethod).WriteTo(module, output, context);
((EntityHandle)kickoffMethod).WriteTo(module, output, context);
return output.ToString();
}
}
public StateMachineMethodEntry(PEFile module, byte* ptr, bool isEmbedded, int row)
public StateMachineMethodEntry(PEFile module, ref BlobReader reader, bool isEmbedded, int row)
{
this.module = module;
this.metadata = module.Metadata;
@ -128,7 +118,10 @@ namespace ICSharpCode.ILSpy.Metadata @@ -128,7 +118,10 @@ namespace ICSharpCode.ILSpy.Metadata
int rowOffset = metadata.GetTableMetadataOffset(TableIndex.StateMachineMethod)
+ metadata.GetTableRowSize(TableIndex.StateMachineMethod) * (row - 1);
this.offset = isEmbedded ? null : (int?)rowOffset;
this.stateMachineMethod = new StateMachineMethod(ptr + rowOffset, metadata.GetTableRowCount(TableIndex.MethodDef) < ushort.MaxValue ? 2 : 4);
int methodDefSize = metadata.GetTableRowCount(TableIndex.MethodDef) < ushort.MaxValue ? 2 : 4;
this.moveNextMethod = MetadataTokens.MethodDefinitionHandle(methodDefSize == 2 ? reader.ReadInt16() : reader.ReadInt32());
this.kickoffMethod = MetadataTokens.MethodDefinitionHandle(methodDefSize == 2 ? reader.ReadInt16() : reader.ReadInt32());
}
}

Loading…
Cancel
Save