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

14
ICSharpCode.Decompiler/IL/Instructions.cs

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

9
ICSharpCode.Decompiler/IL/Instructions.tt

@ -36,7 +36,7 @@ @@ -36,7 +36,7 @@
new OpCode("pop", "Pops the top of the evaluation stack and returns the value.",
NoArguments, ResultTypeParam),
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.",
VoidResult, Unary),
new OpCode("ILFunction", "A container of IL blocks.",
@ -97,8 +97,8 @@ @@ -97,8 +97,8 @@
new OpCode("call", "Non-virtual method call.", Call),
new OpCode("callvirt", "Virtual method call.",
CustomClassName("CallVirt"), Call),
new OpCode("ckfinite", "Checks that the float on top of the stack is not NaN or infinite.",
Peeking, NoArguments, MayThrow, VoidResult),
new OpCode("ckfinite", "Checks that the input float is not NaN or infinite.",
Unary, MayThrow, VoidResult),
new OpCode("conv", "Numeric cast.",
Unary, CustomConstructor),
new OpCode("ldloc", "Loads the value of a local variable. (ldarg/ldloc)",
@ -405,9 +405,6 @@ namespace ICSharpCode.Decompiler.IL @@ -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.
static Action<OpCode> ResultType(string type)
{

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

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

1
ICSharpCode.Decompiler/IL/TransformingVisitor.cs

@ -98,6 +98,7 @@ namespace ICSharpCode.Decompiler.IL @@ -98,6 +98,7 @@ namespace ICSharpCode.Decompiler.IL
stack.didInline = false;
stack.error = false;
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
if (stack.error || inst.HasFlag(InstructionFlags.MayBranch)) {
// 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 @@ -47,5 +47,64 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
{
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 @@ @@ -18,6 +18,7 @@
using System;
using ICSharpCode.Decompiler.IL;
using NUnit.Framework;
using ICSharpCode.Decompiler.Tests.Helpers;
namespace ICSharpCode.Decompiler.Tests.ILTransforms
{
@ -43,10 +44,42 @@ 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)
});
f.AcceptVisitor(new TransformingVisitor());
/*Assert.AreEqual(
,
f.Body
);*/
Assert.AreEqual(
new Add(new LdcI4(1), new LdcI4(2), false, Sign.Signed).ToString(),
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