Browse Source

Fix inlining bug due to Pop not having flag MayPop.

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
f81e720d71
  1. 2
      ICSharpCode.Decompiler/IL/ILReader.cs
  2. 14
      ICSharpCode.Decompiler/IL/Instructions.cs
  3. 9
      ICSharpCode.Decompiler/IL/Instructions.tt
  4. 10
      ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
  5. 1
      ICSharpCode.Decompiler/IL/TransformingVisitor.cs
  6. 59
      ICSharpCode.Decompiler/Tests/Helpers/TypeSystemHelper.cs
  7. 41
      ICSharpCode.Decompiler/Tests/ILTransforms/Inlining.cs

2
ICSharpCode.Decompiler/IL/ILReader.cs

@ -354,7 +354,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Clt_Un: case ILOpCode.Clt_Un:
return Comparison(OpCode.Clt_Un, OpCode.Clt_Un); return Comparison(OpCode.Clt_Un, OpCode.Clt_Un);
case ILOpCode.Ckfinite: case ILOpCode.Ckfinite:
return new Ckfinite(); return new Ckfinite(new Peek(stack.Count > 0 ? stack.Peek() : StackType.Unknown));
case ILOpCode.Conv_I1: case ILOpCode.Conv_I1:
return new Conv(Pop(), PrimitiveType.I1, false, Sign.None); return new Conv(Pop(), PrimitiveType.I1, false, Sign.None);
case ILOpCode.Conv_I2: case ILOpCode.Conv_I2:

14
ICSharpCode.Decompiler/IL/Instructions.cs

