Created
April 9, 2011 10:16
-
-
Save ArildF/911288 to your computer and use it in GitHub Desktop.
Replace calls with tail calls using Mono.Cecil
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using Mono.Cecil; | |
using Mono.Cecil.Cil; | |
namespace TailCalls | |
{ | |
class Program | |
{ | |
static int Main(string[] args) | |
{ | |
var filename = args.FirstOrDefault(); | |
if (filename == null) | |
{ | |
Usage(); | |
return 0; | |
} | |
try | |
{ | |
ProcessModule(filename); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine(ex); | |
return 1; | |
} | |
return 0; | |
} | |
private static void ProcessModule(string filename) | |
{ | |
var moduleDefinition = ModuleDefinition.ReadModule(filename); | |
var methods = from type in moduleDefinition.Types | |
from method in type.Methods | |
select method; | |
foreach (var methodDefinition in methods) | |
{ | |
ProcessMethod(methodDefinition); | |
} | |
moduleDefinition.Write(filename); | |
} | |
private static void ProcessMethod(MethodDefinition methodDefinition) | |
{ | |
var body = methodDefinition.Body; | |
var processor = body.GetILProcessor(); | |
bool seenRet = false; | |
foreach(var instruction in body.Instructions.Reverse()) | |
{ | |
if (instruction.OpCode == OpCodes.Ret) | |
{ | |
seenRet = true; | |
} | |
else if (seenRet && instruction.OpCode.In(OpCodes.Call, OpCodes.Calli, OpCodes.Callvirt)) | |
{ | |
var tailCall = processor.Create(OpCodes.Tail); | |
processor.InsertBefore(instruction, tailCall); | |
seenRet = false; | |
} | |
else if (instruction.OpCode != OpCodes.Nop) | |
{ | |
seenRet = false; | |
} | |
} | |
} | |
private static void Usage() | |
{ | |
Console.WriteLine(@"Usage: TailCall Path\To\Assembly.dll"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment