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