Browse Source

Move DelegateConstruction transform to ILAst

pull/734/head
Siegfried Pammer 9 years ago
parent
commit
81e8df3f96
  1. 61
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 113
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 6
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  4. 2
      ICSharpCode.Decompiler/CSharp/Transforms/DelegateConstruction.cs
  5. 3
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  6. 19
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  7. 181
      ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs
  8. 95
      ICSharpCode.Decompiler/IL/Transforms/RemoveCachedDelegateInitialization.cs
  9. 18
      ICSharpCode.Decompiler/NRExtensions.cs

61
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -46,7 +46,11 @@ namespace ICSharpCode.Decompiler.CSharp
readonly DecompilerTypeSystem typeSystem; readonly DecompilerTypeSystem typeSystem;
readonly DecompilerSettings settings; readonly DecompilerSettings settings;
List<IILTransform> ilTransforms = new List<IILTransform> { List<IILTransform> ilTransforms = GetILTransforms();
public static List<IILTransform> GetILTransforms()
{
return new List<IILTransform> {
new SplitVariables(), new SplitVariables(),
new ControlFlowSimplification(), new ControlFlowSimplification(),
new ILInlining(), new ILInlining(),
@ -59,17 +63,17 @@ namespace ICSharpCode.Decompiler.CSharp
new InlineCompilerGeneratedVariables(), new InlineCompilerGeneratedVariables(),
new ExpressionTransforms(), // must run once before "the loop" to allow RemoveDeadVariablesInit new ExpressionTransforms(), // must run once before "the loop" to allow RemoveDeadVariablesInit
new RemoveDeadVariableInit(), // must run after ExpressionTransforms because it does not handle stobj(ldloca V, ...) new RemoveDeadVariableInit(), // must run after ExpressionTransforms because it does not handle stobj(ldloca V, ...)
new RemoveCachedDelegateInitialization(), new DelegateConstruction(),
new LoopingTransform( new LoopingTransform(
new ExpressionTransforms(), new ExpressionTransforms(),
new TransformArrayInitializers(), new TransformArrayInitializers(),
new ILInlining() new ILInlining()
) )
}; };
}
List<IAstTransform> astTransforms = new List<IAstTransform> { List<IAstTransform> astTransforms = new List<IAstTransform> {
//new PushNegation(), //new PushNegation(),
new DelegateConstruction(),
new PatternStatementTransform(), new PatternStatementTransform(),
new ReplaceMethodCallsWithOperators(), new ReplaceMethodCallsWithOperators(),
new IntroduceUnsafeModifier(), new IntroduceUnsafeModifier(),
@ -605,29 +609,10 @@ namespace ICSharpCode.Decompiler.CSharp
return methodDecl; return methodDecl;
} }
IDecompilerTypeSystem GetSpecializingTypeSystem(ITypeResolveContext decompilationContext) void DecompileBody(MethodDefinition methodDefinition, IMethod method, EntityDeclaration entityDecl, ITypeResolveContext decompilationContext)
{
IList<IType> classTypeParameters = null;
IList<IType> methodTypeParameters = null;
if (decompilationContext.CurrentTypeDefinition != null)
classTypeParameters = decompilationContext.CurrentTypeDefinition.TypeArguments;
IMethod method = decompilationContext.CurrentMember as IMethod;
if (method != null)
methodTypeParameters = method.TypeArguments;
if ((classTypeParameters != null && classTypeParameters.Count > 0) || (methodTypeParameters != null && methodTypeParameters.Count > 0))
return new SpecializingDecompilerTypeSystem(typeSystem, new TypeParameterSubstitution(classTypeParameters, methodTypeParameters));
else
return typeSystem;
}
BlockStatement DecompileBodyInternal(MethodDefinition methodDefinition, IMethod method, EntityDeclaration entityDecl, ITypeResolveContext decompilationContext, string variablesPrefix = null)
{ {
var specializingTypeSystem = GetSpecializingTypeSystem(decompilationContext); var specializingTypeSystem = typeSystem.GetSpecializingTypeSystem(decompilationContext);
var ilReader = new ILReader(specializingTypeSystem); ILFunction function = ILFunction.Read(specializingTypeSystem, methodDefinition, CancellationToken);
var function = ilReader.ReadIL(methodDefinition.Body, CancellationToken);
function.CheckInvariant(ILPhase.Normal);
if (entityDecl != null) { if (entityDecl != null) {
int i = 0; int i = 0;
@ -640,13 +625,6 @@ namespace ICSharpCode.Decompiler.CSharp
} }
} }
if (!string.IsNullOrWhiteSpace(variablesPrefix)) {
var variables = function.Variables.Where(v => v.Kind != VariableKind.Parameter);
foreach (var v in variables) {
v.Name = variablesPrefix + v.Name;
}
}
var context = new ILTransformContext { TypeSystem = specializingTypeSystem, CancellationToken = CancellationToken }; var context = new ILTransformContext { TypeSystem = specializingTypeSystem, CancellationToken = CancellationToken };
foreach (var transform in ilTransforms) { foreach (var transform in ilTransforms) {
CancellationToken.ThrowIfCancellationRequested(); CancellationToken.ThrowIfCancellationRequested();
@ -654,23 +632,8 @@ namespace ICSharpCode.Decompiler.CSharp
function.CheckInvariant(ILPhase.Normal); function.CheckInvariant(ILPhase.Normal);
} }
var statementBuilder = new StatementBuilder(decompilationContext, method); var statementBuilder = new StatementBuilder(specializingTypeSystem, decompilationContext, method);
var body = statementBuilder.ConvertAsBlock(function.Body); entityDecl.AddChild(statementBuilder.ConvertAsBlock(function.Body), Roles.Body);
body.AddAnnotation(function.Variables);
return body;
}
internal BlockStatement DecompileLambdaBody(IMethod method)
{
MethodDefinition definition = typeSystem.GetCecil(method) as MethodDefinition;
if (definition == null)
throw new InvalidOperationException("Could not find method in type system");
return DecompileBodyInternal(definition, method, null, new SimpleTypeResolveContext(method), method.Name + "_");
}
void DecompileBody(MethodDefinition methodDefinition, IMethod method, EntityDeclaration entityDecl, ITypeResolveContext decompilationContext)
{
entityDecl.AddChild(DecompileBodyInternal(methodDefinition, method, entityDecl, decompilationContext), Roles.Body);
} }
EntityDeclaration DoDecompile(FieldDefinition fieldDefinition, IField field, ITypeResolveContext decompilationContext) EntityDeclaration DoDecompile(FieldDefinition fieldDefinition, IField field, ITypeResolveContext decompilationContext)

