PageRenderTime 41ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft.Scripting/Runtime/DelegateSignatureInfo.cs

https://bitbucket.org/stefanrusek/xronos
C# | 262 lines | 182 code | 46 blank | 34 comment | 33 complexity | 122c6e086a6d39f216d3d2a0fbb755f9 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. #if CODEPLEX_40
  22. using System.Dynamic;
  23. using System.Linq.Expressions;
  24. #else
  25. using Microsoft.Scripting;
  26. using Microsoft.Linq.Expressions;
  27. #endif
  28. using System.Reflection;
  29. using System.Reflection.Emit;
  30. using System.Runtime.CompilerServices;
  31. #if !CODEPLEX_40
  32. using Microsoft.Runtime.CompilerServices;
  33. #endif
  34. using System.Text;
  35. using Microsoft.Contracts;
  36. using Microsoft.Scripting.Actions;
  37. using Microsoft.Scripting.Generation;
  38. using Microsoft.Scripting.Utils;
  39. namespace Microsoft.Scripting.Runtime {
  40. /// <summary>
  41. /// Used as the key for the ScriptingRuntimeHelpers.GetDelegate method caching system
  42. /// </summary>
  43. internal sealed class DelegateSignatureInfo {
  44. private readonly LanguageContext _context;
  45. private readonly Type _returnType;
  46. private readonly ParameterInfo[] _parameters;
  47. private readonly ConvertBinder _convert;
  48. private readonly InvokeBinder _invoke;
  49. internal static readonly object TargetPlaceHolder = new object();
  50. internal static readonly object CallSitePlaceHolder = new object();
  51. internal static readonly object ConvertSitePlaceHolder = new object();
  52. internal DelegateSignatureInfo(LanguageContext context, Type returnType, ParameterInfo[] parameters) {
  53. Assert.NotNull(context, returnType);
  54. Assert.NotNullItems(parameters);
  55. _context = context;
  56. _parameters = parameters;
  57. _returnType = returnType;
  58. if (_returnType != typeof(void)) {
  59. _convert = _context.CreateConvertBinder(_returnType, true);
  60. }
  61. _invoke = _context.CreateInvokeBinder(new CallInfo(_parameters.Length));
  62. }
  63. [Confined]
  64. public override bool Equals(object obj) {
  65. DelegateSignatureInfo dsi = obj as DelegateSignatureInfo;
  66. if (dsi == null ||
  67. dsi._context != _context ||
  68. dsi._parameters.Length != _parameters.Length ||
  69. dsi._returnType != _returnType) {
  70. return false;
  71. }
  72. for (int i = 0; i < _parameters.Length; i++) {
  73. if (dsi._parameters[i] != _parameters[i]) {
  74. return false;
  75. }
  76. }
  77. return true;
  78. }
  79. [Confined]
  80. public override int GetHashCode() {
  81. int hashCode = 5331;
  82. for (int i = 0; i < _parameters.Length; i++) {
  83. hashCode ^= _parameters[i].GetHashCode();
  84. }
  85. hashCode ^= _returnType.GetHashCode() ^ _context.GetHashCode();
  86. return hashCode;
  87. }
  88. [Confined]
  89. public override string ToString() {
  90. StringBuilder text = new StringBuilder();
  91. text.Append(_returnType.ToString());
  92. text.Append("(");
  93. for (int i = 0; i < _parameters.Length; i++) {
  94. if (i != 0) text.Append(", ");
  95. text.Append(_parameters[i].ParameterType.Name);
  96. }
  97. text.Append(")");
  98. return text.ToString();
  99. }
  100. internal DelegateInfo GenerateDelegateStub() {
  101. PerfTrack.NoteEvent(PerfTrack.Categories.DelegateCreate, ToString());
  102. Type[] delegateParams = new Type[_parameters.Length];
  103. for (int i = 0; i < _parameters.Length; i++) {
  104. delegateParams[i] = _parameters[i].ParameterType;
  105. }
  106. // Create the method with a special name so the langauge compiler knows that method's stack frame is not visible
  107. DynamicILGen cg = Snippets.Shared.CreateDynamicMethod("_Scripting_", _returnType, ArrayUtils.Insert(typeof(object[]), delegateParams), false);
  108. // Emit the stub
  109. object[] constants = EmitClrCallStub(cg);
  110. // Save the constants in the delegate info class
  111. return new DelegateInfo(cg.Finish(), constants, this);
  112. }
  113. /// <summary>
  114. /// Generates stub to receive the CLR call and then call the dynamic language code.
  115. /// </summary>
  116. private object[] EmitClrCallStub(ILGen cg) {
  117. List<ReturnFixer> fixers = new List<ReturnFixer>(0);
  118. // Create strongly typed return type from the site.
  119. // This will, among other things, generate tighter code.
  120. Type[] siteTypes = MakeSiteSignature();
  121. CallSite callSite = CallSite.Create(DynamicSiteHelpers.MakeCallSiteDelegate(siteTypes), InvokeBinder);
  122. Type siteType = callSite.GetType();
  123. Type convertSiteType = null;
  124. CallSite convertSite = null;
  125. if (_returnType != typeof(void)) {
  126. convertSite = CallSite.Create(DynamicSiteHelpers.MakeCallSiteDelegate(typeof(object), _returnType), ConvertBinder);
  127. convertSiteType = convertSite.GetType();
  128. }
  129. // build up constants array
  130. object[] constants = new object[] { TargetPlaceHolder, CallSitePlaceHolder, ConvertSitePlaceHolder };
  131. const int TargetIndex = 0, CallSiteIndex = 1, ConvertSiteIndex = 2;
  132. LocalBuilder convertSiteLocal = null;
  133. FieldInfo convertTarget = null;
  134. if (_returnType != typeof(void)) {
  135. // load up the conversesion logic on the stack
  136. convertSiteLocal = cg.DeclareLocal(convertSiteType);
  137. EmitConstantGet(cg, ConvertSiteIndex, convertSiteType);
  138. cg.Emit(OpCodes.Dup);
  139. cg.Emit(OpCodes.Stloc, convertSiteLocal);
  140. convertTarget = convertSiteType.GetField("Target");
  141. cg.EmitFieldGet(convertTarget);
  142. cg.Emit(OpCodes.Ldloc, convertSiteLocal);
  143. }
  144. // load up the invoke logic on the stack
  145. LocalBuilder site = cg.DeclareLocal(siteType);
  146. EmitConstantGet(cg, CallSiteIndex, siteType);
  147. cg.Emit(OpCodes.Dup);
  148. cg.Emit(OpCodes.Stloc, site);
  149. FieldInfo target = siteType.GetField("Target");
  150. cg.EmitFieldGet(target);
  151. cg.Emit(OpCodes.Ldloc, site);
  152. EmitConstantGet(cg, TargetIndex, typeof(object));
  153. for (int i = 0; i < _parameters.Length; i++) {
  154. if (_parameters[i].ParameterType.IsByRef) {
  155. ReturnFixer rf = ReturnFixer.EmitArgument(cg, i + 1, _parameters[i].ParameterType);
  156. if (rf != null) fixers.Add(rf);
  157. } else {
  158. cg.EmitLoadArg(i + 1);
  159. }
  160. }
  161. // emit the invoke for the call
  162. cg.EmitCall(target.FieldType, "Invoke");
  163. // emit the invoke for the convert
  164. if (_returnType == typeof(void)) {
  165. cg.Emit(OpCodes.Pop);
  166. } else {
  167. cg.EmitCall(convertTarget.FieldType, "Invoke");
  168. }
  169. // fixup any references
  170. foreach (ReturnFixer rf in fixers) {
  171. rf.FixReturn(cg);
  172. }
  173. cg.Emit(OpCodes.Ret);
  174. return constants;
  175. }
  176. private static void EmitConstantGet(ILGen il, int index, Type type) {
  177. il.Emit(OpCodes.Ldarg_0);
  178. il.EmitInt(index);
  179. il.Emit(OpCodes.Ldelem_Ref);
  180. if (type != typeof(object)) {
  181. il.Emit(OpCodes.Castclass, type);
  182. }
  183. }
  184. internal Type[] MakeSiteSignature() {
  185. Type[] sig = new Type[_parameters.Length + 2];
  186. // target object
  187. sig[0] = typeof(object);
  188. // arguments
  189. for (int i = 0; i < _parameters.Length; i++) {
  190. if (_parameters[i].IsByRefParameter()) {
  191. sig[i + 1] = typeof(object);
  192. } else {
  193. sig[i + 1] = _parameters[i].ParameterType;
  194. }
  195. }
  196. // return type
  197. sig[sig.Length - 1] = typeof(object);
  198. return sig;
  199. }
  200. internal Type ReturnType {
  201. get {
  202. return _returnType;
  203. }
  204. }
  205. internal ConvertBinder ConvertBinder {
  206. get {
  207. return _convert;
  208. }
  209. }
  210. internal InvokeBinder InvokeBinder {
  211. get {
  212. return _invoke;
  213. }
  214. }
  215. }
  216. }