The Labs \ Source Viewer \ SSCLI \ System.Xml.Xsl.IlGen \ XmlILMethodAttributes

  1. //------------------------------------------------------------------------------
  2. // <copyright file="XmlILModule.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System;
  16. using System.IO;
  17. using System.Threading;
  18. using System.Reflection;
  19. using System.Reflection.Emit;
  20. using System.CodeDom.Compiler;
  21. using System.Diagnostics;
  22. using System.Collections;
  23. using System.Security;
  24. using System.Security.Policy;
  25. using System.Security.Permissions;
  26. using System.Diagnostics.SymbolStore;
  27. using System.Xml.Xsl.Runtime;
  28. namespace System.Xml.Xsl.IlGen
  29. {
  30.     using DebuggingModes = DebuggableAttribute.DebuggingModes;
  31.    
  32.     internal enum XmlILMethodAttributes
  33.     {
  34.         None = 0,
  35.         NonUser = 1,
  36.         // Non-user method which should debugger should step through
  37.         Raw = 2
  38.         // Raw method which should not add an implicit first argument of type XmlQueryRuntime
  39.     }
  40.    
  41.     internal class XmlILModule
  42.     {
  43.         private static readonly PermissionSet CreateDelegatePermissionSet;
  44.         // Permission set that contains ReflectionEmit [MemberAccess] permissions
  45.         private static readonly PermissionSet CreateModulePermissionSet;
  46.         // Permission set that contains ReflectionEmit permissions
  47.         private static readonly PermissionSet CreateMethodPermissionSet;
  48.         // Permission set that contains ReflectionEmit and ControlEvidence permissions
  49.         private static long AssemblyId;
  50.         // Unique identifier used to ensure that assembly names are unique within AppDomain
  51.         private static ModuleBuilder LREModule;
  52.         // Module used to emit dynamic lightweight-reflection-emit (LRE) methods
  53.         private TypeBuilder typeBldr;
  54.         private Hashtable methods, urlToSymWriter;
  55.         private string modFile;
  56.         private bool persistAsm, useLRE, emitSymbols;
  57.        
  58.         private static readonly Guid LanguageGuid = new Guid(1177373246, 45655, 19182, 151, 205, 89, 24, 199, 83, 23,
  59.         88);
  60.         private static readonly Guid VendorGuid = new Guid(2571847108u, 59113, 4562, 144, 63, 0, 192, 79, 163, 2,
  61.         161);
  62.         private const string RuntimeName = "{" + XmlReservedNs.NsXslDebug + "}" + "runtime";
  63.        
  64.         static XmlILModule()
  65.         {
  66.             AssemblyName asmName;
  67.             AssemblyBuilder asmBldr;
  68.            
  69.             CreateDelegatePermissionSet = new PermissionSet(PermissionState.None);
  70.             CreateDelegatePermissionSet.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.MemberAccess));
  71.            
  72.             CreateModulePermissionSet = new PermissionSet(PermissionState.None);
  73.             CreateModulePermissionSet.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.ReflectionEmit));
  74.            
  75.             CreateMethodPermissionSet = new PermissionSet(PermissionState.None);
  76.             CreateMethodPermissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.ControlEvidence));
  77.             CreateMethodPermissionSet.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.ReflectionEmit));
  78.            
  79.             AssemblyId = 0;
  80.            
  81.             // 1. LRE assembly only needs to execute
  82.             // 2. No temp files need be created
  83.             // 3. Never allow assembly to Assert permissions
  84.             asmName = CreateAssemblyName();
  85.             asmBldr = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
  86.            
  87.             // Add custom attribute to assembly marking it as security transparent so that Assert will not be allowed
  88.             // and link demands will be converted to full demands.
  89.             asmBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.Transparent, new object[] {}));
  90.            
  91.             try {
  92.                 // DefineDynamicModule demands ReflectionEmit permission
  93.                 CreateModulePermissionSet.Assert();
  94.                
  95.                 // Store LREModule once. If multiple threads are doing this, then some threads might get different
  96.                 // modules. This is OK, since it's not mandatory to share, just preferable.
  97.                 LREModule = asmBldr.DefineDynamicModule("System.Xml.Xsl.CompiledQuery", false);
  98.             }
  99.             finally {
  100.                 CodeAccessPermission.RevertAssert();
  101.             }
  102.         }
  103.        
  104.         public XmlILModule(bool useLRE, bool emitSymbols, AssemblyName asmName)
  105.         {
  106.             AssemblyBuilder asmBldr;
  107.             ModuleBuilder modBldr;
  108.             Debug.Assert(!useLRE || (!emitSymbols && (asmName == null)));
  109.            
  110.             this.useLRE = useLRE;
  111.             this.emitSymbols = emitSymbols;
  112.             this.persistAsm = (asmName != null);
  113.            
  114.             // Index all methods added to this module by unique name
  115.             this.methods = new Hashtable();
  116.            
  117.             if (!useLRE) {
  118.                 // 1. If assembly needs to support debugging, then it must be saved and re-loaded (rule of CLR)
  119.                 // 2. Get path of temp directory, where assembly will be saved
  120.                 // 3. Never allow assembly to Assert permissions
  121.                 if (asmName != null) {
  122.                     this.modFile = asmName.Name;
  123.                 }
  124.                 else {
  125.                     asmName = CreateAssemblyName();
  126.                     if (XmlILTrace.IsEnabled) {
  127.                         this.modFile = "System.Xml.Xsl.CompiledQuery";
  128.                         this.persistAsm = true;
  129.                     }
  130.                 }
  131.                
  132.                 asmBldr = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, this.persistAsm ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run);
  133.                
  134.                 // Add custom attribute to assembly marking it as security transparent so that Assert will not be allowed
  135.                 // and link demands will be converted to full demands.
  136.                 asmBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.Transparent, new object[] {}));
  137.                
  138.                 if (emitSymbols) {
  139.                     // Create mapping from source document to symbol writer
  140.                     this.urlToSymWriter = new Hashtable();
  141.                    
  142.                     // Add DebuggableAttribute to assembly so that debugging is a better experience
  143.                     DebuggingModes debuggingModes = DebuggingModes.Default | DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggingModes.DisableOptimizations;
  144.                     asmBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.Debuggable, new object[] {debuggingModes}));
  145.                 }
  146.                
  147.                 // Create ModuleBuilder
  148.                 if (this.persistAsm)
  149.                     modBldr = asmBldr.DefineDynamicModule("System.Xml.Xsl.CompiledQuery", this.modFile + ".dll", emitSymbols);
  150.                 else
  151.                     modBldr = asmBldr.DefineDynamicModule("System.Xml.Xsl.CompiledQuery", emitSymbols);
  152.                
  153.                 this.typeBldr = modBldr.DefineType("System.Xml.Xsl.CompiledQuery.Query", TypeAttributes.Public);
  154.             }
  155.         }
  156.        
  157.         /// <summary>
  158.         /// Define a method in this module with the specified name and parameters.
  159.         /// </summary>
  160.         public MethodInfo DefineMethod(string name, Type returnType, Type[] paramTypes, string[] paramNames, XmlILMethodAttributes xmlAttrs)
  161.         {
  162.             MethodInfo methResult;
  163.             int uniqueId = 1;
  164.             string nameOrig = name;
  165.             Type[] paramTypesNew;
  166.             bool isRaw = (xmlAttrs & XmlILMethodAttributes.Raw) != 0;
  167.            
  168.             // Ensure that name is unique
  169.             while (this.methods[name] != null) {
  170.                 // Add unique id to end of name in order to make it unique within this module
  171.                 uniqueId++;
  172.                 name = nameOrig + " (" + uniqueId + ")";
  173.             }
  174.            
  175.             if (!isRaw) {
  176.                 // XmlQueryRuntime is always 0th parameter
  177.                 paramTypesNew = new Type[paramTypes.Length + 1];
  178.                 paramTypesNew[0] = typeof(XmlQueryRuntime);
  179.                 Array.Copy(paramTypes, 0, paramTypesNew, 1, paramTypes.Length);
  180.                 paramTypes = paramTypesNew;
  181.             }
  182.            
  183.             if (!this.useLRE) {
  184.                 MethodBuilder methBldr;
  185.                
  186.                 methBldr = this.typeBldr.DefineMethod(name, MethodAttributes.Public | MethodAttributes.Static, returnType, paramTypes);
  187.                
  188.                 if (emitSymbols && (xmlAttrs & XmlILMethodAttributes.NonUser) != 0) {
  189.                     // Add DebuggerStepThroughAttribute and DebuggerNonUserCodeAttribute to non-user methods so that debugging is a better experience
  190.                     methBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.StepThrough, new object[] {}));
  191.                     methBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.NonUserCode, new object[] {}));
  192.                 }
  193.                
  194.                 if (!isRaw)
  195.                     methBldr.DefineParameter(1, ParameterAttributes.None, RuntimeName);
  196.                
  197.                 for (int i = 0; i < paramNames.Length; i++) {
  198.                     if (paramNames[i] != null && paramNames[i].Length != 0)
  199.                         methBldr.DefineParameter(i + (isRaw ? 1 : 2), ParameterAttributes.None, paramNames[i]);
  200.                 }
  201.                
  202.                 methResult = methBldr;
  203.             }
  204.             else {
  205.                 try {
  206.                     // DynamicMethod constructor demands ReflectionEmit and ControlEvidence permission
  207.                     CreateMethodPermissionSet.Assert();
  208.                    
  209.                     DynamicMethod methDyn = new DynamicMethod(name, returnType, paramTypes, LREModule);
  210.                     methDyn.InitLocals = true;
  211.                    
  212.                     if (!isRaw)
  213.                         methDyn.DefineParameter(1, ParameterAttributes.None, RuntimeName);
  214.                    
  215.                     for (int i = 0; i < paramNames.Length; i++) {
  216.                         if (paramNames[i] != null && paramNames[i].Length != 0)
  217.                             methDyn.DefineParameter(i + (isRaw ? 1 : 2), ParameterAttributes.None, paramNames[i]);
  218.                     }
  219.                    
  220.                     methResult = methDyn;
  221.                 }
  222.                 finally {
  223.                     CodeAccessPermission.RevertAssert();
  224.                 }
  225.             }
  226.            
  227.             // Index method by name
  228.             this.methods[name] = methResult;
  229.             return methResult;
  230.         }
  231.        
  232.         /// <summary>
  233.         /// Get an XmlILGenerator that can be used to generate the body of the specified method.
  234.         /// </summary>
  235.         public static ILGenerator DefineMethodBody(MethodInfo methInfo)
  236.         {
  237.             DynamicMethod methDyn = methInfo as DynamicMethod;
  238.            
  239.             if (methDyn != null)
  240.                 return methDyn.GetILGenerator();
  241.            
  242.             return ((MethodBuilder)methInfo).GetILGenerator();
  243.         }
  244.        
  245.         /// <summary>
  246.         /// Find a MethodInfo of the specified name and return it. Return null if no such method exists.
  247.         /// </summary>
  248.         public MethodInfo FindMethod(string name)
  249.         {
  250.             return (MethodInfo)this.methods[name];
  251.         }
  252.        
  253.         /// <summary>
  254.         /// Add the file name of a document containing source code for this module and return a symbol writer.
  255.         /// </summary>
  256.         public ISymbolDocumentWriter AddSourceDocument(string fileName)
  257.         {
  258.             ISymbolDocumentWriter symDoc;
  259.             Debug.Assert(this.emitSymbols, "Cannot add source information to a module that doesn't allow symbols.");
  260.            
  261.             symDoc = this.urlToSymWriter[fileName] as ISymbolDocumentWriter;
  262.             if (symDoc == null) {
  263.                 symDoc = ((ModuleBuilder)this.typeBldr.Module).DefineDocument(fileName, LanguageGuid, VendorGuid, Guid.Empty);
  264.                 this.urlToSymWriter.Add(fileName, symDoc);
  265.             }
  266.            
  267.             return symDoc;
  268.         }
  269.        
  270.         /// <summary>
  271.         /// Once all methods have been defined, CreateModule must be called in order to "bake" the methods within
  272.         /// this module.
  273.         /// </summary>
  274.         public void BakeMethods()
  275.         {
  276.             Type typBaked;
  277.             Hashtable methodsBaked;
  278.            
  279.             if (!this.useLRE) {
  280.                 typBaked = this.typeBldr.CreateType();
  281.                
  282.                 if (this.persistAsm) {
  283.                     // Persist the assembly to disk
  284.                     ((AssemblyBuilder)this.typeBldr.Module.Assembly).Save(this.modFile + ".dll");
  285.                 }
  286.                
  287.                 // Replace all MethodInfos in this.methods
  288.                 methodsBaked = new Hashtable(this.methods.Count);
  289.                 foreach (string methName in this.methods.Keys) {
  290.                     methodsBaked[methName] = typBaked.GetMethod(methName);
  291.                 }
  292.                 this.methods = methodsBaked;
  293.                
  294.                 // Release TypeBuilder and symbol writer resources
  295.                 this.typeBldr = null;
  296.                 this.urlToSymWriter = null;
  297.             }
  298.         }
  299.        
  300.         /// <summary>
  301.         /// Wrap a delegate around a MethodInfo of the specified name and type and return it.
  302.         /// </summary>
  303.         public Delegate CreateDelegate(string name, Type typDelegate)
  304.         {
  305.             try {
  306.                 // CreateDelegate demands MemberAccess permission
  307.                 CreateDelegatePermissionSet.Assert();
  308.                
  309.                 if (!this.useLRE)
  310.                     return Delegate.CreateDelegate(typDelegate, (MethodInfo)this.methods[name]);
  311.                
  312.                 return ((DynamicMethod)this.methods[name]).CreateDelegate(typDelegate);
  313.             }
  314.             finally {
  315.                 CodeAccessPermission.RevertAssert();
  316.             }
  317.         }
  318.        
  319.         /// <summary>
  320.         /// Define unique assembly name (within AppDomain).
  321.         /// </summary>
  322.         private static AssemblyName CreateAssemblyName()
  323.         {
  324.             AssemblyName name;
  325.            
  326.             Interlocked.Increment(ref AssemblyId);
  327.             name = new AssemblyName();
  328.             name.Name = "System.Xml.Xsl.CompiledQuery." + AssemblyId;
  329.            
  330.             return name;
  331.         }
  332.     }
  333. }

Developer Fusion