PageRenderTime 33ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/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. #if CODEPLEX_40
  16. using System;
  17. #else
  18. using System; using Microsoft;
  19. #endif
  20. using System.Collections.Generic;
  21. using System.Reflection;
  22. using System.Reflection.Emit;
  23. using System.Runtime.CompilerServices;
  24. #if !CODEPLEX_40
  25. using Microsoft.Runtime.CompilerServices;
  26. #endif
  27. using System.Threading;
  28. using Microsoft.Scripting.Generation;
  29. namespace Microsoft.Scripting.Interpretation {
  30. public static partial class Interpreter {
  31. internal delegate object MatchCallerTarget(CallSite site, object[] args);
  32. /// <summary>
  33. /// MatchCaller allows to call match maker delegate with the signature (object, CallSite, object[])
  34. /// It is used by the call site cache lookup logic when searching for applicable rule.
  35. /// </summary>
  36. internal static class MatchCaller {
  37. public static object Target0(CallSite site, object[] args) {
  38. return ((CallSite<Func<CallSite, object>>)site).Target(site);
  39. }
  40. public static object Target1(CallSite site, object[] args) {
  41. return ((CallSite<Func<CallSite, object, object>>)site).Target(site, args[0]);
  42. }
  43. public static object Target2(CallSite site, object[] args) {
  44. return ((CallSite<Func<CallSite, object, object, object>>)site).Target(site, args[0], args[1]);
  45. }
  46. public static object Target3(CallSite site, object[] args) {
  47. return ((CallSite<Func<CallSite, object, object, object, object>>)site).Target(site, args[0], args[1], args[2]);
  48. }
  49. public static object Target4(CallSite site, object[] args) {
  50. return ((CallSite<Func<CallSite, object, object, object, object, object>>)site).Target(site, args[0], args[1], args[2], args[3]);
  51. }
  52. public static object Target5(CallSite site, object[] args) {
  53. return ((CallSite<Func<CallSite, object, object, object, object, object, object>>)site).Target(site, args[0], args[1], args[2], args[3], args[4]);
  54. }
  55. public static object Target6(CallSite site, object[] args) {
  56. 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]);
  57. }
  58. public static object Target7(CallSite site, object[] args) {
  59. 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]);
  60. }
  61. public static object Target8(CallSite site, object[] args) {
  62. 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]);
  63. }
  64. public static object Target9(CallSite site, object[] args) {
  65. 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]);
  66. }
  67. private struct RefFixer {
  68. internal readonly LocalBuilder Temp;
  69. internal readonly int Index;
  70. internal RefFixer(LocalBuilder temp, int index) {
  71. Temp = temp;
  72. Index = index;
  73. }
  74. }
  75. // TODO: Should this really be Type -> WeakReference?
  76. // Issue #1, we'll end up growing the dictionary for each unique type
  77. // Issue #2, we'll lose the generated delegate in the first gen-0
  78. // collection.
  79. //
  80. // We probably need to replace this with an actual cache that holds
  81. // onto the delegates and ages them out.
  82. //
  83. private static readonly Dictionary<Type, MatchCallerTarget> _Callers = new Dictionary<Type, MatchCallerTarget>();
  84. private static readonly Type[] _CallerSignature = new Type[] { typeof(CallSite), typeof(object[]) };
  85. internal static MatchCallerTarget GetCaller(Type type) {
  86. MatchCallerTarget target;
  87. // LOCK to extract the weak reference with the updater DynamicMethod
  88. lock (_Callers) {
  89. if (!_Callers.TryGetValue(type, out target)) {
  90. target = (MatchCallerTarget)CreateCaller(type);
  91. _Callers[type] = target;
  92. }
  93. }
  94. return target;
  95. }
  96. private static int _id;
  97. /// <summary>
  98. /// Uses LCG to create method such as this:
  99. ///
  100. /// object MatchCaller(object target, CallSite site, object[] args) {
  101. /// return ((ActualDelegateType)target)(site, args[0], args[1], args[2], ...);
  102. /// }
  103. ///
  104. /// inserting appropriate casts and boxings as needed.
  105. /// </summary>
  106. /// <param name="type">Type of the delegate to call</param>
  107. /// <returns>A MatchCallerTarget delegate.</returns>
  108. private static object CreateCaller(Type type) {
  109. PerfTrack.NoteEvent(PerfTrack.Categories.Count, "Interpreter.MatchCaller.CreateCaller");
  110. MethodInfo invoke = type.GetMethod("Invoke");
  111. ParameterInfo[] parameters = invoke.GetParameters();
  112. var il = Snippets.Shared.CreateDynamicMethod("_istub_" + Interlocked.Increment(ref _id), typeof(object), _CallerSignature, false);
  113. Type siteType = typeof(CallSite<>).MakeGenericType(type);
  114. List<RefFixer> fixers = null;
  115. // Emit the call site and cast it to the right type
  116. il.Emit(OpCodes.Ldarg_0);
  117. il.Emit(OpCodes.Castclass, siteType);
  118. il.Emit(OpCodes.Ldfld, siteType.GetField("Target"));
  119. // CallSite
  120. il.Emit(OpCodes.Ldarg_0);
  121. // Arguments
  122. for (int i = 1; i < parameters.Length; i++) {
  123. il.Emit(OpCodes.Ldarg_1);
  124. il.Emit(OpCodes.Ldc_I4, i - 1);
  125. il.Emit(OpCodes.Ldelem_Ref);
  126. Type pt = parameters[i].ParameterType;
  127. if (pt.IsByRef) {
  128. RefFixer rf = new RefFixer(il.DeclareLocal(pt.GetElementType()), i - 1);
  129. if (rf.Temp.LocalType.IsValueType) {
  130. il.Emit(OpCodes.Unbox_Any, rf.Temp.LocalType);
  131. } else if (rf.Temp.LocalType != typeof(object)) {
  132. il.Emit(OpCodes.Castclass, rf.Temp.LocalType);
  133. }
  134. il.Emit(OpCodes.Stloc, rf.Temp);
  135. il.Emit(OpCodes.Ldloca, rf.Temp);
  136. if (fixers == null) {
  137. fixers = new List<RefFixer>();
  138. }
  139. fixers.Add(rf);
  140. } else if (pt.IsValueType) {
  141. il.Emit(OpCodes.Unbox_Any, pt);
  142. } else if (pt != typeof(object)) {
  143. il.Emit(OpCodes.Castclass, pt);
  144. }
  145. }
  146. // Call the delegate
  147. il.Emit(OpCodes.Callvirt, invoke);
  148. // Propagate the ref parameters back into the array.
  149. if (fixers != null) {
  150. foreach (RefFixer rf in fixers) {
  151. il.Emit(OpCodes.Ldarg_1);
  152. il.Emit(OpCodes.Ldc_I4, rf.Index);
  153. il.Emit(OpCodes.Ldloc, rf.Temp);
  154. if (rf.Temp.LocalType.IsValueType) {
  155. il.Emit(OpCodes.Box, rf.Temp.LocalType);
  156. }
  157. il.Emit(OpCodes.Stelem_Ref);
  158. }
  159. }
  160. // Return value
  161. if (invoke.ReturnType == typeof(void)) {
  162. il.Emit(OpCodes.Ldnull);
  163. } else if (invoke.ReturnType.IsValueType) {
  164. il.Emit(OpCodes.Box, invoke.ReturnType);
  165. }
  166. il.Emit(OpCodes.Ret);
  167. return il.CreateDelegate<MatchCallerTarget>();
  168. }
  169. }
  170. }
  171. }