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.