xronos /Microsoft.Scripting/Generation/Snippets.cs

Language C# Lines 257
MD5 Hash 7df87c9ff62eacc761944b074a9dde66 Estimated Cost $4,281 (why?)
Repository https://bitbucket.org/stefanrusek/xronos View Raw File
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 *
 * ***************************************************************************/

#if CODEPLEX_40
using System;
#else
using System; using Microsoft;
#endif
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
using Microsoft.Scripting.Utils;
using System.Collections.Generic;

namespace Microsoft.Scripting.Generation {

    // TODO: This should be a static class
    // TODO: simplify initialization logic & state
    public sealed class Snippets {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
        public static readonly Snippets Shared = new Snippets();

        private Snippets() { }
        
        private int _methodNameIndex;

        private AssemblyGen _assembly;
        private AssemblyGen _debugAssembly;

        // TODO: options should be internal
        private string _snippetsDirectory;
        private bool _saveSnippets;

        /// <summary>
        /// Directory where snippet assembly will be saved if SaveSnippets is set.
        /// </summary>
        public string SnippetsDirectory {
            get { return _snippetsDirectory; }
        }

        /// <summary>
        /// Save snippets to an assembly (see also SnippetsDirectory, SnippetsFileName).
        /// </summary>
        public bool SaveSnippets {
            get { return _saveSnippets; }
        }

        private AssemblyGen GetAssembly(bool emitSymbols) {
            return (emitSymbols) ?
                GetOrCreateAssembly(emitSymbols,  ref _debugAssembly) :
                GetOrCreateAssembly(emitSymbols, ref _assembly);
        }

        private AssemblyGen GetOrCreateAssembly(bool emitSymbols, ref AssemblyGen assembly) {
            if (assembly == null) {
                string suffix = (emitSymbols) ? ".debug" : "";
                suffix += ".scripting";
                Interlocked.CompareExchange(ref assembly, CreateNewAssembly(suffix, emitSymbols), null);
            }
            return assembly;
        }

        private AssemblyGen CreateNewAssembly(string nameSuffix, bool emitSymbols) {
            string dir;

            if (_saveSnippets) {
                dir = _snippetsDirectory ?? Directory.GetCurrentDirectory();
            } else {
                dir = null;
            }

            string name = "Snippets" + nameSuffix;

            return new AssemblyGen(new AssemblyName(name), dir, ".dll", emitSymbols);
        }

        internal string GetMethodILDumpFile(MethodBase method) {
            string fullName = ((method.DeclaringType != null) ? method.DeclaringType.Name + "." : "") + method.Name;

            if (fullName.Length > 100) {
                fullName = fullName.Substring(0, 100);
            }

            string filename = String.Format("{0}_{1}.il", IOUtils.ToValidFileName(fullName), Interlocked.Increment(ref _methodNameIndex));

            string dir = _snippetsDirectory ?? Path.Combine(Path.GetTempPath(), "__DLRIL");
            Directory.CreateDirectory(dir);
            return Path.Combine(dir, filename);
        }

        public static void SetSaveAssemblies(bool enable, string directory) {
            //Set SaveAssemblies on for inner ring by calling SetSaveAssemblies via Reflection.
#if CODEPLEX_40
            Assembly core = typeof(System.Linq.Expressions.Expression).Assembly;
            Type assemblyGen = core.GetType("System.Linq.Expressions.Compiler.AssemblyGen");
#else
            Assembly core = typeof(Microsoft.Linq.Expressions.Expression).Assembly;
            Type assemblyGen = core.GetType("Microsoft.Linq.Expressions.Compiler.AssemblyGen");
#endif
            //The type may not exist.
            if (assemblyGen != null) {
                MethodInfo configSaveAssemblies = assemblyGen.GetMethod("SetSaveAssemblies", BindingFlags.NonPublic | BindingFlags.Static);
                //The method may not exist.
                if (configSaveAssemblies != null) {
                    string[] coreAssemblyLocations = (string[])configSaveAssemblies.Invoke(null, new object[] { enable, directory });
                }
            }
            Shared.ConfigureSaveAssemblies(enable, directory);
        }

        private void ConfigureSaveAssemblies(bool enable, string directory) {
            _saveSnippets = enable;
            _snippetsDirectory = directory;
        }

