Consider the following snippet of code:

    private string GetFieldValueAsString(string nonAliasedEntityName = 
null, string nonAliasedName = null)
    {
        return nonAliasedEntityName ?? nonAliasedName;   // simplified code 
of course!
    }

It is compiled to the following IL code:

    .method private hidebysig 
        instance string GetFieldValueAsString (
            [opt] string nonAliasedEntityName,
            [opt] string nonAliasedName
        ) cil managed 
    {
        .param [1] = nullref
        .param [2] = nullref
        // Method begins at RVA 0x2cb6f
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.1
        IL_0001: dup
        IL_0002: brtrue.s IL_0006

        IL_0004: pop
        IL_0005: ldarg.2

        IL_0006: ret
    } // end of method MessageBuilder::GetFieldValueAsString

I borrowed the 'fix the returns' from Anotar to my add-in. I get the 
following IL code when I compile:

    .method private hidebysig 
        instance string GetFieldValueAsString (
            [opt] string nonAliasedEntityName,
            [opt] string nonAliasedName
        ) cil managed 
    {
        .param [1] = nullref
        .param [2] = nullref
        // Method begins at RVA 0x2cb70
        // Code size 15 (0xf)
        .maxstack 3
        .locals (
            [0] string $returnVariable
        )

        IL_0000: ldarg.1
        IL_0001: dup
        IL_0002: dup
        IL_0003: stloc.0
        IL_0004: brtrue.s IL_000b

        IL_0006: pop
        IL_0007: ldarg.2
        IL_0008: stloc.0
        IL_0009: br.s IL_000b

        IL_000b: nop
        IL_000c: nop
        IL_000d: ldloc.0
        IL_000e: ret
    } // end of method MessageBuilder::GetFieldValueAsString

It gives me the following error when decompiling in ILSpy, and fails to run:

    ICSharpCode.Decompiler.DecompilerException: Error decompiling 
System.String 
LinkDev.Notifications.Steps.MessageBuilder::GetFieldValueAsString(System.String,System.String)
     ---> System.Exception: Inconsistent stack size at IL_09
       at 
ICSharpCode.Decompiler.ILAst.ILAstBuilder.StackAnalysis(MethodDefinition 
methodDef)
       at ICSharpCode.Decompiler.ILAst.ILAstBuilder.Build(MethodDefinition 
methodDef, Boolean optimize, DecompilerContext context)
       at 
ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(IEnumerable`1 
parameters)
       at 
ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(MethodDefinition
 
methodDef, DecompilerContext context, IEnumerable`1 parameters)
       --- End of inner exception stack trace ---
       at 
ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(MethodDefinition
 
methodDef, DecompilerContext context, IEnumerable`1 parameters)
       at 
ICSharpCode.Decompiler.Ast.AstBuilder.CreateMethod(MethodDefinition 
methodDef)
       at ICSharpCode.Decompiler.Ast.AstBuilder.AddMethod(MethodDefinition 
method)
       at ICSharpCode.ILSpy.CSharpLanguage.DecompileMethod(MethodDefinition 
method, ITextOutput output, DecompilationOptions options)
       at 
ICSharpCode.ILSpy.TextView.DecompilerTextView.DecompileNodes(DecompilationContext
 
context, ITextOutput textOutput)
       at 
ICSharpCode.ILSpy.TextView.DecompilerTextView.<>c__DisplayClass31_0.<DecompileAsync>b__0()

I traced the stack size, and it seems to hold. Any idea what could be 
causing this issue?

The ReturnFixer class is as follows:

    using Mono.Cecil;
    using Mono.Cecil.Cil;
    using Mono.Collections.Generic;

    public class ReturnFixer
    {
        public MethodDefinition Method;
        Instruction nopForHandleEnd;
        Collection<Instruction> instructions;
        public Instruction NopBeforeReturn;
        Instruction sealBranchesNop;
        public VariableDefinition ReturnVariable;

        public void MakeLastStatementReturn()
        {

            instructions = Method.Body.Instructions;
            FixHangingHandlerEnd();

            sealBranchesNop = Instruction.Create(OpCodes.Nop);
            instructions.Add(sealBranchesNop);

            NopBeforeReturn = Instruction.Create(OpCodes.Nop);

            if (IsMethodReturnValue())
            {
                ReturnVariable = 
Method.Body.DeclareVariable("$returnVariable", 
Method.MethodReturnType.ReturnType);
            }

            for (var index = 0; index < instructions.Count; index++)
            {
                var operand = instructions[index].Operand as Instruction;

                if (operand == null || operand.OpCode != OpCodes.Ret)
                {
                    continue;
                }

                if (IsMethodReturnValue())
                {
                    // The C# compiler never jumps directly to a ret
                    // when returning a value from the method. But other 
Fody
                    // modules and other compilers might. So store the 
value here.
                    instructions.Insert(index, 
Instruction.Create(OpCodes.Stloc, ReturnVariable));
                    instructions.Insert(index, 
Instruction.Create(OpCodes.Dup));
                    index += 2;
                }

                instructions[index].Operand = sealBranchesNop;
            }

            if (IsMethodReturnValue())
            {
                WithReturnValue();
            }
            else
            {
                WithNoReturn();
            }
        }

        bool IsMethodReturnValue()
        {
            return Method.MethodReturnType.ReturnType.Name != "Void";
        }

        void FixHangingHandlerEnd()
        {
            if (Method.Body.ExceptionHandlers.Count == 0)
            {
                return;
            }

            nopForHandleEnd = Instruction.Create(OpCodes.Nop);
            Method.Body.Instructions.Add(nopForHandleEnd);
            foreach (var handler in Method.Body.ExceptionHandlers)
            {
                if (handler.HandlerStart != null && handler.HandlerEnd == 
null)
                {
                    handler.HandlerEnd = nopForHandleEnd;
                }
            }
        }


        void WithReturnValue()
        {

            for (var index = 0; index < instructions.Count; index++)
            {
                var instruction = instructions[index];
                if (instruction.OpCode == OpCodes.Ret)
                {
                    instructions.Insert(index, 
Instruction.Create(OpCodes.Stloc, ReturnVariable));
                    instruction.OpCode = OpCodes.Br;
                    instruction.Operand = sealBranchesNop;
                    index++;
                }
            }
            instructions.Add(NopBeforeReturn);
            instructions.Add(Instruction.Create(OpCodes.Ldloc, 
ReturnVariable));
            instructions.Add(Instruction.Create(OpCodes.Ret));

        }

        void WithNoReturn()
        {

            foreach (var instruction in instructions)
            {
                if (instruction.OpCode == OpCodes.Ret)
                {
                    instruction.OpCode = OpCodes.Br;
                    instruction.Operand = sealBranchesNop;
                }
            }
            instructions.Add(NopBeforeReturn);
            instructions.Add(Instruction.Create(OpCodes.Ret));
        }

    }

-- 
-- 
--
mono-cecil
--- 
You received this message because you are subscribed to the Google Groups 
"mono-cecil" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to