Hi guys,
I'm using cecil to write a basic optimizing / post processing tool.
I've decided to go for the low hanging fruit first. I'm trying to
replace callvirt's that are used purely for null checks, with call
instructions.
I iterate through the instructions in a method, find callvirt's, and
if its a non virtual/abstract method, then I use the
ILProcessor.Replace() method. When I'm done I use
AssemblyDefinition.Write() to save it back to disk.
private void stripMethod( MethodDefinition method )
{
var processor = method.Body.GetILProcessor();
for(int i = 0; i < method.Body.Instructions.Count; i++)
{
var instruction = method.Body.Instructions[i];
if(instruction.OpCode == OpCodes.Callvirt)
{
MethodDefinition callee = ( instruction.Operand as
MethodReference ).Resolve();
if( canUseCall( callee ) )
{
Console.Write("->");
var newInstruction =
processor.Create(OpCodes.Call, callee);
processor.Replace(instruction, newInstruction);
Debug.Print(">>> {0} {1} <<<",
newInstruction.OpCode.Name,
newInstruction.Operand);
}
}
Console.WriteLine("\t{0} {1}", instruction.OpCode.Name,
instruction.Operand);
}
}
This works, sort of. The problem is that when I save back the
resulting assembly to disk, sometimes its wrong. The IL that gets
saved is not always matching up with the IL I modified. At first
glance, it appears to only happen with method calls that exist in
another assembly, but truth be told I haven't fully tested that yet.
In one case as an example, by making System.Object::GetType() use a
call instruction, somehow a call to Main() got inserted into the
instruction stream.
I'm not sure if this is a bug in Mono.Cecil, or a bug in my brain. I
just grabbed cecil yesterday morning and started on this. So I'm
leaning towards me doing something stupid here...
--
--
mono-cecil