Skip to content

Instantly share code, notes, and snippets.

@LukasBoersma
Created January 21, 2014 12:01
Show Gist options
  • Save LukasBoersma/8538784 to your computer and use it in GitHub Desktop.
Save LukasBoersma/8538784 to your computer and use it in GitHub Desktop.
MethodRental
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
public class Program
{
static ModuleBuilder modb;
static Type type;
static void Main()
{
var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Foo"), AssemblyBuilderAccess.Run);
modb = ab.DefineDynamicModule("Foo");
var tb1 = modb.DefineType("Frob");
var jitstub = new byte[15];
jitstub[0] = (byte)OpCodes.Ldtoken.Value;
jitstub[5] = (byte)OpCodes.Call.Value;
WriteInt32(jitstub, 6, modb.GetMethodToken(typeof(Program).GetMethod("JIT")).Token);
jitstub[10] = (byte)OpCodes.Jmp.Value;
var mb1 = tb1.DefineMethod("M", MethodAttributes.Static | MethodAttributes.Public, null, new Type[] { typeof(int) });
mb1.SetImplementationFlags(MethodImplAttributes.NoInlining);
int tok1 = modb.GetMethodToken(mb1).Token;
WriteInt32(jitstub, 1, tok1);
WriteInt32(jitstub, 11, tok1);
mb1.CreateMethodBody(jitstub, jitstub.Length);
var mb2 = tb1.DefineMethod(".ctor", MethodAttributes.Public | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName, null, new Type[] { typeof(int) });
mb2.SetImplementationFlags(MethodImplAttributes.NoInlining);
var tok2 = modb.GetMethodToken(mb2).Token;
WriteInt32(jitstub, 1, tok2);
WriteInt32(jitstub, 11, tok2);
mb2.CreateMethodBody(jitstub, jitstub.Length);
type = tb1.CreateType();
var mi = type.GetMethod("M");
mi.Invoke(null, new object[] { 42 });
mi.Invoke(null, new object[] { 42 });
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void JIT(RuntimeMethodHandle rmh)
{
MethodBase method = MethodBase.GetMethodFromHandle(rmh);
Console.WriteLine("JIT compiling " + method.Name);
if (method.Name == "M")
{
byte[] buf = new byte[18];
buf[0] = 0x02 | (17 << 2);
buf[1] = (byte)OpCodes.Call.Value;
WriteInt32(buf, 2, modb.GetMethodToken(typeof(Console).GetMethod("WriteLine", Type.EmptyTypes)).Token);
buf[6] = (byte)OpCodes.Ldarg_0.Value;
buf[7] = (byte)OpCodes.Newobj.Value;
WriteInt32(buf, 8, modb.GetConstructorToken(type.GetConstructor(new Type[] { typeof(int) })).Token);
buf[12] = (byte)OpCodes.Call.Value;
WriteInt32(buf, 13, modb.GetMethodToken(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(object) })).Token);
buf[17] = (byte)OpCodes.Ret.Value;
GCHandle h = GCHandle.Alloc(buf, GCHandleType.Pinned);
MethodRental.SwapMethodBody(method.DeclaringType, method.MetadataToken, h.AddrOfPinnedObject(), 18, MethodRental.JitImmediate);
h.Free();
}
else
{
byte[] buf = new byte[14];
buf[0] = 0x02 | (13 << 2);
buf[1] = (byte)OpCodes.Ldarg_0.Value;
buf[2] = (byte)OpCodes.Call.Value;
WriteInt32(buf, 3, modb.GetConstructorToken(typeof(object).GetConstructor(Type.EmptyTypes)).Token);
buf[7] = (byte)OpCodes.Ldarg_1.Value;
buf[8] = (byte)OpCodes.Call.Value;
WriteInt32(buf, 9, modb.GetMethodToken(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) })).Token);
buf[13] = (byte)OpCodes.Ret.Value;
GCHandle h = GCHandle.Alloc(buf, GCHandleType.Pinned);
MethodRental.SwapMethodBody(method.DeclaringType, method.MetadataToken, h.AddrOfPinnedObject(), 14, MethodRental.JitImmediate);
h.Free();
}
}
private static void WriteInt32(byte[] buf, int offset, int value)
{
buf[offset++] = (byte)(value >> 0);
buf[offset++] = (byte)(value >> 8);
buf[offset++] = (byte)(value >> 16);
buf[offset++] = (byte)(value >> 24);
}
}
@T0bi-Ethirbirge
Copy link

Thank you. I really appreciate your work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment