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