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); } }