Browse Source

[async] small improvements to await decompilation

pull/850/head
Daniel Grunwald 8 years ago
parent
commit
123a7f4a62
  1. 18
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 17
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
  3. 3
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  4. 4
      ILSpy/Languages/CSharpLanguage.cs

18
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1732,7 +1732,23 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitAwait(Await inst, TranslationContext context) protected internal override TranslatedExpression VisitAwait(Await inst, TranslationContext context)
{ {
var value = Translate(inst.Value); IType expectedType = null;
if (inst.GetAwaiterMethod != null) {
if (inst.GetAwaiterMethod.IsStatic) {
expectedType = inst.GetAwaiterMethod.Parameters.FirstOrDefault()?.Type;
} else {
expectedType = inst.GetAwaiterMethod.DeclaringType;
}
}
var value = Translate(inst.Value, typeHint: expectedType);
if (value.Expression is DirectionExpression) {
// we can deference the managed reference by stripping away the 'ref'
value = value.UnwrapChild(((DirectionExpression)value.Expression).Expression);
}
if (expectedType != null) {
value = value.ConvertTo(expectedType, this, allowImplicitConversion: true);
}
return new UnaryOperatorExpression(UnaryOperatorType.Await, value.Expression) return new UnaryOperatorExpression(UnaryOperatorType.Await, value.Expression)
.WithILInstruction(inst) .WithILInstruction(inst)
.WithRR(new ResolveResult(inst?.GetResultMethod.ReturnType ?? SpecialType.UnknownType)); .WithRR(new ResolveResult(inst?.GetResultMethod.ReturnType ?? SpecialType.UnknownType));

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

@ -58,6 +58,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
ILVariable doFinallyBodies; ILVariable doFinallyBodies;
// These fields are set by AnalyzeStateMachine(): // These fields are set by AnalyzeStateMachine():
int smallestAwaiterVarIndex;
// For each block containing an 'await', stores the awaiter variable, and the field storing the awaiter // For each block containing an 'await', stores the awaiter variable, and the field storing the awaiter
// across the yield point. // across the yield point.
@ -90,6 +91,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
DetectAwaitPattern(function); DetectAwaitPattern(function);
context.Step("Translate fields to local accesses", function); context.Step("Translate fields to local accesses", function);
MarkGeneratedVariables(function);
YieldReturnDecompiler.TranslateFieldsToLocalAccess(function, function, fieldToParameterMap); YieldReturnDecompiler.TranslateFieldsToLocalAccess(function, function, fieldToParameterMap);
FinalizeInlineMoveNext(function); FinalizeInlineMoveNext(function);
@ -444,6 +446,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
void AnalyzeStateMachine(ILFunction function) void AnalyzeStateMachine(ILFunction function)
{ {
context.Step("AnalyzeStateMachine()", function); context.Step("AnalyzeStateMachine()", function);
smallestAwaiterVarIndex = int.MaxValue;
foreach (var container in function.Descendants.OfType<BlockContainer>()) { foreach (var container in function.Descendants.OfType<BlockContainer>()) {
// Use a separate state range analysis per container. // Use a separate state range analysis per container.
var sra = new StateRangeAnalysis(StateRangeAnalysisMode.AsyncMoveNext, stateField, cachedStateVar); var sra = new StateRangeAnalysis(StateRangeAnalysisMode.AsyncMoveNext, stateField, cachedStateVar);
@ -464,6 +467,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
block.Instructions.Add(new InvalidBranch("Could not find block for state " + state)); block.Instructions.Add(new InvalidBranch("Could not find block for state " + state));
} }
awaitBlocks.Add(block, (awaiterVar, awaiterField)); awaitBlocks.Add(block, (awaiterVar, awaiterField));
if (awaiterVar.Index < smallestAwaiterVarIndex) {
smallestAwaiterVarIndex = awaiterVar.Index;
}
} }
} }
} }
@ -731,5 +737,16 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return block.Instructions[pos].MatchBranch(completedBlock); return block.Instructions[pos].MatchBranch(completedBlock);
} }
#endregion #endregion
void MarkGeneratedVariables(ILFunction function)
{
// Variables after the awaiters are usually compiler-generated;
// so mark them as stack slots.
foreach (var v in function.Variables) {
if (v.Kind == VariableKind.Local && v.Index >= smallestAwaiterVarIndex) {
v.Kind = VariableKind.StackSlot;
}
}
}
} }
} }

3
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -240,8 +240,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
case OpCode.CallVirt: case OpCode.CallVirt:
return !((CallVirt)parent).Method.IsStatic; return !((CallVirt)parent).Method.IsStatic;
case OpCode.LdFlda: case OpCode.LdFlda:
// TODO : Reimplement Await case OpCode.Await:
//case OpCode.Await:
return true; return true;
} }
} }

4
ILSpy/Languages/CSharpLanguage.cs

@ -35,7 +35,9 @@ using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
/// <summary> /// <summary>
/// Decompiler logic for C#. /// C# decompiler integration into ILSpy.
/// Note: if you're interested in using the decompiler without the ILSpy UI,
/// please directly use the CSharpDecompiler class.
/// </summary> /// </summary>
[Export(typeof(Language))] [Export(typeof(Language))]
public class CSharpLanguage : Language public class CSharpLanguage : Language

Loading…
Cancel
Save