PageRenderTime 49ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/Microsoft.Scripting/Utils/ReflectedCaller.cs

https://bitbucket.org/stefanrusek/xronos
C# | 197 lines | 137 code | 26 blank | 34 comment | 28 complexity | 31ab5cff6db38b6b0f9b47add08645f3 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. * ironpy@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 Microsoft.Scripting.Runtime;
  24. namespace Microsoft.Scripting.Utils {
  25. public partial class ReflectedCaller {
  26. internal ReflectedCaller() { }
  27. private static readonly Dictionary<MethodInfo, ReflectedCaller> _cache = new Dictionary<MethodInfo,ReflectedCaller>();
  28. /// <summary>
  29. /// Creates a new ReflectedCaller which can be used to quickly invoke the provided MethodInfo.
  30. /// </summary>
  31. public static ReflectedCaller Create(MethodInfo info) {
  32. if ((!info.IsStatic && info.DeclaringType.IsValueType) ||
  33. info is System.Reflection.Emit.DynamicMethod) {
  34. return new SlowReflectedCaller(info);
  35. }
  36. ParameterInfo[] pis = info.GetParameters();
  37. int argCnt = pis.Length;
  38. if (!info.IsStatic) argCnt++;
  39. if (argCnt >= MaxHelpers) {
  40. // no delegate for this size, fallback to reflection invoke
  41. return new SlowReflectedCaller(info);
  42. }
  43. foreach (ParameterInfo pi in pis) {
  44. if (pi.ParameterType.IsByRef) {
  45. // we don't support ref args via generics.
  46. return new SlowReflectedCaller(info);
  47. }
  48. }
  49. // see if we've created one w/ a delegate
  50. ReflectedCaller res;
  51. if (ShouldCache(info)) {
  52. lock (_cache) {
  53. if (_cache.TryGetValue(info, out res)) {
  54. return res;
  55. }
  56. }
  57. }
  58. // create it
  59. try {
  60. if (argCnt < MaxArgs) {
  61. res = FastCreate(info, pis);
  62. } else {
  63. res = SlowCreate(info, pis);
  64. }
  65. } catch (TargetInvocationException tie) {
  66. if (!(tie.InnerException is NotSupportedException)) {
  67. throw;
  68. }
  69. res = new SlowReflectedCaller(info);
  70. } catch (NotSupportedException) {
  71. // if Delegate.CreateDelegate can't handle the method fallback to
  72. // the slow reflection version. For example this can happen w/
  73. // a generic method defined on an interface and implemented on a class.
  74. res = new SlowReflectedCaller(info);
  75. }
  76. // cache it for future users if it's a reasonable method to cache
  77. if (ShouldCache(info)) {
  78. lock (_cache) {
  79. _cache[info] = res;
  80. }
  81. }
  82. return res;
  83. }
  84. private static bool ShouldCache(MethodInfo info) {
  85. return !(info is DynamicMethod);
  86. }
  87. /// <summary>
  88. /// Gets the next type or null if no more types are available.
  89. /// </summary>
  90. private static Type TryGetParameterOrReturnType(MethodInfo target, ParameterInfo[] pi, int index) {
  91. if (!target.IsStatic) {
  92. index--;
  93. if (index < 0) {
  94. return target.DeclaringType;
  95. }
  96. }
  97. if (index < pi.Length) {
  98. // next in signature
  99. return pi[index].ParameterType;
  100. }
  101. if (target.ReturnType == typeof(void) || index > pi.Length) {
  102. // no more parameters
  103. return null;
  104. }
  105. // last parameter on Invoke is return type
  106. return target.ReturnType;
  107. }
  108. private static bool IndexIsNotReturnType(int index, MethodInfo target, ParameterInfo[] pi) {
  109. return pi.Length != index || (pi.Length == index && !target.IsStatic);
  110. }
  111. /// <summary>
  112. /// Uses reflection to create new instance of the appropriate ReflectedCaller
  113. /// </summary>
  114. private static ReflectedCaller SlowCreate(MethodInfo info, ParameterInfo[] pis) {
  115. List<Type> types = new List<Type>();
  116. if (!info.IsStatic) types.Add(info.DeclaringType);
  117. foreach (ParameterInfo pi in pis) {
  118. types.Add(pi.ParameterType);
  119. }
  120. if (info.ReturnType != typeof(void)) {
  121. types.Add(info.ReturnType);
  122. }
  123. Type[] arrTypes = types.ToArray();
  124. return (ReflectedCaller)Activator.CreateInstance(GetHelperType(info, arrTypes), info);
  125. }
  126. }
  127. sealed partial class SlowReflectedCaller : ReflectedCaller {
  128. private MethodInfo _target;
  129. public SlowReflectedCaller(MethodInfo target) {
  130. _target = target;
  131. }
  132. public override object Invoke(params object[] args) {
  133. return InvokeWorker(args);
  134. }
  135. public override object InvokeInstance(object instance, params object[] args) {
  136. if (_target.IsStatic) {
  137. try {
  138. return _target.Invoke(null, args);
  139. } catch (TargetInvocationException e) {
  140. throw ExceptionHelpers.UpdateForRethrow(e.InnerException);
  141. }
  142. }
  143. try {
  144. return _target.Invoke(instance, args);
  145. } catch (TargetInvocationException e) {
  146. throw ExceptionHelpers.UpdateForRethrow(e.InnerException);
  147. }
  148. }
  149. private object InvokeWorker(params object[] args) {
  150. if (_target.IsStatic) {
  151. try {
  152. return _target.Invoke(null, args);
  153. } catch (TargetInvocationException e) {
  154. throw ExceptionHelpers.UpdateForRethrow(e.InnerException);
  155. }
  156. }
  157. try {
  158. return _target.Invoke(args[0], GetNonStaticArgs(args));
  159. } catch (TargetInvocationException e) {
  160. throw ExceptionHelpers.UpdateForRethrow(e.InnerException);
  161. }
  162. }
  163. private static object[] GetNonStaticArgs(object[] args) {
  164. object[] newArgs = new object[args.Length - 1];
  165. for (int i = 0; i < newArgs.Length; i++) {
  166. newArgs[i] = args[i + 1];
  167. }
  168. return newArgs;
  169. }
  170. }
  171. }