/// <summary> /// Uses LCG to create method such as this: /// /// object MatchCaller(object target, CallSite site, object[] args) { /// return ((ActualDelegateType)target)(site, args[0], args[1], args[2], ...); /// } /// /// inserting appropriate casts and boxings as needed. /// </summary> /// <param name="type">Type of the delegate to call</param> /// <returns>A MatchCallerTarget delegate.</returns> private static object CreateCaller(Type type) { PerfTrack.NoteEvent(PerfTrack.Categories.Count, "Interpreter.MatchCaller.CreateCaller"); MethodInfo invoke = type.GetMethod("Invoke"); ParameterInfo[] parameters = invoke.GetParameters(); var il = Snippets.Shared.CreateDynamicMethod("_istub_" + Interlocked.Increment(ref _id), typeof(object), _CallerSignature, false); Type siteType = typeof(CallSite <>).MakeGenericType(type); List <RefFixer> fixers = null; // Emit the call site and cast it to the right type il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Castclass, siteType); il.Emit(OpCodes.Ldfld, siteType.GetField("Target")); // CallSite il.Emit(OpCodes.Ldarg_0); // Arguments for (int i = 1; i < parameters.Length; i++) { il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldc_I4, i - 1); il.Emit(OpCodes.Ldelem_Ref); Type pt = parameters[i].ParameterType; if (pt.IsByRef) { RefFixer rf = new RefFixer(il.DeclareLocal(pt.GetElementType()), i - 1); if (rf.Temp.LocalType.IsValueType) { il.Emit(OpCodes.Unbox_Any, rf.Temp.LocalType); } else if (rf.Temp.LocalType != typeof(object)) { il.Emit(OpCodes.Castclass, rf.Temp.LocalType); } il.Emit(OpCodes.Stloc, rf.Temp); il.Emit(OpCodes.Ldloca, rf.Temp); if (fixers == null) { fixers = new List <RefFixer>(); } fixers.Add(rf); } else if (pt.IsValueType) { il.Emit(OpCodes.Unbox_Any, pt); } else if (pt != typeof(object)) { il.Emit(OpCodes.Castclass, pt); } } // Call the delegate il.Emit(OpCodes.Callvirt, invoke); // Propagate the ref parameters back into the array. if (fixers != null) { foreach (RefFixer rf in fixers) { il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldc_I4, rf.Index); il.Emit(OpCodes.Ldloc, rf.Temp); if (rf.Temp.LocalType.IsValueType) { il.Emit(OpCodes.Box, rf.Temp.LocalType); } il.Emit(OpCodes.Stelem_Ref); } } // Return value if (invoke.ReturnType == typeof(void)) { il.Emit(OpCodes.Ldnull); } else if (invoke.ReturnType.IsValueType) { il.Emit(OpCodes.Box, invoke.ReturnType); } il.Emit(OpCodes.Ret); return(il.CreateDelegate <MatchCallerTarget>()); }
/// <summary> /// Uses LCG to create method such as this: /// /// object MatchCaller(object target, CallSite site, object[] args) { /// return ((ActualDelegateType)target)(site, args[0], args[1], args[2], ...); /// } /// /// inserting appropriate casts and boxings as needed. /// </summary> /// <param name="type">Type of the delegate to call</param> /// <returns>A MatchCallerTarget delegate.</returns> private static object CreateCaller(Type type) { PerfTrack.NoteEvent(PerfTrack.Categories.Count, "Interpreter.MatchCaller.CreateCaller"); MethodInfo invoke = type.GetMethod("Invoke"); ParameterInfo[] parameters = invoke.GetParameters(); var il = Snippets.Shared.CreateDynamicMethod("_istub_" + Interlocked.Increment(ref _id), typeof(object), _CallerSignature, false); Type siteType = typeof(CallSite<>).MakeGenericType(type); List<RefFixer> fixers = null; // Emit the call site and cast it to the right type il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Castclass, siteType); il.Emit(OpCodes.Ldfld, siteType.GetField("Target")); // CallSite il.Emit(OpCodes.Ldarg_0); // Arguments for (int i = 1; i < parameters.Length; i++) { il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldc_I4, i - 1); il.Emit(OpCodes.Ldelem_Ref); Type pt = parameters[i].ParameterType; if (pt.IsByRef) { RefFixer rf = new RefFixer(il.DeclareLocal(pt.GetElementType()), i - 1); if (rf.Temp.LocalType.IsValueType) { il.Emit(OpCodes.Unbox_Any, rf.Temp.LocalType); } else if (rf.Temp.LocalType != typeof(object)) { il.Emit(OpCodes.Castclass, rf.Temp.LocalType); } il.Emit(OpCodes.Stloc, rf.Temp); il.Emit(OpCodes.Ldloca, rf.Temp); if (fixers == null) { fixers = new List<RefFixer>(); } fixers.Add(rf); } else if (pt.IsValueType) { il.Emit(OpCodes.Unbox_Any, pt); } else if (pt != typeof(object)) { il.Emit(OpCodes.Castclass, pt); } } // Call the delegate il.Emit(OpCodes.Callvirt, invoke); // Propagate the ref parameters back into the array. if (fixers != null) { foreach (RefFixer rf in fixers) { il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldc_I4, rf.Index); il.Emit(OpCodes.Ldloc, rf.Temp); if (rf.Temp.LocalType.IsValueType) { il.Emit(OpCodes.Box, rf.Temp.LocalType); } il.Emit(OpCodes.Stelem_Ref); } } // Return value if (invoke.ReturnType == typeof(void)) { il.Emit(OpCodes.Ldnull); } else if (invoke.ReturnType.IsValueType) { il.Emit(OpCodes.Box, invoke.ReturnType); } il.Emit(OpCodes.Ret); return il.CreateDelegate<MatchCallerTarget>(); }