@ -94,7 +94,7 @@ namespace ICSharpCode.Decompiler.IL
Call, Call,
/// <summary>Virtual method call.</summary> /// <summary>Virtual method call.</summary>
CallVirt, CallVirt,
/// <summary>Checks that the float on top of the stack is not NaN or infinite.</summary> /// <summary>Checks that the input float is not NaN or infinite.</summary>
Ckfinite, Ckfinite,
/// <summary>Numeric cast.</summary> /// <summary>Numeric cast.</summary>
Conv, Conv,
@ -307,10 +307,6 @@ namespace ICSharpCode.Decompiler.IL
} }
StackType resultType; StackType resultType;
public override StackType ResultType { get { return resultType; } } public override StackType ResultType { get { return resultType; } }
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayPeek;
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitPeek(this); return visitor.VisitPeek(this);
@ -789,16 +785,16 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
/// <summary>Checks that the float on top of the stack is not NaN or infinite.</summary> /// <summary>Checks that the input float is not NaN or infinite.</summary>
public sealed partial class Ckfinite : SimpleInstruction public sealed partial class Ckfinite : UnaryInstruction
{ {
public Ckfinite() : base(OpCode.Ckfinite) public Ckfinite(ILInstruction argument) : base(OpCode.Ckfinite, argument)
{ {
} }
public override StackType ResultType { get { return StackType.Void; } } public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return InstructionFlags.MayPeek | InstructionFlags.MayThrow; return base.ComputeFlags() | InstructionFlags.MayThrow;
} }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {

9
ICSharpCode.Decompiler/IL/Instructions.tt

@ -36,7 +36,7 @@
new OpCode("pop", "Pops the top of the evaluation stack and returns the value.", new OpCode("pop", "Pops the top of the evaluation stack and returns the value.",
NoArguments, ResultTypeParam), NoArguments, ResultTypeParam),
new OpCode("peek", "Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'.", new OpCode("peek", "Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'.",
Peeking, NoArguments, ResultTypeParam), NoArguments, ResultTypeParam),
new OpCode("void", "Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.", new OpCode("void", "Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.",
VoidResult, Unary), VoidResult, Unary),
new OpCode("ILFunction", "A container of IL blocks.", new OpCode("ILFunction", "A container of IL blocks.",
@ -97,8 +97,8 @@
new OpCode("call", "Non-virtual method call.", Call), new OpCode("call", "Non-virtual method call.", Call),
new OpCode("callvirt", "Virtual method call.", new OpCode("callvirt", "Virtual method call.",
CustomClassName("CallVirt"), Call), CustomClassName("CallVirt"), Call),
new OpCode("ckfinite", "Checks that the float on top of the stack is not NaN or infinite.", new OpCode("ckfinite", "Checks that the input float is not NaN or infinite.",
Peeking, NoArguments, MayThrow, VoidResult), Unary, MayThrow, VoidResult),
new OpCode("conv", "Numeric cast.", new OpCode("conv", "Numeric cast.",
Unary, CustomConstructor), Unary, CustomConstructor),
new OpCode("ldloc", "Loads the value of a local variable. (ldarg/ldloc)", new OpCode("ldloc", "Loads the value of a local variable. (ldarg/ldloc)",
@ -405,9 +405,6 @@ namespace ICSharpCode.Decompiler.IL
}; };
} }
// Peeking trait: the instruction looks at the top-of-stack without popping
static Action<OpCode> Peeking = HasFlag("InstructionFlags.MayPeek");
// ResultType trait: the instruction has the specified result type. // ResultType trait: the instruction has the specified result type.
static Action<OpCode> ResultType(string type) static Action<OpCode> ResultType(string type)
{ {

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

@ -63,6 +63,11 @@ namespace ICSharpCode.Decompiler.IL
partial class Pop partial class Pop
{ {
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayPop;
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context) internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{ {
return context.Pop(flagsBefore) ?? this; return context.Pop(flagsBefore) ?? this;
@ -71,6 +76,11 @@ namespace ICSharpCode.Decompiler.IL
partial class Peek partial class Peek
{ {
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayPeek;
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context) internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{ {
return context.Peek(flagsBefore) ?? this; return context.Peek(flagsBefore) ?? this;

1
ICSharpCode.Decompiler/IL/TransformingVisitor.cs

@ -98,6 +98,7 @@ namespace ICSharpCode.Decompiler.IL
stack.didInline = false; stack.didInline = false;
stack.error = false; stack.error = false;
inst = inst.Inline(InstructionFlags.None, stack); inst = inst.Inline(InstructionFlags.None, stack);
Debug.Assert(stack.error == inst.HasFlag(InstructionFlags.MayPeek | InstructionFlags.MayPop));
} while (stack.didInline); // repeat transformations when something was inlined } while (stack.didInline); // repeat transformations when something was inlined
if (stack.error || inst.HasFlag(InstructionFlags.MayBranch)) { if (stack.error || inst.HasFlag(InstructionFlags.MayBranch)) {
// Values currently on the stack might be used on both sides of the branch, // Values currently on the stack might be used on both sides of the branch,

59
ICSharpCode.Decompiler/Tests/Helpers/TypeSystemHelper.cs

@ -47,5 +47,64 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
{ {
return decompilerTypeSystem.Value.Compilation.FindType(type); return decompilerTypeSystem.Value.Compilation.FindType(type);
} }
/// <summary>
/// Retrieves a static method that returns void and takes the specified parameter types.
/// </summary>
public static IMethod Action<T1>()
{
return Action(typeof(T1));
}
/// <summary>
/// Retrieves a static method that returns void and takes the specified parameter types.
/// </summary>
public static IMethod Action<T1, T2>()
{
return Action(typeof(T1), typeof(T2));
}
/// <summary>
/// Retrieves a static method that returns void and takes the specified parameter types.
/// </summary>
public static IMethod Action<T1, T2, T3>()
{
return Action(typeof(T1), typeof(T2), typeof(T3));
}
/// <summary>
/// Retrieves a static method that returns void and takes the specified parameter types.
/// </summary>
public static IMethod Action<T1, T2, T3, T4>()
{
return Action(typeof(T1), typeof(T2), typeof(T3), typeof(T4));
}
/// <summary>
/// Retrieves a static method that returns void and takes the specified parameter types.
/// </summary>
public static IMethod Action(params Type[] paramTypes)
{
return Action(paramTypes.Select(FromReflection).ToArray());
}
/// <summary>
/// Retrieves a static method that returns void and takes the specified parameter types.
/// </summary>
public static IMethod Action(params IType[] paramTypes)
{
return FromReflection(typeof(Actions)).GetMethods(
m => m.Name == "Action" && m.TypeParameters.Count == paramTypes.Length && m.Parameters.Count == paramTypes.Length)
.Single();
}
}
static class Actions
{
public static void Action() {}
public static void Action<T1>(T1 a1) {}
public static void Action<T1, T2>(T1 a1, T2 a2) {}
public static void Action<T1, T2, T3>(T1 a1, T2 a2, T3 a3) {}
public static void Action<T1, T2, T3, T4>(T1 a1, T2 a2, T3 a3, T4 a4) {}
} }
} }

41
ICSharpCode.Decompiler/Tests/ILTransforms/Inlining.cs

@ -18,6 +18,7 @@
using System; using System;
using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL;
using NUnit.Framework; using NUnit.Framework;
using ICSharpCode.Decompiler.Tests.Helpers;
namespace ICSharpCode.Decompiler.Tests.ILTransforms namespace ICSharpCode.Decompiler.Tests.ILTransforms
{ {
@ -43,10 +44,42 @@ namespace ICSharpCode.Decompiler.Tests.ILTransforms
new Add(new Pop(StackType.I4), new Pop(StackType.I4), false, Sign.Signed) new Add(new Pop(StackType.I4), new Pop(StackType.I4), false, Sign.Signed)
}); });
f.AcceptVisitor(new TransformingVisitor()); f.AcceptVisitor(new TransformingVisitor());
/*Assert.AreEqual( Assert.AreEqual(
, new Add(new LdcI4(1), new LdcI4(2), false, Sign.Signed).ToString(),
f.Body f.Body.ToString()
);*/ );
}
[Test]
public void SkipInlineBlocks()
{
var f = MakeFunction(
new Block {
new LdcI4(1),
new LdcI4(2),
new LdcI4(3),
new Call(TypeSystem.Action<int, int, int>()) {
Arguments = {
new Pop(StackType.I4),
new Block { new Pop(StackType.I4) },
new Pop(StackType.I4),
}
}
});
f.AcceptVisitor(new TransformingVisitor());
Assert.AreEqual(
new Block {
new LdcI4(1),
new Call(TypeSystem.Action<int, int, int>()) {
Arguments = {
new LdcI4(2),
new Block { new Pop(StackType.I4) },
new LdcI4(3)
}
}
}.ToString(),
f.Body.ToString()
);
} }
} }
} }

Loading…
Cancel
Save