Browse Source

Migrate AsyncAwaitDecompiler and YieldReturnDecompiler to SRM.

pull/1198/head
Siegfried Pammer 8 years ago
parent
commit
592935537a
  1. 14
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 3
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  3. 20
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
  4. 82
      ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs

14
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -80,8 +80,8 @@ namespace ICSharpCode.Decompiler.CSharp
new ILInlining(), new ILInlining(),
new DetectPinnedRegions(), // must run after inlining but before non-critical control flow transforms new DetectPinnedRegions(), // must run after inlining but before non-critical control flow transforms
new InlineReturnTransform(), new InlineReturnTransform(),
//new YieldReturnDecompiler(), // must run after inlining but before loop detection new YieldReturnDecompiler(), // must run after inlining but before loop detection
//new AsyncAwaitDecompiler(), // must run after inlining but before loop detection new AsyncAwaitDecompiler(), // must run after inlining but before loop detection
new DetectCatchWhenConditionBlocks(), // must run after inlining but before loop detection new DetectCatchWhenConditionBlocks(), // must run after inlining but before loop detection
new DetectExitPoints(canIntroduceExitForReturn: false), new DetectExitPoints(canIntroduceExitForReturn: false),
new EarlyExpressionTransforms(), new EarlyExpressionTransforms(),
@ -222,8 +222,8 @@ namespace ICSharpCode.Decompiler.CSharp
return true; return true;
if (settings.AnonymousMethods && methodHandle.HasGeneratedName(metadata) && methodHandle.IsCompilerGenerated(metadata)) if (settings.AnonymousMethods && methodHandle.HasGeneratedName(metadata) && methodHandle.IsCompilerGenerated(metadata))
return true; return true;
/*if (settings.AsyncAwait && AsyncAwaitDecompiler.IsCompilerGeneratedMainMethod(module, (MethodDefinitionHandle)member)) if (settings.AsyncAwait && AsyncAwaitDecompiler.IsCompilerGeneratedMainMethod(module, (MethodDefinitionHandle)member))
return true;*/ return true;
return false; return false;
case HandleKind.TypeDefinition: case HandleKind.TypeDefinition:
var typeHandle = (TypeDefinitionHandle)member; var typeHandle = (TypeDefinitionHandle)member;
@ -232,10 +232,10 @@ namespace ICSharpCode.Decompiler.CSharp
if (!type.GetDeclaringType().IsNil) { if (!type.GetDeclaringType().IsNil) {
if (settings.AnonymousMethods && IsClosureType(type, metadata)) if (settings.AnonymousMethods && IsClosureType(type, metadata))
return true; return true;
/*if (settings.YieldReturn && YieldReturnDecompiler.IsCompilerGeneratorEnumerator(type)) if (settings.YieldReturn && YieldReturnDecompiler.IsCompilerGeneratorEnumerator(typeHandle, metadata))
return true;
if (settings.AsyncAwait && AsyncAwaitDecompiler.IsCompilerGeneratedStateMachine(typeHandle, metadata))
return true; return true;
if (settings.AsyncAwait && AsyncAwaitDecompiler.IsCompilerGeneratedStateMachine(type))
return true;*/
if (settings.FixedBuffers && name.StartsWith("<", StringComparison.Ordinal) && name.Contains("__FixedBuffer")) if (settings.FixedBuffers && name.StartsWith("<", StringComparison.Ordinal) && name.Contains("__FixedBuffer"))
return true; return true;
} else if (type.IsCompilerGenerated(metadata)) { } else if (type.IsCompilerGenerated(metadata)) {

3
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -282,6 +282,9 @@
<Compile Include="Documentation\XmlDocKeyProvider.cs" /> <Compile Include="Documentation\XmlDocKeyProvider.cs" />
<Compile Include="Documentation\XmlDocLoader.cs" /> <Compile Include="Documentation\XmlDocLoader.cs" />
<Compile Include="Documentation\XmlDocumentationProvider.cs" /> <Compile Include="Documentation\XmlDocumentationProvider.cs" />
<Compile Include="IL\ControlFlow\AsyncAwaitDecompiler.cs" />
<Compile Include="IL\ControlFlow\AwaitInCatchTransform.cs" />
<Compile Include="IL\ControlFlow\YieldReturnDecompiler.cs" />
<Compile Include="Metadata\Dom.cs" /> <Compile Include="Metadata\Dom.cs" />
<Compile Include="Metadata\MetadataResolver.cs" /> <Compile Include="Metadata\MetadataResolver.cs" />
<Compile Include="Metadata\DotNetCorePathFinder.cs" /> <Compile Include="Metadata\DotNetCorePathFinder.cs" />

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

@ -24,6 +24,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection.Metadata;
namespace ICSharpCode.Decompiler.IL.ControlFlow namespace ICSharpCode.Decompiler.IL.ControlFlow
{ {
@ -32,19 +33,20 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
/// </summary> /// </summary>
class AsyncAwaitDecompiler : IILTransform class AsyncAwaitDecompiler : IILTransform
{ {
public static bool IsCompilerGeneratedStateMachine(Mono.Cecil.TypeDefinition type) public static bool IsCompilerGeneratedStateMachine(TypeDefinitionHandle type, MetadataReader metadata)
{ {
if (!(type.DeclaringType != null && type.IsCompilerGenerated())) TypeDefinition td;
if (type.IsNil || !type.IsCompilerGenerated(metadata) || (td = metadata.GetTypeDefinition(type)).GetDeclaringType().IsNil)
return false; return false;
foreach (var i in type.Interfaces) { foreach (var i in td.GetInterfaceImplementations()) {
var iface = i.InterfaceType; var tr = metadata.GetInterfaceImplementation(i).Interface.GetFullTypeName(metadata);
if (iface.Namespace == "System.Runtime.CompilerServices" && iface.Name == "IAsyncStateMachine") if (!tr.IsNested && tr.TopLevelTypeName.Namespace == "System.Runtime.CompilerServices" && tr.TopLevelTypeName.Name == "IAsyncStateMachine")
return true; return true;
} }
return false; return false;
} }
public static bool IsCompilerGeneratedMainMethod(Metadata.PEFile module, System.Reflection.Metadata.MethodDefinitionHandle method) public static bool IsCompilerGeneratedMainMethod(Metadata.PEFile module, MethodDefinitionHandle method)
{ {
var metadata = module.GetMetadataReader(); var metadata = module.GetMetadataReader();
var definition = metadata.GetMethodDefinition(method); var definition = metadata.GetMethodDefinition(method);
@ -60,6 +62,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} }
ILTransformContext context; ILTransformContext context;
MetadataReader metadata;
// These fields are set by MatchTaskCreationPattern() // These fields are set by MatchTaskCreationPattern()
IType taskType; // return type of the async method IType taskType; // return type of the async method
@ -95,6 +98,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if (!context.Settings.AsyncAwait) if (!context.Settings.AsyncAwait)
return; // abort if async/await decompilation is disabled return; // abort if async/await decompilation is disabled
this.context = context; this.context = context;
this.metadata = context.TypeSystem.GetMetadata();
fieldToParameterMap.Clear(); fieldToParameterMap.Clear();
cachedFieldToParameterMap.Clear(); cachedFieldToParameterMap.Clear();
awaitBlocks.Clear(); awaitBlocks.Clear();
@ -328,7 +332,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
/// </summary> /// </summary>
void AnalyzeMoveNext() void AnalyzeMoveNext()
{ {
var moveNextMethod = context.TypeSystem.GetCecil(stateMachineType)?.Methods.FirstOrDefault(f => f.Name == "MoveNext"); if (stateMachineType.MetadataToken.IsNil)
throw new SymbolicAnalysisFailedException();
var moveNextMethod = metadata.GetTypeDefinition((TypeDefinitionHandle)stateMachineType.MetadataToken).GetMethods().FirstOrDefault(f => metadata.GetString(metadata.GetMethodDefinition(f).Name)== "MoveNext");
if (moveNextMethod == null) if (moveNextMethod == null)
throw new SymbolicAnalysisFailedException(); throw new SymbolicAnalysisFailedException();
moveNextFunction = YieldReturnDecompiler.CreateILAst(moveNextMethod, context); moveNextFunction = YieldReturnDecompiler.CreateILAst(moveNextMethod, context);

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

@ -20,11 +20,11 @@ using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
using Mono.Cecil;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection.Metadata;
namespace ICSharpCode.Decompiler.IL.ControlFlow namespace ICSharpCode.Decompiler.IL.ControlFlow
{ {
@ -42,24 +42,25 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// for a description of this step. // for a description of this step.
ILTransformContext context; ILTransformContext context;
MetadataReader metadata;
/// <summary>The type that contains the function being decompiled.</summary> /// <summary>The type that contains the function being decompiled.</summary>
TypeDefinition currentType; TypeDefinitionHandle currentType;
/// <summary>The compiler-generated enumerator class.</summary> /// <summary>The compiler-generated enumerator class.</summary>
/// <remarks>Set in MatchEnumeratorCreationPattern()</remarks> /// <remarks>Set in MatchEnumeratorCreationPattern()</remarks>
TypeDefinition enumeratorType; TypeDefinitionHandle enumeratorType;
/// <summary>The constructor of the compiler-generated enumerator class.</summary> /// <summary>The constructor of the compiler-generated enumerator class.</summary>
/// <remarks>Set in MatchEnumeratorCreationPattern()</remarks> /// <remarks>Set in MatchEnumeratorCreationPattern()</remarks>
MethodDefinition enumeratorCtor; MethodDefinitionHandle enumeratorCtor;
/// <remarks>Set in MatchEnumeratorCreationPattern()</remarks> /// <remarks>Set in MatchEnumeratorCreationPattern()</remarks>
bool isCompiledWithMono; bool isCompiledWithMono;
/// <summary>The dispose method of the compiler-generated enumerator class.</summary> /// <summary>The dispose method of the compiler-generated enumerator class.</summary>
/// <remarks>Set in ConstructExceptionTable()</remarks> /// <remarks>Set in ConstructExceptionTable()</remarks>
MethodDefinition disposeMethod; MethodDefinitionHandle disposeMethod;
/// <summary>The field in the compiler-generated class holding the current state of the state machine</summary> /// <summary>The field in the compiler-generated class holding the current state of the state machine</summary>
/// <remarks>Set in AnalyzeCtor() for MS, MatchEnumeratorCreationPattern() or AnalyzeMoveNext() for Mono</remarks> /// <remarks>Set in AnalyzeCtor() for MS, MatchEnumeratorCreationPattern() or AnalyzeMoveNext() for Mono</remarks>
@ -105,9 +106,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if (!context.Settings.YieldReturn) if (!context.Settings.YieldReturn)
return; // abort if enumerator decompilation is disabled return; // abort if enumerator decompilation is disabled
this.context = context; this.context = context;
this.currentType = function.CecilMethod.DeclaringType; this.metadata = context.TypeSystem.GetMetadata();
this.enumeratorType = null; this.currentType = metadata.GetMethodDefinition((MethodDefinitionHandle)context.Function.Method.MetadataToken).GetDeclaringType();
this.enumeratorCtor = null; this.enumeratorType = default;
this.enumeratorCtor = default;
this.stateField = null; this.stateField = null;
this.currentField = null; this.currentField = null;
this.fieldToParameterMap.Clear(); this.fieldToParameterMap.Clear();
@ -303,10 +305,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return false; return false;
if (!(initialState == -2 || initialState == 0)) if (!(initialState == -2 || initialState == 0))
return false; return false;
enumeratorCtor = context.TypeSystem.GetCecil(newObj.Method) as MethodDefinition; enumeratorCtor = (MethodDefinitionHandle)newObj.Method.MetadataToken;
enumeratorType = enumeratorCtor?.DeclaringType; enumeratorType = enumeratorCtor.IsNil ? default : metadata.GetMethodDefinition(enumeratorCtor).GetDeclaringType();
return enumeratorType?.DeclaringType == currentType return (enumeratorType.IsNil ? default : metadata.GetTypeDefinition(enumeratorType).GetDeclaringType()) == currentType
&& IsCompilerGeneratorEnumerator(enumeratorType); && IsCompilerGeneratorEnumerator(enumeratorType, metadata);
} }
bool MatchMonoEnumeratorCreationNewObj(ILInstruction inst) bool MatchMonoEnumeratorCreationNewObj(ILInstruction inst)
@ -316,19 +318,20 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return false; return false;
if (newObj.Arguments.Count != 0) if (newObj.Arguments.Count != 0)
return false; return false;
enumeratorCtor = context.TypeSystem.GetCecil(newObj.Method) as MethodDefinition; enumeratorCtor = (MethodDefinitionHandle)newObj.Method.MetadataToken;
enumeratorType = enumeratorCtor?.DeclaringType; enumeratorType = enumeratorCtor.IsNil ? default : metadata.GetMethodDefinition(enumeratorCtor).GetDeclaringType();
return enumeratorType?.DeclaringType == currentType return (enumeratorType.IsNil ? default : metadata.GetTypeDefinition(enumeratorType).GetDeclaringType()) == currentType
&& IsCompilerGeneratorEnumerator(enumeratorType); && IsCompilerGeneratorEnumerator(enumeratorType, metadata);
} }
public static bool IsCompilerGeneratorEnumerator(TypeDefinition type) public static bool IsCompilerGeneratorEnumerator(TypeDefinitionHandle type, MetadataReader metadata)
{ {
if (!(type?.DeclaringType != null && type.IsCompilerGenerated())) TypeDefinition td;
if (type.IsNil || !type.IsCompilerGenerated(metadata) || (td = metadata.GetTypeDefinition(type)).GetDeclaringType().IsNil)
return false; return false;
foreach (var i in type.Interfaces) { foreach (var i in td.GetInterfaceImplementations()) {
var tr = i.InterfaceType; var tr = metadata.GetInterfaceImplementation(i).Interface.GetFullTypeName(metadata);
if (tr.Namespace == "System.Collections" && tr.Name == "IEnumerator") if (!tr.IsNested && tr.TopLevelTypeName.Namespace == "System.Collections" && tr.TopLevelTypeName.Name == "IEnumerator")
return true; return true;
} }
return false; return false;
@ -359,12 +362,15 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
/// <summary> /// <summary>
/// Creates ILAst for the specified method, optimized up to before the 'YieldReturn' step. /// Creates ILAst for the specified method, optimized up to before the 'YieldReturn' step.
/// </summary> /// </summary>
internal static ILFunction CreateILAst(MethodDefinition method, ILTransformContext context) internal static ILFunction CreateILAst(MethodDefinitionHandle method, ILTransformContext context)
{ {
if (method == null || !method.HasBody) var typeSystem = context.TypeSystem;
var metadata = typeSystem.GetMetadata();
if (method.IsNil || !method.HasBody(metadata))
throw new SymbolicAnalysisFailedException(); throw new SymbolicAnalysisFailedException();
var typeSystem = context.TypeSystem; var methodDef = metadata.GetMethodDefinition(method);
var sdtp = typeSystem as SpecializingDecompilerTypeSystem; var sdtp = typeSystem as SpecializingDecompilerTypeSystem;
if (sdtp != null) { if (sdtp != null) {
typeSystem = new SpecializingDecompilerTypeSystem( typeSystem = new SpecializingDecompilerTypeSystem(
@ -376,7 +382,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
) )
); );
} }
var il = new ILReader(typeSystem).ReadIL(method.Body, context.CancellationToken); var il = new ILReader(typeSystem).ReadIL(typeSystem.ModuleDefinition, method, typeSystem.ModuleDefinition.Reader.GetMethodBody(methodDef.RelativeVirtualAddress), context.CancellationToken);
il.RunTransforms(CSharpDecompiler.EarlyILTransforms(true), il.RunTransforms(CSharpDecompiler.EarlyILTransforms(true),
new ILTransformContext(il, typeSystem, context.Settings) { new ILTransformContext(il, typeSystem, context.Settings) {
CancellationToken = context.CancellationToken, CancellationToken = context.CancellationToken,
@ -392,9 +398,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
/// </summary> /// </summary>
void AnalyzeCurrentProperty() void AnalyzeCurrentProperty()
{ {
MethodDefinition getCurrentMethod = enumeratorType.Methods.FirstOrDefault( MethodDefinitionHandle getCurrentMethod = metadata.GetTypeDefinition(enumeratorType).GetMethods().FirstOrDefault(
m => m.Name.StartsWith("System.Collections.Generic.IEnumerator", StringComparison.Ordinal) m => metadata.GetString(metadata.GetMethodDefinition(m).Name).StartsWith("System.Collections.Generic.IEnumerator", StringComparison.Ordinal)
&& m.Name.EndsWith(".get_Current", StringComparison.Ordinal)); && metadata.GetString(metadata.GetMethodDefinition(m).Name).EndsWith(".get_Current", StringComparison.Ordinal));
Block body = SingleBlock(CreateILAst(getCurrentMethod, context).Body); Block body = SingleBlock(CreateILAst(getCurrentMethod, context).Body);
if (body == null) if (body == null)
throw new SymbolicAnalysisFailedException(); throw new SymbolicAnalysisFailedException();
@ -426,10 +432,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
#region Figure out the mapping of IEnumerable fields to IEnumerator fields (analysis of GetEnumerator()) #region Figure out the mapping of IEnumerable fields to IEnumerator fields (analysis of GetEnumerator())
void ResolveIEnumerableIEnumeratorFieldMapping() void ResolveIEnumerableIEnumeratorFieldMapping()
{ {
MethodDefinition getEnumeratorMethod = enumeratorType.Methods.FirstOrDefault( MethodDefinitionHandle getEnumeratorMethod = metadata.GetTypeDefinition(enumeratorType).GetMethods().FirstOrDefault(
m => m.Name.StartsWith("System.Collections.Generic.IEnumerable", StringComparison.Ordinal) m => metadata.GetString(metadata.GetMethodDefinition(m).Name).StartsWith("System.Collections.Generic.IEnumerable", StringComparison.Ordinal)
&& m.Name.EndsWith(".GetEnumerator", StringComparison.Ordinal)); && metadata.GetString(metadata.GetMethodDefinition(m).Name).EndsWith(".GetEnumerator", StringComparison.Ordinal));
if (getEnumeratorMethod == null) if (getEnumeratorMethod.IsNil)
return; // no mappings (maybe it's just an IEnumerator implementation?) return; // no mappings (maybe it's just an IEnumerator implementation?)
var function = CreateILAst(getEnumeratorMethod, context); var function = CreateILAst(getEnumeratorMethod, context);
foreach (var block in function.Descendants.OfType<Block>()) { foreach (var block in function.Descendants.OfType<Block>()) {
@ -455,12 +461,12 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
{ {
if (isCompiledWithMono) { if (isCompiledWithMono) {
// On mono, we don't need to analyse Dispose() to reconstruct the try-finally structure. // On mono, we don't need to analyse Dispose() to reconstruct the try-finally structure.
disposeMethod = null; disposeMethod = default;
finallyMethodToStateRange = null; finallyMethodToStateRange = default;
return; return;
} }
disposeMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "System.IDisposable.Dispose"); disposeMethod = metadata.GetTypeDefinition(enumeratorType).GetMethods().FirstOrDefault(m => metadata.GetString(metadata.GetMethodDefinition(m).Name) == "System.IDisposable.Dispose");
var function = CreateILAst(disposeMethod, context); var function = CreateILAst(disposeMethod, context);
var rangeAnalysis = new StateRangeAnalysis(StateRangeAnalysisMode.IteratorDispose, stateField); var rangeAnalysis = new StateRangeAnalysis(StateRangeAnalysisMode.IteratorDispose, stateField);
@ -485,7 +491,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
BlockContainer AnalyzeMoveNext() BlockContainer AnalyzeMoveNext()
{ {
context.StepStartGroup("AnalyzeMoveNext"); context.StepStartGroup("AnalyzeMoveNext");
MethodDefinition moveNextMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "MoveNext"); MethodDefinitionHandle moveNextMethod = metadata.GetTypeDefinition(enumeratorType).GetMethods().FirstOrDefault(m => metadata.GetString(metadata.GetMethodDefinition(m).Name) == "MoveNext");
ILFunction moveNextFunction = CreateILAst(moveNextMethod, context); ILFunction moveNextFunction = CreateILAst(moveNextMethod, context);
// Copy-propagate temporaries holding a copy of 'this'. // Copy-propagate temporaries holding a copy of 'this'.
@ -503,7 +509,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
var faultBlock = faultBlockContainer.Blocks.Single(); var faultBlock = faultBlockContainer.Blocks.Single();
if (!(faultBlock.Instructions.Count == 2 if (!(faultBlock.Instructions.Count == 2
&& faultBlock.Instructions[0] is Call call && faultBlock.Instructions[0] is Call call
&& context.TypeSystem.GetCecil(call.Method) == disposeMethod && call.Method.MetadataToken == disposeMethod
&& call.Arguments.Count == 1 && call.Arguments.Count == 1
&& call.Arguments[0].MatchLdThis() && call.Arguments[0].MatchLdThis()
&& faultBlock.Instructions[1].MatchLeave(faultBlockContainer))) { && faultBlock.Instructions[1].MatchLeave(faultBlockContainer))) {
@ -823,7 +829,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
void DecompileFinallyBlocks() void DecompileFinallyBlocks()
{ {
foreach (var method in finallyMethodToStateRange.Keys) { foreach (var method in finallyMethodToStateRange.Keys) {
var function = CreateILAst((MethodDefinition)context.TypeSystem.GetCecil(method), context); var function = CreateILAst((MethodDefinitionHandle)method.MetadataToken, context);
var body = (BlockContainer)function.Body; var body = (BlockContainer)function.Body;
var newState = GetNewState(body.EntryPoint); var newState = GetNewState(body.EntryPoint);
if (newState != null) { if (newState != null) {

Loading…
Cancel
Save