Created
February 27, 2020 18:07
-
-
Save pawlos/0ac1a64e00593cb1ec40263775b6df65 to your computer and use it in GitHub Desktop.
This file contains hidden or 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.Diagnostics; | |
using System.IO; | |
using System.Linq; | |
using System.Reflection; | |
using Mono.Cecil; | |
using Mono.Cecil.Cil; | |
namespace SimpleILMeasurement | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
if (args.Length != 1) | |
{ | |
Console.WriteLine("SimpleILMeasurement.exe <assembly>"); | |
return; | |
} | |
string fileName = args[0]; | |
ModuleDefinition module = ModuleDefinition.ReadModule(fileName); | |
if (module.Kind == ModuleKind.Windows) | |
module.Kind = ModuleKind.Console; | |
var stopWatchCtor = | |
module.ImportReference(typeof(Stopwatch).GetConstructor(BindingFlags.Instance | BindingFlags.Public, | |
null, new Type[0], null)); | |
var stopWatchRef = module.ImportReference(typeof(Stopwatch)); | |
var stopWatchStartRef = module.ImportReference(typeof(Stopwatch).GetMethod("Start", new Type[0])); | |
var stopWatchStopRef = module.ImportReference(typeof(Stopwatch).GetMethod("Stop", new Type[0])); | |
var stopWatchElapsedRef = module.ImportReference(typeof(Stopwatch).GetProperty("Elapsed")?.GetMethod); | |
var consoleWriteLineRef = | |
module.ImportReference(typeof(Console).GetMethod("WriteLine", new[] {typeof(string), typeof(object)})); | |
var timeSpanRef = module.ImportReference(typeof(TimeSpan)); | |
foreach (var type in module.Types) | |
{ | |
foreach (var method in type.Methods) | |
{ | |
if (!method.HasBody) continue; | |
var ilProcessor = method.Body.GetILProcessor(); | |
var variableDeclaration = new VariableDefinition(stopWatchRef); | |
method.Body.Variables.Add(variableDeclaration); | |
var firstInstruction = method.Body.Instructions.First(); | |
// var v0 = new Stopwatch(); | |
// v0.Start(); | |
var newObjOpcode = ilProcessor.Create(OpCodes.Newobj, stopWatchCtor); | |
var stLocOpcode = ilProcessor.Create(OpCodes.Stloc, variableDeclaration); | |
var ldLocOpcode = ilProcessor.Create(OpCodes.Ldloc, variableDeclaration); | |
var callStartOpcode = ilProcessor.Create(OpCodes.Call, stopWatchStartRef); | |
ilProcessor.InsertBefore(firstInstruction, newObjOpcode); | |
ilProcessor.InsertBefore(firstInstruction, stLocOpcode); | |
ilProcessor.InsertBefore(firstInstruction, ldLocOpcode); | |
ilProcessor.InsertBefore(firstInstruction, callStartOpcode); | |
// original code | |
// v0.Stop(); | |
// Console.WriteLine($"---Method {method.Name} took {0}", v0.Elapsed); | |
var ldLocOpcode2 = ilProcessor.Create(OpCodes.Ldloc, variableDeclaration); | |
var callStopOpcode = ilProcessor.Create(OpCodes.Call, stopWatchStopRef); | |
var ldStrOpcode = ilProcessor.Create(OpCodes.Ldstr, $"---Method {method.Name} took {{0}}"); | |
var callElapsedOpcode = ilProcessor.Create(OpCodes.Call, stopWatchElapsedRef); | |
var callWriteLineOpcode = ilProcessor.Create(OpCodes.Call, consoleWriteLineRef); | |
var boxOpcode = ilProcessor.Create(OpCodes.Box, timeSpanRef); | |
var lastInstruction = ilProcessor.Body.Instructions.Last(); | |
ilProcessor.Replace(lastInstruction, ldLocOpcode2); | |
ilProcessor.Body.Instructions.Add(callStopOpcode); | |
ilProcessor.Body.Instructions.Add(ldStrOpcode); | |
ilProcessor.Body.Instructions.Add(ldLocOpcode); | |
ilProcessor.Body.Instructions.Add(callElapsedOpcode); | |
ilProcessor.Body.Instructions.Add(boxOpcode); | |
ilProcessor.Body.Instructions.Add(callWriteLineOpcode); | |
ilProcessor.Body.Instructions.Add(lastInstruction); | |
foreach (var bodyInstruction in ilProcessor.Body.Instructions) | |
{ | |
if (bodyInstruction.OpCode != OpCodes.Br && bodyInstruction.OpCode != OpCodes.Br_S) continue; | |
if (((Instruction)bodyInstruction.Operand).OpCode != OpCodes.Ret) continue; | |
bodyInstruction.Operand = ldLocOpcode2; | |
} | |
} | |
} | |
module.Write(Path.GetFileNameWithoutExtension(fileName) + ".modified" + Path.GetExtension(fileName)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment