PageRenderTime 42ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft.Scripting/Generation/Snippets.cs

https://bitbucket.org/stefanrusek/xronos
C# | 256 lines | 173 code | 37 blank | 46 comment | 28 complexity | 7df87c9ff62eacc761944b074a9dde66 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.IO;
  21. using System.Reflection;
  22. using System.Reflection.Emit;
  23. using System.Threading;
  24. using Microsoft.Scripting.Utils;
  25. using System.Collections.Generic;
  26. namespace Microsoft.Scripting.Generation {
  27. // TODO: This should be a static class
  28. // TODO: simplify initialization logic & state
  29. public sealed class Snippets {
  30. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
  31. public static readonly Snippets Shared = new Snippets();
  32. private Snippets() { }
  33. private int _methodNameIndex;
  34. private AssemblyGen _assembly;
  35. private AssemblyGen _debugAssembly;
  36. // TODO: options should be internal
  37. private string _snippetsDirectory;
  38. private bool _saveSnippets;
  39. /// <summary>
  40. /// Directory where snippet assembly will be saved if SaveSnippets is set.
  41. /// </summary>
  42. public string SnippetsDirectory {
  43. get { return _snippetsDirectory; }
  44. }
  45. /// <summary>
  46. /// Save snippets to an assembly (see also SnippetsDirectory, SnippetsFileName).
  47. /// </summary>
  48. public bool SaveSnippets {
  49. get { return _saveSnippets; }
  50. }
  51. private AssemblyGen GetAssembly(bool emitSymbols) {
  52. return (emitSymbols) ?
  53. GetOrCreateAssembly(emitSymbols, ref _debugAssembly) :
  54. GetOrCreateAssembly(emitSymbols, ref _assembly);
  55. }
  56. private AssemblyGen GetOrCreateAssembly(bool emitSymbols, ref AssemblyGen assembly) {
  57. if (assembly == null) {
  58. string suffix = (emitSymbols) ? ".debug" : "";
  59. suffix += ".scripting";
  60. Interlocked.CompareExchange(ref assembly, CreateNewAssembly(suffix, emitSymbols), null);
  61. }
  62. return assembly;
  63. }
  64. private AssemblyGen CreateNewAssembly(string nameSuffix, bool emitSymbols) {
  65. string dir;
  66. if (_saveSnippets) {
  67. dir = _snippetsDirectory ?? Directory.GetCurrentDirectory();
  68. } else {
  69. dir = null;
  70. }
  71. string name = "Snippets" + nameSuffix;
  72. return new AssemblyGen(new AssemblyName(name), dir, ".dll", emitSymbols);
  73. }
  74. internal string GetMethodILDumpFile(MethodBase method) {
  75. string fullName = ((method.DeclaringType != null) ? method.DeclaringType.Name + "." : "") + method.Name;
  76. if (fullName.Length > 100) {
  77. fullName = fullName.Substring(0, 100);
  78. }
  79. string filename = String.Format("{0}_{1}.il", IOUtils.ToValidFileName(fullName), Interlocked.Increment(ref _methodNameIndex));
  80. string dir = _snippetsDirectory ?? Path.Combine(Path.GetTempPath(), "__DLRIL");
  81. Directory.CreateDirectory(dir);
  82. return Path.Combine(dir, filename);
  83. }
  84. public static void SetSaveAssemblies(bool enable, string directory) {
  85. //Set SaveAssemblies on for inner ring by calling SetSaveAssemblies via Reflection.
  86. #if CODEPLEX_40
  87. Assembly core = typeof(System.Linq.Expressions.Expression).Assembly;
  88. Type assemblyGen = core.GetType("System.Linq.Expressions.Compiler.AssemblyGen");
  89. #else
  90. Assembly core = typeof(Microsoft.Linq.Expressions.Expression).Assembly;
  91. Type assemblyGen = core.GetType("Microsoft.Linq.Expressions.Compiler.AssemblyGen");
  92. #endif
  93. //The type may not exist.
  94. if (assemblyGen != null) {
  95. MethodInfo configSaveAssemblies = assemblyGen.GetMethod("SetSaveAssemblies", BindingFlags.NonPublic | BindingFlags.Static);
  96. //The method may not exist.
  97. if (configSaveAssemblies != null) {
  98. string[] coreAssemblyLocations = (string[])configSaveAssemblies.Invoke(null, new object[] { enable, directory });
  99. }
  100. }
  101. Shared.ConfigureSaveAssemblies(enable, directory);
  102. }
  103. private void ConfigureSaveAssemblies(bool enable, string directory) {
  104. _saveSnippets = enable;
  105. _snippetsDirectory = directory;
  106. }
  107. public static void SaveAndVerifyAssemblies() {
  108. if (!Shared.SaveSnippets) {
  109. return;
  110. }
  111. // Invoke the core AssemblyGen.SaveAssembliesToDisk via reflection to get the locations of assemlies
  112. // to be verified. Verify them using PEVerify.exe.
  113. // Do this before verifying outer ring assemblies because they will depend on
  114. // the core ones.
  115. // The order needs to be
  116. // 1) Save inner ring assemblies.
  117. // 2) Save outer ring assemblies. This has to happen before verifying inner ring assemblies because
  118. // inner ring assemblies have dependency on outer ring assemlies via generated IL.
  119. // 3) Verify inner ring assemblies.
  120. // 4) Verify outer ring assemblies.
  121. #if CODEPLEX_40
  122. Assembly core = typeof(System.Linq.Expressions.Expression).Assembly;
  123. Type assemblyGen = core.GetType("System.Linq.Expressions.Compiler.AssemblyGen");
  124. #else
  125. Assembly core = typeof(Microsoft.Linq.Expressions.Expression).Assembly;
  126. Type assemblyGen = core.GetType("Microsoft.Linq.Expressions.Compiler.AssemblyGen");
  127. #endif
  128. //The type may not exist.
  129. string[] coreAssemblyLocations = null;
  130. if (assemblyGen != null) {
  131. MethodInfo saveAssemblies = assemblyGen.GetMethod("SaveAssembliesToDisk", BindingFlags.NonPublic | BindingFlags.Static);
  132. //The method may not exist.
  133. if (saveAssemblies != null) {
  134. coreAssemblyLocations = (string[])saveAssemblies.Invoke(null, null);
  135. }
  136. }
  137. string[] outerAssemblyLocations = Shared.SaveAssemblies();
  138. if (coreAssemblyLocations != null) {
  139. foreach (var file in coreAssemblyLocations) {
  140. AssemblyGen.PeVerifyAssemblyFile(file);
  141. }
  142. }
  143. //verify outer ring assemblies
  144. foreach (var file in outerAssemblyLocations) {
  145. AssemblyGen.PeVerifyAssemblyFile(file);
  146. }
  147. }
  148. // Return the assembly locations that need to be verified
  149. private string[] SaveAssemblies() {
  150. if (!SaveSnippets) {
  151. return new string[0];
  152. }
  153. List<string> assemlyLocations = new List<string>();
  154. // first save all assemblies to disk:
  155. if (_assembly != null) {
  156. string assemblyLocation = _assembly.SaveAssembly();
  157. if (assemblyLocation != null) {
  158. assemlyLocations.Add(assemblyLocation);
  159. }
  160. _assembly = null;
  161. }
  162. if (_debugAssembly != null) {
  163. string debugAssemblyLocation = _debugAssembly.SaveAssembly();
  164. if (debugAssemblyLocation != null) {
  165. assemlyLocations.Add(debugAssemblyLocation);
  166. }
  167. _debugAssembly = null;
  168. }
  169. return assemlyLocations.ToArray();
  170. }
  171. public DynamicILGen CreateDynamicMethod(string methodName, Type returnType, Type[] parameterTypes, bool isDebuggable) {
  172. ContractUtils.RequiresNotEmpty(methodName, "methodName");
  173. ContractUtils.RequiresNotNull(returnType, "returnType");
  174. ContractUtils.RequiresNotNullItems(parameterTypes, "parameterTypes");
  175. if (Snippets.Shared.SaveSnippets) {
  176. AssemblyGen assembly = GetAssembly(isDebuggable);
  177. TypeBuilder tb = assembly.DefinePublicType(methodName, typeof(object), false);
  178. MethodBuilder mb = tb.DefineMethod(methodName, CompilerHelpers.PublicStatic, returnType, parameterTypes);
  179. return new DynamicILGenType(tb, mb, mb.GetILGenerator());
  180. } else {
  181. DynamicMethod dm = RawCreateDynamicMethod(methodName, returnType, parameterTypes);
  182. return new DynamicILGenMethod(dm, dm.GetILGenerator());
  183. }
  184. }
  185. public TypeBuilder DefinePublicType(string name, Type parent) {
  186. return GetAssembly(false).DefinePublicType(name, parent, false);
  187. }
  188. public TypeGen DefineType(string name, Type parent, bool preserveName, bool emitDebugSymbols) {
  189. AssemblyGen ag = GetAssembly(emitDebugSymbols);
  190. TypeBuilder tb = ag.DefinePublicType(name, parent, preserveName);
  191. return new TypeGen(ag, tb);
  192. }
  193. internal DynamicMethod CreateDynamicMethod(string name, Type returnType, Type[] parameterTypes) {
  194. string uniqueName = name + "##" + Interlocked.Increment(ref _methodNameIndex);
  195. return RawCreateDynamicMethod(uniqueName, returnType, parameterTypes);
  196. }
  197. public TypeBuilder DefineDelegateType(string name) {
  198. AssemblyGen assembly = GetAssembly(false);
  199. return assembly.DefineType(
  200. name,
  201. typeof(MulticastDelegate),
  202. TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass,
  203. false
  204. );
  205. }
  206. private static DynamicMethod RawCreateDynamicMethod(string name, Type returnType, Type[] parameterTypes) {
  207. #if SILVERLIGHT // Module-hosted DynamicMethod is not available in SILVERLIGHT
  208. return new DynamicMethod(name, returnType, parameterTypes);
  209. #else
  210. //
  211. // WARNING: we set restrictedSkipVisibility == true (last parameter)
  212. // setting this bit will allow accessing nonpublic members
  213. // for more information see http://msdn.microsoft.com/en-us/library/bb348332.aspx
  214. //
  215. return new DynamicMethod(name, returnType, parameterTypes, true);
  216. #endif
  217. }
  218. }
  219. }