What I want to do is change how a C# method executes when it is called, so that I can write something like this:
[Distributed]
public DTask<bool> Solve(int n, DEvent<bool> callback)
{
for (int m = 2; m < n - 1; m += 1)
if (m % n == 0)
return false;
return true;
}
At run-time, I need to be able to analyse methods that have the Distributed attribute (which I already can do) and then insert code before the body of the function executes and after the function returns. More importantly, I need to be able to do it without modifying code where Solve is called or at the start of the function (at compile time; doing so at run-time is the objective).
At the moment I have attempted this bit of code (assume t is the type that Solve is stored in, and m is a MethodInfo of Solve):
private void WrapMethod(Type t, MethodInfo m)
{
// Generate ILasm for delegate.
byte[] il = typeof(Dpm).GetMethod("ReplacedSolve").GetMethodBody().GetILAsByteArray();
// Pin the bytes in the garbage collection.
GCHandle h = GCHandle.Alloc((object)il, GCHandleType.Pinned);
IntPtr addr = h.AddrOfPinnedObject();
int size = il.Length;
// Swap the method.
MethodRental.SwapMethodBody(t, m.MetadataToken, addr, size, MethodRental.JitImmediate);
}
public DTask<bool> ReplacedSolve(int n, DEvent<bool> callback)
{
Console.WriteLine("This was executed instead!");
return true;
}
However, MethodRental.SwapMethodBody only works on dynamic modules; not those that have already been compiled and stored in the assembly.
So I'm looking for a way to effectively do SwapMethodBody on a method that is already stored in a loaded and executing assembly.
Note, it is not an issue if I have to completely copy the method into a dynamic module, but in this case I need to find a way to copy across the IL as well as update all of the calls to Solve() such that they would point to the new copy.
You CAN modify a method's content at runtime. But you're not supposed to, and it's strongly recommended to keep that for test purposes.
Just have a look at:
http://www.codeproject.com/Articles/463508/NET-CLR-Injection-Modify-IL-Code-during-Run-time
Basically, you can:
Mess with these bytes.
If you just wish to prepend or append some code, then just preprend/append opcodes you want (be careful about leaving stack clean, though)
Here are some tips to "uncompile" existing IL:
Once modified, you IL byte array can be reinjected via InjectionHelper.UpdateILCodes(MethodInfo method, byte[] ilCodes) - see link mentioned above
This is the "unsafe" part... It works well, but this consists in hacking internal CLR mechanisms...
I know it is not the exact answer to your question, but the usual way to do it is using factories/proxy approach.
First we declare a base type.
Then we can declare a derived type (call it proxy).
The derived type can be also generated at runtime.
The only performance loss is during construction of the derived object, the first time is quite slow because it will use a lot of reflection and reflection emit. All other times, it is the cost of a concurrent table lookup and a constructor. As said, you can optimize construction using
Logman's solution, but with an interface for swapping method bodies. Also, a simpler example.
You can replace a method at runtime by using the ICLRPRofiling Interface.
See this blog for more details.
Harmony is an open source library designed to replace, decorate or modify existing C# methods of any kind during runtime. It main focus is games and plugins written in Mono but the technique can be used with any .NET version. It also takes care of multiple changes to the same method (they accumulate instead of overwrite).
It creates methods of type DynamicMethod for every original method and emits code to it that calls custom methods at the start and end. It also allows you to write filters to process the original IL code which allows for more detailed manipulation of the original method.
To complete the process, it writes a simple assembler jump into the trampoline of the original method that points to the assembler generated from compiling the dynamic method. This works for 32/64Bit on Windows, macOS and any Linux that Mono supports.
There exists a couple of frameworks that allows you to dynamically change any method at runtime (they use the ICLRProfiling interface mentioned by user152949):
There are also a few frameworks that mocks around with the internals of .NET, these are likely more fragile, and probably can't change inlined code, but on the other hand they are fully self-contained and does not require you to use a custom launcher.