1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. 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 Apache License, Version 2.0, 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 Apache License, Version 2.0.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
18 using System.Collections.Generic;
19 using System.Dynamic.Utils;
21 using System.Reflection;
22 using System.Reflection.Emit;
23 using System.Security;
25 using System.Threading;
27 using Microsoft.Scripting.Utils;
30 namespace Microsoft.Scripting.Ast.Compiler {
32 namespace System.Linq.Expressions.Compiler {
34 internal sealed class AssemblyGen {
35 private static AssemblyGen _assembly;
37 // Testing options. Only ever set in CLR2 build
38 // configurations, see SetSaveAssemblies
40 private static string _saveAssembliesPath;
41 private static bool _saveAssemblies;
44 private readonly AssemblyBuilder _myAssembly;
45 private readonly ModuleBuilder _myModule;
47 #if !FEATURE_CORE_DLR && !SILVERLIGHT
48 private readonly string _outFileName; // can be null iff !SaveAndReloadAssemblies
49 private readonly string _outDir; // null means the current directory
53 private static AssemblyGen Assembly {
55 if (_assembly == null) {
56 Interlocked.CompareExchange(ref _assembly, new AssemblyGen(), null);
62 private AssemblyGen() {
63 var name = new AssemblyName("Snippets");
65 #if SILVERLIGHT // AssemblyBuilderAccess.RunAndSave, Environment.CurrentDirectory
66 _myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
67 _myModule = _myAssembly.DefineDynamicModule(name.Name, false);
70 // mark the assembly transparent so that it works in partial trust:
71 var attributes = new[] {
72 new CustomAttributeBuilder(typeof(SecurityTransparentAttribute).GetConstructor(ReflectionUtils.EmptyTypes), new object[0])
76 if (_saveAssemblies) {
77 string outDir = _saveAssembliesPath ?? Directory.GetCurrentDirectory();
79 outDir = Path.GetFullPath(outDir);
81 throw Error.InvalidOutputDir();
84 Path.Combine(outDir, name.Name + ".dll");
85 } catch (ArgumentException) {
86 throw Error.InvalidAsmNameOrExtension();
89 _outFileName = name.Name + ".dll";
91 _myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave, outDir,
92 null, null, null, null, false, attributes);
94 _myModule = _myAssembly.DefineDynamicModule(name.Name, _outFileName, false);
98 _myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run, attributes);
99 _myModule = _myAssembly.DefineDynamicModule(name.Name, false);
102 _myAssembly.DefineVersionInfoResource();
106 private TypeBuilder DefineType(string name, Type parent, TypeAttributes attr) {
107 ContractUtils.RequiresNotNull(name, "name");
108 ContractUtils.RequiresNotNull(parent, "parent");
110 StringBuilder sb = new StringBuilder(name);
112 int index = Interlocked.Increment(ref _index);
116 // There is a bug in Reflection.Emit that leads to
117 // Unhandled Exception: System.Runtime.InteropServices.COMException (0x80131130): Record not found on lookup.
118 // if there is any of the characters []*&+,\ in the type name and a method defined on the type is called.
119 sb.Replace('+', '_').Replace('[', '_').Replace(']', '_').Replace('*', '_').Replace('&', '_').Replace(',', '_').Replace('\\', '_');
121 name = sb.ToString();
123 return _myModule.DefineType(name, attr, parent);
126 internal static TypeBuilder DefineDelegateType(string name) {
127 return Assembly.DefineType(
129 typeof(MulticastDelegate),
130 TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass
134 #if !FEATURE_CORE_DLR
135 //Return the location of the saved assembly file.
136 //The file location is used by PE verification in Microsoft.Scripting.
137 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
138 internal string SaveAssembly() {
139 #if !SILVERLIGHT // AssemblyBuilder.Save
140 _myAssembly.Save(_outFileName, PortableExecutableKinds.ILOnly, ImageFileMachine.I386);
141 return Path.Combine(_outDir, _outFileName);
147 // NOTE: this method is called through reflection from Microsoft.Scripting
148 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
149 internal static void SetSaveAssemblies(bool enable, string directory) {
150 _saveAssemblies = enable;
151 _saveAssembliesPath = directory;
154 // NOTE: this method is called through reflection from Microsoft.Scripting
155 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
156 internal static string[] SaveAssembliesToDisk() {
157 if (!_saveAssemblies) {
158 return new string[0];
161 var assemlyLocations = new List<string>();
163 // first save all assemblies to disk:
164 if (_assembly != null) {
165 string assemblyLocation = _assembly.SaveAssembly();
166 if (assemblyLocation != null) {
167 assemlyLocations.Add(assemblyLocation);
172 return assemlyLocations.ToArray();