diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs
index 1d7d904d7..af3dd2e13 100644
--- a/ICSharpCode.Decompiler/IL/ILReader.cs
+++ b/ICSharpCode.Decompiler/IL/ILReader.cs
@@ -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:
diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs
index 936ddcf93..7eb435221 100644
--- a/ICSharpCode.Decompiler/IL/Instructions.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions.cs
@@ -94,7 +94,7 @@ namespace ICSharpCode.Decompiler.IL
Call,
/// Virtual method call.
CallVirt,
- /// Checks that the float on top of the stack is not NaN or infinite.
+ /// Checks that the input float is not NaN or infinite.
Ckfinite,
/// Numeric cast.
Conv,
@@ -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(ILVisitor visitor)
{
return visitor.VisitPeek(this);
@@ -789,16 +785,16 @@ namespace ICSharpCode.Decompiler.IL
}
}
- /// Checks that the float on top of the stack is not NaN or infinite.
- public sealed partial class Ckfinite : SimpleInstruction
+ /// Checks that the input float is not NaN or infinite.
+ 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(ILVisitor visitor)
{
diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt
index 5380511ef..acf021417 100644
--- a/ICSharpCode.Decompiler/IL/Instructions.tt
+++ b/ICSharpCode.Decompiler/IL/Instructions.tt
@@ -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 @@
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
};
}
- // Peeking trait: the instruction looks at the top-of-stack without popping
- static Action Peeking = HasFlag("InstructionFlags.MayPeek");
-
// ResultType trait: the instruction has the specified result type.
static Action ResultType(string type)
{
diff --git a/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
index c03292cb8..b976a8f88 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
@@ -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
partial class Peek
{
+ protected override InstructionFlags ComputeFlags()
+ {
+ return InstructionFlags.MayPeek;
+ }
+
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
return context.Peek(flagsBefore) ?? this;
diff --git a/ICSharpCode.Decompiler/IL/TransformingVisitor.cs b/ICSharpCode.Decompiler/IL/TransformingVisitor.cs
index 4644250b5..22b0fcf39 100644
--- a/ICSharpCode.Decompiler/IL/TransformingVisitor.cs
+++ b/ICSharpCode.Decompiler/IL/TransformingVisitor.cs
@@ -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,
diff --git a/ICSharpCode.Decompiler/Tests/Helpers/TypeSystemHelper.cs b/ICSharpCode.Decompiler/Tests/Helpers/TypeSystemHelper.cs
index 54f0414b9..fb340ce3b 100644
--- a/ICSharpCode.Decompiler/Tests/Helpers/TypeSystemHelper.cs
+++ b/ICSharpCode.Decompiler/Tests/Helpers/TypeSystemHelper.cs
@@ -47,5 +47,64 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
{
return decompilerTypeSystem.Value.Compilation.FindType(type);
}
+
+ ///
+ /// Retrieves a static method that returns void and takes the specified parameter types.
+ ///
+ public static IMethod Action()
+ {
+ return Action(typeof(T1));
+ }
+
+ ///
+ /// Retrieves a static method that returns void and takes the specified parameter types.
+ ///
+ public static IMethod Action()
+ {
+ return Action(typeof(T1), typeof(T2));
+ }
+
+ ///
+ /// Retrieves a static method that returns void and takes the specified parameter types.
+ ///
+ public static IMethod Action()
+ {
+ return Action(typeof(T1), typeof(T2), typeof(T3));
+ }
+
+ ///
+ /// Retrieves a static method that returns void and takes the specified parameter types.
+ ///
+ public static IMethod Action()
+ {
+ return Action(typeof(T1), typeof(T2), typeof(T3), typeof(T4));
+ }
+
+ ///
+ /// Retrieves a static method that returns void and takes the specified parameter types.
+ ///
+ public static IMethod Action(params Type[] paramTypes)
+ {
+ return Action(paramTypes.Select(FromReflection).ToArray());
+ }
+
+ ///
+ /// Retrieves a static method that returns void and takes the specified parameter types.
+ ///
+ 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 a1) {}
+ public static void Action(T1 a1, T2 a2) {}
+ public static void Action(T1 a1, T2 a2, T3 a3) {}
+ public static void Action(T1 a1, T2 a2, T3 a3, T4 a4) {}
}
}
diff --git a/ICSharpCode.Decompiler/Tests/ILTransforms/Inlining.cs b/ICSharpCode.Decompiler/Tests/ILTransforms/Inlining.cs
index 2fb3ee21d..fd3736e74 100644
--- a/ICSharpCode.Decompiler/Tests/ILTransforms/Inlining.cs
+++ b/ICSharpCode.Decompiler/Tests/ILTransforms/Inlining.cs
@@ -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
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()) {
+ 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()) {
+ Arguments = {
+ new LdcI4(2),
+ new Block { new Pop(StackType.I4) },
+ new LdcI4(3)
+ }
+ }
+ }.ToString(),
+ f.Body.ToString()
+ );
}
}
}