113
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -60,13 +60,17 @@ namespace ICSharpCode.Decompiler.CSharp
/// </remarks> /// </remarks>
class ExpressionBuilder : ILVisitor<TranslatedExpression> class ExpressionBuilder : ILVisitor<TranslatedExpression>
{ {
readonly IDecompilerTypeSystem typeSystem;
readonly ITypeResolveContext decompilationContext;
internal readonly ICompilation compilation; internal readonly ICompilation compilation;
internal readonly CSharpResolver resolver; internal readonly CSharpResolver resolver;
readonly TypeSystemAstBuilder astBuilder; readonly TypeSystemAstBuilder astBuilder;
public ExpressionBuilder(ITypeResolveContext decompilationContext) public ExpressionBuilder(IDecompilerTypeSystem typeSystem, ITypeResolveContext decompilationContext)
{ {
Debug.Assert(decompilationContext != null); Debug.Assert(decompilationContext != null);
this.typeSystem = typeSystem;
this.decompilationContext = decompilationContext;
this.compilation = decompilationContext.Compilation; this.compilation = decompilationContext.Compilation;
this.resolver = new CSharpResolver(new CSharpTypeResolveContext(compilation.MainAssembly, null, decompilationContext.CurrentTypeDefinition, decompilationContext.CurrentMember)); this.resolver = new CSharpResolver(new CSharpTypeResolveContext(compilation.MainAssembly, null, decompilationContext.CurrentTypeDefinition, decompilationContext.CurrentMember));
this.astBuilder = new TypeSystemAstBuilder(resolver); this.astBuilder = new TypeSystemAstBuilder(resolver);
@ -730,22 +734,20 @@ namespace ICSharpCode.Decompiler.CSharp
return HandleCallInstruction(inst); return HandleCallInstruction(inst);
} }
internal static bool IsDelegateConstruction(CallInstruction inst)
{
return inst.Arguments.Count == 2
&& (inst.Arguments[1].OpCode == OpCode.LdFtn
|| inst.Arguments[1].OpCode == OpCode.LdVirtFtn)
&& inst.Method.DeclaringType.Kind == TypeKind.Delegate;
}
TranslatedExpression HandleDelegateConstruction(CallInstruction inst) TranslatedExpression HandleDelegateConstruction(CallInstruction inst)
{ {
ILInstruction func = inst.Arguments[1]; ILInstruction func = inst.Arguments[1];
IMethod method; IMethod method;
if (func.OpCode == OpCode.LdFtn) { switch (func.OpCode) {
case OpCode.LdFtn:
method = ((LdFtn)func).Method; method = ((LdFtn)func).Method;
} else { break;
case OpCode.LdVirtFtn:
method = ((LdVirtFtn)func).Method; method = ((LdVirtFtn)func).Method;
break;
default:
method = (IMethod)typeSystem.Resolve(((ILFunction)func).Method);
break;
} }
var target = TranslateTarget(method, inst.Arguments[0], func.OpCode == OpCode.LdFtn); var target = TranslateTarget(method, inst.Arguments[0], func.OpCode == OpCode.LdFtn);
@ -763,14 +765,97 @@ namespace ICSharpCode.Decompiler.CSharp
var mre = new MemberReferenceExpression(target, method.Name); var mre = new MemberReferenceExpression(target, method.Name);
mre.TypeArguments.AddRange(method.TypeArguments.Select(a => ConvertType(a))); mre.TypeArguments.AddRange(method.TypeArguments.Select(a => ConvertType(a)));
return new ObjectCreateExpression(ConvertType(inst.Method.DeclaringType), mre) var oce = new ObjectCreateExpression(ConvertType(inst.Method.DeclaringType), mre)
.WithAnnotation(new DelegateConstruction.Annotation(func.OpCode == OpCode.LdVirtFtn, target, method.Name)) // .WithAnnotation(new DelegateConstruction.Annotation(func.OpCode == OpCode.LdVirtFtn, target, method.Name))
.WithILInstruction(inst) .WithILInstruction(inst)
.WithRR(new ConversionResolveResult( .WithRR(new ConversionResolveResult(
inst.Method.DeclaringType, inst.Method.DeclaringType,
new MemberResolveResult(target.ResolveResult, method), new MemberResolveResult(target.ResolveResult, method),
// TODO handle extension methods capturing the first argument // TODO handle extension methods capturing the first argument
Conversion.MethodGroupConversion(method, func.OpCode == OpCode.LdVirtFtn, false))); Conversion.MethodGroupConversion(method, func.OpCode == OpCode.LdVirtFtn, false)));
if (func is ILFunction) {
return TranslateFunction(oce, target, (ILFunction)func);
} else {
return oce;
}
}
TranslatedExpression TranslateFunction(TranslatedExpression objectCreateExpression, TranslatedExpression target, ILFunction function)
{
var method = typeSystem.Resolve(function.Method) as IMethod;
Debug.Assert(method != null);
// Create AnonymousMethodExpression and prepare parameters
AnonymousMethodExpression ame = new AnonymousMethodExpression();
ame.Parameters.AddRange(MakeParameters(method, function));
ame.HasParameterList = true;
StatementBuilder builder = new StatementBuilder(typeSystem, decompilationContext, method);
var body = builder.ConvertAsBlock(function.Body);
bool isLambda = false;
if (ame.Parameters.All(p => p.ParameterModifier == ParameterModifier.None)) {
isLambda = (body.Statements.Count == 1 && body.Statements.Single() is ReturnStatement);
}
// Remove the parameter list from an AnonymousMethodExpression if the original method had no names,
// and the parameters are not used in the method body
if (!isLambda && method.Parameters.All(p => string.IsNullOrEmpty(p.Name))) {
var parameterReferencingIdentifiers =
from ident in body.Descendants.OfType<IdentifierExpression>()
let v = ident.Annotation<ILVariable>()
where v != null && v.Kind == VariableKind.Parameter
select ident;
if (!parameterReferencingIdentifiers.Any()) {
ame.Parameters.Clear();
ame.HasParameterList = false;
}
}
// Replace all occurrences of 'this' in the method body with the delegate's target:
foreach (AstNode node in body.Descendants) {
if (node is ThisReferenceExpression)
node.ReplaceWith(target.Expression.Clone());
}
Expression replacement;
if (isLambda) {
LambdaExpression lambda = new LambdaExpression();
lambda.CopyAnnotationsFrom(ame);
ame.Parameters.MoveTo(lambda.Parameters);
Expression returnExpr = ((ReturnStatement)body.Statements.Single()).Expression;
returnExpr.Remove();
lambda.Body = returnExpr;
replacement = lambda;
} else {
ame.Body = body;
replacement = ame;
}
var expectedType = objectCreateExpression.ResolveResult.Type.GetDefinition();
if (expectedType != null && expectedType.Kind != TypeKind.Delegate) {
var simplifiedDelegateCreation = (ObjectCreateExpression)objectCreateExpression.Expression.Clone();
simplifiedDelegateCreation.Arguments.Clear();
simplifiedDelegateCreation.Arguments.Add(replacement);
replacement = simplifiedDelegateCreation;
}
return replacement
.WithILInstruction(function)
.WithRR(objectCreateExpression.ResolveResult);
}
IEnumerable<ParameterDeclaration> MakeParameters(IMethod method, ILFunction function)
{
var variables = function.Variables.Where(v => v.Kind == VariableKind.Parameter).ToDictionary(v => v.Index);
int i = 0;
foreach (var parameter in method.Parameters) {
var pd = astBuilder.ConvertParameter(parameter);
if (parameter.Type.ContainsAnonymousType())
pd.Type = null;
ILVariable v;
if (variables.TryGetValue(i, out v))
pd.AddAnnotation(new ILVariableResolveResult(v, method.Parameters[i].Type));
yield return pd;
i++;
}
} }
TranslatedExpression TranslateTarget(IMember member, ILInstruction target, bool nonVirtualInvocation) TranslatedExpression TranslateTarget(IMember member, ILInstruction target, bool nonVirtualInvocation)
@ -800,7 +885,7 @@ namespace ICSharpCode.Decompiler.CSharp
// Used for Call, CallVirt and NewObj // Used for Call, CallVirt and NewObj
TranslatedExpression target; TranslatedExpression target;
if (inst.OpCode == OpCode.NewObj) { if (inst.OpCode == OpCode.NewObj) {
if (IsDelegateConstruction(inst)) { if (IL.Transforms.DelegateConstruction.IsDelegateConstruction((NewObj)inst, true)) {
return HandleDelegateConstruction(inst); return HandleDelegateConstruction(inst);
} }
target = default(TranslatedExpression); // no target target = default(TranslatedExpression); // no target

6
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -33,10 +33,10 @@ namespace ICSharpCode.Decompiler.CSharp
internal readonly ExpressionBuilder exprBuilder; internal readonly ExpressionBuilder exprBuilder;
readonly IMethod currentMethod; readonly IMethod currentMethod;
public StatementBuilder(ITypeResolveContext decompilationContext, IMethod currentMethod) public StatementBuilder(IDecompilerTypeSystem typeSystem, ITypeResolveContext decompilationContext, IMethod currentMethod)
{ {
Debug.Assert(decompilationContext != null && currentMethod != null); Debug.Assert(typeSystem != null && decompilationContext != null && currentMethod != null);
this.exprBuilder = new ExpressionBuilder(decompilationContext); this.exprBuilder = new ExpressionBuilder(typeSystem, decompilationContext);
this.currentMethod = currentMethod; this.currentMethod = currentMethod;
} }

2
ICSharpCode.Decompiler/CSharp/Transforms/DelegateConstruction.cs

@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// For anonymous methods, creates an AnonymousMethodExpression. /// For anonymous methods, creates an AnonymousMethodExpression.
/// Also gets rid of any "Display Classes" left over after inlining an anonymous method. /// Also gets rid of any "Display Classes" left over after inlining an anonymous method.
/// </summary> /// </summary>
public class DelegateConstruction : ContextTrackingVisitor<object>, IAstTransform public class DelegateConstructionOld : ContextTrackingVisitor<object>, IAstTransform
{ {
internal sealed class Annotation internal sealed class Annotation
{ {

3
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -68,7 +68,6 @@
<Compile Include="CSharp\Transforms\ContextTrackingVisitor.cs" /> <Compile Include="CSharp\Transforms\ContextTrackingVisitor.cs" />
<Compile Include="CSharp\Transforms\DecimalConstantTransform.cs" /> <Compile Include="CSharp\Transforms\DecimalConstantTransform.cs" />
<Compile Include="CSharp\Transforms\DeclareVariables.cs" /> <Compile Include="CSharp\Transforms\DeclareVariables.cs" />
<Compile Include="CSharp\Transforms\DelegateConstruction.cs" />
<Compile Include="CSharp\Transforms\EscapeInvalidIdentifiers.cs" /> <Compile Include="CSharp\Transforms\EscapeInvalidIdentifiers.cs" />
<Compile Include="CSharp\Transforms\FixNameCollisions.cs" /> <Compile Include="CSharp\Transforms\FixNameCollisions.cs" />
<Compile Include="CSharp\Transforms\IntroduceUsingDeclarations.cs" /> <Compile Include="CSharp\Transforms\IntroduceUsingDeclarations.cs" />
@ -132,7 +131,7 @@
<Compile Include="IL\Transforms\ExpressionTransforms.cs" /> <Compile Include="IL\Transforms\ExpressionTransforms.cs" />
<Compile Include="IL\Transforms\InlineCompilerGeneratedVariables.cs" /> <Compile Include="IL\Transforms\InlineCompilerGeneratedVariables.cs" />
<Compile Include="IL\Transforms\LoopingTransform.cs" /> <Compile Include="IL\Transforms\LoopingTransform.cs" />
<Compile Include="IL\Transforms\RemoveCachedDelegateInitialization.cs" /> <Compile Include="IL\Transforms\DelegateConstruction.cs" />
<Compile Include="IL\Transforms\RemoveDeadVariableInit.cs" /> <Compile Include="IL\Transforms\RemoveDeadVariableInit.cs" />
<Compile Include="IL\Transforms\SplitVariables.cs" /> <Compile Include="IL\Transforms\SplitVariables.cs" />
<Compile Include="IL\Transforms\TransformArrayInitializers.cs" /> <Compile Include="IL\Transforms\TransformArrayInitializers.cs" />

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

@ -18,6 +18,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using ICSharpCode.NRefactory.TypeSystem;
using Mono.Cecil; using Mono.Cecil;
using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.Disassembler;
@ -73,13 +75,28 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Apply a list of transforms to this function. /// Apply a list of transforms to this function.
/// </summary> /// </summary>
public void RunTransforms(IEnumerable<IILTransform> transforms, ILTransformContext context) public void RunTransforms(IEnumerable<IILTransform> transforms, ILTransformContext context, Func<IILTransform, bool> stopTransform = null)
{ {
foreach (var transform in transforms) { foreach (var transform in transforms) {
context.CancellationToken.ThrowIfCancellationRequested(); context.CancellationToken.ThrowIfCancellationRequested();
if (stopTransform != null && stopTransform(transform))
break;
transform.Run(this, context); transform.Run(this, context);
this.CheckInvariant(ILPhase.Normal); this.CheckInvariant(ILPhase.Normal);
} }
} }
public static ILFunction Read(IDecompilerTypeSystem context, IMethod method, CancellationToken cancellationToken = default(CancellationToken))
{
return Read(context, (MethodDefinition)context.GetCecil(method), cancellationToken);
}
public static ILFunction Read(IDecompilerTypeSystem context, MethodDefinition methodDefinition, CancellationToken cancellationToken = default(CancellationToken))
{
var ilReader = new ILReader(context);
var function = ilReader.ReadIL(methodDefinition.Body, cancellationToken);
function.CheckInvariant(ILPhase.Normal);
return function;
}
} }
} }

181
ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs

@ -0,0 +1,181 @@
// Copyright (c) 2011-2016 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.Decompiler.IL.Transforms
{
public class DelegateConstruction : IILTransform
{
ILTransformContext context;
ITypeResolveContext decompilationContext;
void IILTransform.Run(ILFunction function, ILTransformContext context)
{
if (!new DecompilerSettings().AnonymousMethods)
return;
this.context = context;
this.decompilationContext = new SimpleTypeResolveContext(context.TypeSystem.Resolve(function.Method));
foreach (var block in function.Descendants.OfType<Block>()) {
for (int i = block.Instructions.Count - 1; i >= 0; i--) {
foreach (var call in block.Instructions[i].Descendants.OfType<NewObj>()) {
ILFunction f = TransformDelegateConstruction(call);
if (f != null)
call.Arguments[1].ReplaceWith(f);
}
var inst = block.Instructions[i] as IfInstruction;
if (inst != null) {
if (CachedDelegateInitializationWithField(inst)) {
block.Instructions.RemoveAt(i);
continue;
}
if (CachedDelegateInitializationWithLocal(inst)) {
block.Instructions.RemoveAt(i);
continue;
}
}
}
}
}
#region TransformDelegateConstruction
internal static bool IsDelegateConstruction(NewObj inst, bool allowTransformed = false)
{
if (inst == null || inst.Arguments.Count != 2 || inst.Method.DeclaringType.Kind != TypeKind.Delegate)
return false;
var opCode = inst.Arguments[1].OpCode;
return opCode == OpCode.LdFtn || opCode == OpCode.LdVirtFtn || (allowTransformed && opCode == OpCode.ILFunction);
}
static bool IsAnonymousMethod(ITypeDefinition decompiledTypeDefinition, IMethod method)
{
if (method == null || !(method.HasGeneratedName() || method.Name.Contains("$")))
return false;
if (!(method.IsCompilerGenerated() || IsPotentialClosure(decompiledTypeDefinition, method.DeclaringTypeDefinition)))
return false;
return true;
}
static bool IsPotentialClosure(ITypeDefinition decompiledTypeDefinition, ITypeDefinition potentialDisplayClass)
{
if (potentialDisplayClass == null || !potentialDisplayClass.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
return false;
// check that methodContainingType is within containingType
while (potentialDisplayClass != decompiledTypeDefinition) {
potentialDisplayClass = potentialDisplayClass.DeclaringTypeDefinition;
if (potentialDisplayClass == null)
return false;
}
return true;
}
ILFunction TransformDelegateConstruction(NewObj value)
{
if (!IsDelegateConstruction(value))
return null;
var targetMethod = ((IInstructionWithMethodOperand)value.Arguments[1]).Method;
if (IsAnonymousMethod(decompilationContext.CurrentTypeDefinition, targetMethod)) {
var target = value.Arguments[0];
var localTypeSystem = context.TypeSystem.GetSpecializingTypeSystem(decompilationContext);
var function = ILFunction.Read(localTypeSystem, targetMethod, context.CancellationToken);
var contextPrefix = targetMethod.Name;
foreach (ILVariable v in function.Variables.Where(v => v.Kind != VariableKind.Parameter)) {
v.Name = contextPrefix + v.Name;
}
function.RunTransforms(CSharpDecompiler.GetILTransforms(), context, t => t is DelegateConstruction);
function.AcceptVisitor(new ReplaceDelegateTargetVisitor(target, function.Variables.SingleOrDefault(v => v.Index == -1 && v.Kind == VariableKind.Parameter)));
((IILTransform)this).Run(function, new ILTransformContext { CancellationToken = context.CancellationToken, TypeSystem = localTypeSystem });
return function;
}
return null;
}
class ReplaceDelegateTargetVisitor : ILVisitor
{
readonly ILVariable thisVariable;
readonly ILInstruction target;
public ReplaceDelegateTargetVisitor(ILInstruction target, ILVariable thisVariable)
{
this.target = target;
this.thisVariable = thisVariable;
}
protected override void Default(ILInstruction inst)
{
foreach (var child in inst.Children) {
child.AcceptVisitor(this);
}
}
protected internal override void VisitLdLoc(LdLoc inst)
{
if (inst.MatchLdLoc(thisVariable)) {
inst.ReplaceWith(target.Clone());
return;
}
base.VisitLdLoc(inst);
}
}
#endregion
bool CachedDelegateInitializationWithField(IfInstruction inst)
{
// if (comp(ldsfld CachedAnonMethodDelegate == ldnull) {
// stsfld CachedAnonMethodDelegate(DelegateConstruction)
// }
// ... one usage of CachedAnonMethodDelegate ...
// =>
// ... one usage of DelegateConstruction ...
Block trueInst = inst.TrueInst as Block;
var condition = inst.Condition as Comp;
if (condition == null || trueInst == null || trueInst.Instructions.Count != 1 || !inst.FalseInst.MatchNop())
return false;
IField field, field2;
ILInstruction value;
var storeInst = trueInst.Instructions[0];
if (!condition.Left.MatchLdsFld(out field) || !condition.Right.MatchLdNull())
return false;
if (!storeInst.MatchStsFld(out value, out field2) || !field.Equals(field2) || !field.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
return false;
if (!IsDelegateConstruction(value as NewObj, true))
return false;
var nextInstruction = inst.Parent.Children.ElementAtOrDefault(inst.ChildIndex + 1);
if (nextInstruction == null)
return false;
var usages = nextInstruction.Descendants.OfType<LdsFld>().Where(i => i.Field.Equals(field)).ToArray();
if (usages.Length != 1)
return false;
usages[0].ReplaceWith(value);
return true;
}
bool CachedDelegateInitializationWithLocal(IfInstruction inst)
{
return false;
}
}
}

95
ICSharpCode.Decompiler/IL/Transforms/RemoveCachedDelegateInitialization.cs

@ -1,95 +0,0 @@
// Copyright (c) 2011-2016 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.Transforms;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.Decompiler.IL.Transforms
{
public class RemoveCachedDelegateInitialization : IILTransform
{
ILTransformContext context;
ITypeResolveContext decompilationContext;
void IILTransform.Run(ILFunction function, ILTransformContext context)
{
if (!new DecompilerSettings().AnonymousMethods)
return;
this.context = context;
this.decompilationContext = new SimpleTypeResolveContext(context.TypeSystem.Resolve(function.Method));
foreach (var block in function.Descendants.OfType<Block>()) {
for (int i = block.Instructions.Count - 1; i >= 0; i--) {
var inst = block.Instructions[i] as IfInstruction;
if (inst != null) {
if (CachedDelegateInitializationWithField(inst)) {
block.Instructions.RemoveAt(i);
continue;
}
if (CachedDelegateInitializationWithLocal(inst)) {
block.Instructions.RemoveAt(i);
continue;
}
}
}
}
}
bool CachedDelegateInitializationWithField(IfInstruction inst)
{
// if (comp(ldsfld CachedAnonMethodDelegate == ldnull) {
// stsfld CachedAnonMethodDelegate(DelegateConstruction)
// }
// ... one usage of CachedAnonMethodDelegate ...
// =>
// ... one usage of DelegateConstruction ...
Block trueInst = inst.TrueInst as Block;
var condition = inst.Condition as Comp;
if (condition == null || trueInst == null || trueInst.Instructions.Count != 1 || !inst.FalseInst.MatchNop())
return false;
IField field, field2;
ILInstruction value;
var storeInst = trueInst.Instructions[0];
if (!condition.Left.MatchLdsFld(out field) || !condition.Right.MatchLdNull())
return false;
if (!storeInst.MatchStsFld(out value, out field2) || !field.Equals(field2) || !field.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
return false;
if (value.OpCode != OpCode.NewObj || !ExpressionBuilder.IsDelegateConstruction((CallInstruction)value))
return false;
var targetMethod = ((IInstructionWithMethodOperand)((CallInstruction)value).Arguments[1]).Method;
if (!DelegateConstruction.IsAnonymousMethod(decompilationContext.CurrentTypeDefinition, targetMethod))
return false;
var nextInstruction = inst.Parent.Children.ElementAtOrDefault(inst.ChildIndex + 1);
if (nextInstruction == null)
return false;
var usages = nextInstruction.Descendants.OfType<LdsFld>().Where(i => i.Field.Equals(field)).ToArray();
if (usages.Length > 1)
return false;
usages[0].ReplaceWith(value);
return true;
}
bool CachedDelegateInitializationWithLocal(IfInstruction inst)
{
return false;
}
}
}

18
ICSharpCode.Decompiler/NRExtensions.cs

@ -16,12 +16,30 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.Decompiler namespace ICSharpCode.Decompiler
{ {
public static class NRExtensions public static class NRExtensions
{ {
public static IDecompilerTypeSystem GetSpecializingTypeSystem(this IDecompilerTypeSystem typeSystem, ITypeResolveContext decompilationContext)
{
IList<IType> classTypeParameters = null;
IList<IType> methodTypeParameters = null;
if (decompilationContext.CurrentTypeDefinition != null)
classTypeParameters = decompilationContext.CurrentTypeDefinition.TypeArguments;
IMethod method = decompilationContext.CurrentMember as IMethod;
if (method != null)
methodTypeParameters = method.TypeArguments;
if ((classTypeParameters != null && classTypeParameters.Count > 0) || (methodTypeParameters != null && methodTypeParameters.Count > 0))
return new SpecializingDecompilerTypeSystem(typeSystem, new TypeParameterSubstitution(classTypeParameters, methodTypeParameters));
else
return typeSystem;
}
public static bool IsCompilerGenerated(this IEntity entity) public static bool IsCompilerGenerated(this IEntity entity)
{ {
if (entity != null) { if (entity != null) {

Loading…
Cancel
Save