PageRenderTime 104ms CodeModel.GetById 40ms app.highlight 15ms RepoModel.GetById 45ms app.codeStats 1ms

/Microsoft.Scripting/Interpretation/Interpreter.MatchCaller.cs

https://bitbucket.org/stefanrusek/xronos
C# | 203 lines | 127 code | 32 blank | 44 comment | 21 complexity | 5dd2fa7af628e5b4200e9e09bd1275b0 MD5 | raw file
  1/* ****************************************************************************
  2 *
  3 * Copyright (c) Microsoft Corporation. 
  4 *
  5 * This source code is subject to terms and conditions of the Microsoft Public License. A 
  6 * copy of the license can be found in the License.html file at the root of this distribution. If 
  7 * you cannot locate the  Microsoft Public License, please send an email to 
  8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
  9 * by the terms of the Microsoft Public License.
 10 *
 11 * You must not remove this notice, or any other, from this software.
 12 *
 13 *
 14 * ***************************************************************************/
 15
 16#if CODEPLEX_40
 17using System;
 18#else
 19using System; using Microsoft;
 20#endif
 21using System.Collections.Generic;
 22using System.Reflection;
 23using System.Reflection.Emit;
 24using System.Runtime.CompilerServices;
 25#if !CODEPLEX_40
 26using Microsoft.Runtime.CompilerServices;
 27#endif
 28
 29using System.Threading;
 30using Microsoft.Scripting.Generation;
 31
 32namespace Microsoft.Scripting.Interpretation {
 33    public static partial class Interpreter {
 34        internal delegate object MatchCallerTarget(CallSite site, object[] args);
 35
 36        /// <summary>
 37        /// MatchCaller allows to call match maker delegate with the signature (object, CallSite, object[])
 38        /// It is used by the call site cache lookup logic when searching for applicable rule.
 39        /// </summary>
 40        internal static class MatchCaller {
 41            public static object Target0(CallSite site, object[] args) {
 42                return ((CallSite<Func<CallSite, object>>)site).Target(site);
 43            }
 44
 45            public static object Target1(CallSite site, object[] args) {
 46                return ((CallSite<Func<CallSite, object, object>>)site).Target(site, args[0]);
 47            }
 48
 49            public static object Target2(CallSite site, object[] args) {
 50                return ((CallSite<Func<CallSite, object, object, object>>)site).Target(site, args[0], args[1]);
 51            }
 52
 53            public static object Target3(CallSite site, object[] args) {
 54                return ((CallSite<Func<CallSite, object, object, object, object>>)site).Target(site, args[0], args[1], args[2]);
 55            }
 56
 57            public static object Target4(CallSite site, object[] args) {
 58                return ((CallSite<Func<CallSite, object, object, object, object, object>>)site).Target(site, args[0], args[1], args[2], args[3]);
 59            }
 60
 61            public static object Target5(CallSite site, object[] args) {
 62                return ((CallSite<Func<CallSite, object, object, object, object, object, object>>)site).Target(site, args[0], args[1], args[2], args[3], args[4]);
 63            }
 64
 65            public static object Target6(CallSite site, object[] args) {
 66                return ((CallSite<Func<CallSite, object, object, object, object, object, object, object>>)site).Target(site, args[0], args[1], args[2], args[3], args[4], args[5]);
 67            }
 68
 69            public static object Target7(CallSite site, object[] args) {
 70                return ((CallSite<Func<CallSite, object, object, object, object, object, object, object, object>>)site).Target(site, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
 71            }
 72
 73            public static object Target8(CallSite site, object[] args) {
 74                return ((CallSite<Func<CallSite, object, object, object, object, object, object, object, object, object>>)site).Target(site, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
 75            }
 76
 77            public static object Target9(CallSite site, object[] args) {
 78                return ((CallSite<Func<CallSite, object, object, object, object, object, object, object, object, object, object>>)site).Target(site, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
 79            }
 80
 81            private struct RefFixer {
 82                internal readonly LocalBuilder Temp;
 83                internal readonly int Index;
 84
 85                internal RefFixer(LocalBuilder temp, int index) {
 86                    Temp = temp;
 87                    Index = index;
 88                }
 89            }
 90
 91            // TODO: Should this really be Type -> WeakReference?
 92            // Issue #1, we'll end up growing the dictionary for each unique type
 93            // Issue #2, we'll lose the generated delegate in the first gen-0
 94            // collection.
 95            //
 96            // We probably need to replace this with an actual cache that holds
 97            // onto the delegates and ages them out.
 98            //
 99            private static readonly Dictionary<Type, MatchCallerTarget> _Callers = new Dictionary<Type, MatchCallerTarget>();
100            private static readonly Type[] _CallerSignature = new Type[] { typeof(CallSite), typeof(object[]) };
101
102            internal static MatchCallerTarget GetCaller(Type type) {
103                MatchCallerTarget target;
104
105                // LOCK to extract the weak reference with the updater DynamicMethod 
106                lock (_Callers) {
107                    if (!_Callers.TryGetValue(type, out target)) {
108                        target = (MatchCallerTarget)CreateCaller(type);
109                        _Callers[type] = target;
110                    }
111                }
112
113                return target;
114            }
115
116            private static int _id;
117
118            /// <summary>
119            /// Uses LCG to create method such as this:
120            /// 
121            /// object MatchCaller(object target, CallSite site, object[] args) {
122            ///      return ((ActualDelegateType)target)(site, args[0], args[1], args[2], ...);
123            /// }
124            /// 
125            /// inserting appropriate casts and boxings as needed.
126            /// </summary>
127            /// <param name="type">Type of the delegate to call</param>
128            /// <returns>A MatchCallerTarget delegate.</returns>
129            private static object CreateCaller(Type type) {
130                PerfTrack.NoteEvent(PerfTrack.Categories.Count, "Interpreter.MatchCaller.CreateCaller");
131                
132                MethodInfo invoke = type.GetMethod("Invoke");
133                ParameterInfo[] parameters = invoke.GetParameters();
134
135                var il = Snippets.Shared.CreateDynamicMethod("_istub_" + Interlocked.Increment(ref _id), typeof(object), _CallerSignature, false);
136                Type siteType = typeof(CallSite<>).MakeGenericType(type);
137
138                List<RefFixer> fixers = null;
139
140                // Emit the call site and cast it to the right type
141                il.Emit(OpCodes.Ldarg_0);
142                il.Emit(OpCodes.Castclass, siteType);
143                il.Emit(OpCodes.Ldfld, siteType.GetField("Target"));
144
145                // CallSite
146                il.Emit(OpCodes.Ldarg_0);
147
148                // Arguments
149                for (int i = 1; i < parameters.Length; i++) {
150                    il.Emit(OpCodes.Ldarg_1);
151                    il.Emit(OpCodes.Ldc_I4, i - 1);
152                    il.Emit(OpCodes.Ldelem_Ref);
153                    Type pt = parameters[i].ParameterType;
154                    if (pt.IsByRef) {
155                        RefFixer rf = new RefFixer(il.DeclareLocal(pt.GetElementType()), i - 1);
156                        if (rf.Temp.LocalType.IsValueType) {
157                            il.Emit(OpCodes.Unbox_Any, rf.Temp.LocalType);
158                        } else if (rf.Temp.LocalType != typeof(object)) {
159                            il.Emit(OpCodes.Castclass, rf.Temp.LocalType);
160                        }
161                        il.Emit(OpCodes.Stloc, rf.Temp);
162                        il.Emit(OpCodes.Ldloca, rf.Temp);
163
164                        if (fixers == null) {
165                            fixers = new List<RefFixer>();
166                        }
167                        fixers.Add(rf);
168                    } else if (pt.IsValueType) {
169                        il.Emit(OpCodes.Unbox_Any, pt);
170                    } else if (pt != typeof(object)) {
171                        il.Emit(OpCodes.Castclass, pt);
172                    }
173                }
174
175                // Call the delegate
176                il.Emit(OpCodes.Callvirt, invoke);
177
178                // Propagate the ref parameters back into the array.
179                if (fixers != null) {
180                    foreach (RefFixer rf in fixers) {
181                        il.Emit(OpCodes.Ldarg_1);
182                        il.Emit(OpCodes.Ldc_I4, rf.Index);
183                        il.Emit(OpCodes.Ldloc, rf.Temp);
184                        if (rf.Temp.LocalType.IsValueType) {
185                            il.Emit(OpCodes.Box, rf.Temp.LocalType);
186                        }
187                        il.Emit(OpCodes.Stelem_Ref);
188                    }
189                }
190
191                // Return value
192                if (invoke.ReturnType == typeof(void)) {
193                    il.Emit(OpCodes.Ldnull);
194                } else if (invoke.ReturnType.IsValueType) {
195                    il.Emit(OpCodes.Box, invoke.ReturnType);
196                }
197
198                il.Emit(OpCodes.Ret);
199                return il.CreateDelegate<MatchCallerTarget>();
200            }
201        }
202    }
203}