        public static void SaveAndVerifyAssemblies() {
            if (!Shared.SaveSnippets) {
                return;
            }
            // Invoke the core AssemblyGen.SaveAssembliesToDisk via reflection to get the locations of assemlies
            // to be verified. Verify them using PEVerify.exe.
            // Do this before verifying outer ring assemblies because they will depend on
            // the core ones.
            // The order needs to be
            // 1) Save inner ring assemblies.
            // 2) Save outer ring assemblies. This has to happen before verifying inner ring assemblies because
            //    inner ring assemblies have dependency on outer ring assemlies via generated IL.
            // 3) Verify inner ring assemblies.
            // 4) Verify outer ring assemblies.
#if CODEPLEX_40
            Assembly core = typeof(System.Linq.Expressions.Expression).Assembly;
            Type assemblyGen = core.GetType("System.Linq.Expressions.Compiler.AssemblyGen");
#else
            Assembly core = typeof(Microsoft.Linq.Expressions.Expression).Assembly;
            Type assemblyGen = core.GetType("Microsoft.Linq.Expressions.Compiler.AssemblyGen");
#endif
            //The type may not exist.
            string[] coreAssemblyLocations = null;
            if (assemblyGen != null) {
                MethodInfo saveAssemblies = assemblyGen.GetMethod("SaveAssembliesToDisk", BindingFlags.NonPublic | BindingFlags.Static);
                //The method may not exist.
                if (saveAssemblies != null) {
                    coreAssemblyLocations = (string[])saveAssemblies.Invoke(null, null);
                }
            }

            string[] outerAssemblyLocations = Shared.SaveAssemblies();

            if (coreAssemblyLocations != null) {
                foreach (var file in coreAssemblyLocations) {
                    AssemblyGen.PeVerifyAssemblyFile(file);
                }
            }
            //verify outer ring assemblies
            foreach (var file in outerAssemblyLocations) {
                AssemblyGen.PeVerifyAssemblyFile(file);
            }
        }

        // Return the assembly locations that need to be verified
        private string[] SaveAssemblies() {
            if (!SaveSnippets) {
                return new string[0];
            }

            List<string> assemlyLocations = new List<string>();

            // first save all assemblies to disk:
            if (_assembly != null) {
                string assemblyLocation = _assembly.SaveAssembly();
                if (assemblyLocation != null) {
                    assemlyLocations.Add(assemblyLocation);
                }
                _assembly = null;
            }

            if (_debugAssembly != null) {
                string debugAssemblyLocation = _debugAssembly.SaveAssembly();
                if (debugAssemblyLocation != null) {
                    assemlyLocations.Add(debugAssemblyLocation);
                }
                _debugAssembly = null;
            }

            return assemlyLocations.ToArray();
        }

        public DynamicILGen CreateDynamicMethod(string methodName, Type returnType, Type[] parameterTypes, bool isDebuggable) {

            ContractUtils.RequiresNotEmpty(methodName, "methodName");
            ContractUtils.RequiresNotNull(returnType, "returnType");
            ContractUtils.RequiresNotNullItems(parameterTypes, "parameterTypes");

            if (Snippets.Shared.SaveSnippets) {
                AssemblyGen assembly = GetAssembly(isDebuggable);
                TypeBuilder tb = assembly.DefinePublicType(methodName, typeof(object), false);
                MethodBuilder mb = tb.DefineMethod(methodName, CompilerHelpers.PublicStatic, returnType, parameterTypes);
                return new DynamicILGenType(tb, mb, mb.GetILGenerator());
            } else {
                DynamicMethod dm = RawCreateDynamicMethod(methodName, returnType, parameterTypes);
                return new DynamicILGenMethod(dm, dm.GetILGenerator());
            }
        }

        public TypeBuilder DefinePublicType(string name, Type parent) {
            return GetAssembly(false).DefinePublicType(name, parent, false);
        }

        public TypeGen DefineType(string name, Type parent, bool preserveName, bool emitDebugSymbols) {
            AssemblyGen ag = GetAssembly(emitDebugSymbols);
            TypeBuilder tb = ag.DefinePublicType(name, parent, preserveName);
            return new TypeGen(ag, tb);
        }

        internal DynamicMethod CreateDynamicMethod(string name, Type returnType, Type[] parameterTypes) {
            string uniqueName = name + "##" + Interlocked.Increment(ref _methodNameIndex);
            return RawCreateDynamicMethod(uniqueName, returnType, parameterTypes);
        }

        public TypeBuilder DefineDelegateType(string name) {
            AssemblyGen assembly = GetAssembly(false);
            return assembly.DefineType(
                name,
                typeof(MulticastDelegate),
                TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass,
                false
            );
        }

        private static DynamicMethod RawCreateDynamicMethod(string name, Type returnType, Type[] parameterTypes) {
#if SILVERLIGHT // Module-hosted DynamicMethod is not available in SILVERLIGHT
            return new DynamicMethod(name, returnType, parameterTypes);
#else
            //
            // WARNING: we set restrictedSkipVisibility == true  (last parameter)
            //          setting this bit will allow accessing nonpublic members
            //          for more information see http://msdn.microsoft.com/en-us/library/bb348332.aspx
            //
            return new DynamicMethod(name, returnType, parameterTypes, true);
#endif
        }
    }
}
Back to Top