Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / XmlUtils / System / Xml / Xsl / XmlIlGenerator.cs / 1 / XmlIlGenerator.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //[....] //----------------------------------------------------------------------------- using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Security; using System.Xml.XPath; using System.Xml.Xsl.IlGen; using System.Xml.Xsl.Qil; using System.Xml.Xsl.Runtime; namespace System.Xml.Xsl { internal delegate void ExecuteDelegate(XmlQueryRuntime runtime); ////// This internal class is the entry point for creating Msil assemblies from QilExpression. /// ////// Generate will return an AssemblyBuilder with the following setup: /// Assembly Name = "MS.Internal.Xml.CompiledQuery" /// Module Dll Name = "MS.Internal.Xml.CompiledQuery.dll" /// public class MS.Internal.Xml.CompiledQuery.Test { /// public static void Execute(XmlQueryRuntime runtime); /// public static void Root(XmlQueryRuntime runtime); /// private static ... UserMethod1(XmlQueryRuntime runtime, ...); /// ... /// private static ... UserMethodN(XmlQueryRuntime runtime, ...); /// } /// /// XmlILGenerator incorporates a number of different technologies in order to generate efficient code that avoids caching /// large result sets in memory: /// /// 1. Code Iterators - Query results are computed using a set of composable, interlocking iterators that alone perform a /// simple task, but together execute complex queries. The iterators are actually little blocks of code /// that are connected to each other using a series of jumps. Because each iterator is not instantiated /// as a separate object, the number of objects and number of function calls is kept to a minimum during /// execution. Also, large result sets are often computed incrementally, with each iterator performing one step in a /// pipeline of sequence items. /// /// 2. Analyzers - During code generation, QilToMsil traverses the semantic tree representation of the query (QIL) several times. /// As visits to each node in the tree start and end, various Analyzers are invoked. These Analyzers incrementally /// collect and store information that is later used to generate faster and smaller code. /// internal class XmlILGenerator { private QilExpression qil; private GenerateHelper helper; private XmlILOptimizerVisitor optVisitor; private XmlILVisitor xmlIlVisitor; private XmlILModule module; ////// Always output debug information in debug mode. /// public XmlILGenerator() { } ////// Given the logical query plan (QilExpression) generate a physical query plan (MSIL) that can be executed. /// public XmlILCommand Generate(QilExpression query, TypeBuilder typeBldr) { MethodInfo methRoot, methExec; bool useLRE, emitSymbols; XmlQueryStaticData staticData; ExecuteDelegate delExec; XmlILMethodAttributes methAttrs; this.qil = query; useLRE = !this.qil.IsDebug && (typeBldr == null); emitSymbols = this.qil.IsDebug; // In debug code, ensure that input QIL is correct QilValidationVisitor.Validate(this.qil); // Trace Qil before optimization XmlILTrace.WriteQil(this.qil, "qilbefore.xml"); // Trace optimizations XmlILTrace.TraceOptimizations(this.qil, "qilopt.xml"); if (XmlILTrace.IsEnabled) { // Dump assembly to disk; can't do this when using LRE useLRE = false; } // Optimize and annotate the Qil graph this.optVisitor = new XmlILOptimizerVisitor(this.qil, !this.qil.IsDebug); this.qil = this.optVisitor.Optimize(); // In debug code, ensure that output QIL is correct QilValidationVisitor.Validate(this.qil); // Trace Qil after optimization XmlILTrace.WriteQil(this.qil, "qilafter.xml"); try { XmlILModule.CreateModulePermissionSet.Assert(); // Create module in which methods will be generated if (typeBldr != null) this.module = new XmlILModule(typeBldr); else this.module = new XmlILModule(useLRE, emitSymbols); // Create a code generation helper for the module; enable optimizations if IsDebug is false this.helper = new GenerateHelper(this.module, this.qil.IsDebug); // Create helper methods CreateHelperFunctions(); // Create metadata for the Execute function, which is the entry point to the query // public static void Execute(XmlQueryRuntime); methExec = this.module.DefineMethod("Execute", typeof(void), new Type[] {}, new string[] {}, XmlILMethodAttributes.NonUser); // Create metadata for the root expression // public void Root() Debug.Assert(this.qil.Root != null); methAttrs = (this.qil.Root.SourceLine == null) ? XmlILMethodAttributes.NonUser : XmlILMethodAttributes.None; methRoot = this.module.DefineMethod("Root", typeof(void), new Type[] {}, new string[] {}, methAttrs); // Declare all early bound function objects foreach (EarlyBoundInfo info in this.qil.EarlyBoundTypes) this.helper.StaticData.DeclareEarlyBound(info.NamespaceUri, info.EarlyBoundType); // Create metadata for each QilExpression function that has at least one caller CreateFunctionMetadata(this.qil.FunctionList); // Create metadata for each QilExpression global variable and parameter CreateGlobalValueMetadata(this.qil.GlobalVariableList); CreateGlobalValueMetadata(this.qil.GlobalParameterList); // Generate Execute method GenerateExecuteFunction(methExec, methRoot); // Visit the QilExpression graph this.xmlIlVisitor = new XmlILVisitor(); this.xmlIlVisitor.Visit(this.qil, this.helper, methRoot); // Collect all static information required by the runtime staticData = new XmlQueryStaticData( this.qil.DefaultWriterSettings, this.qil.WhitespaceRules, this.helper.StaticData); // Create static constructor that initializes XmlQueryStaticData instance at runtime if (typeBldr != null) CreateTypeInitializer(staticData); // Finish up creation of the type this.module.BakeMethods(); // Create delegate over "Execute" method delExec = (ExecuteDelegate) this.module.CreateDelegate("Execute", typeof(ExecuteDelegate)); return new XmlILCommand(delExec, staticData); } finally { CodeAccessPermission.RevertAssert(); } } ////// Create MethodBuilder metadata for the specified QilExpression function. Annotate ndFunc with the /// MethodBuilder. Also, each QilExpression argument type should be converted to a corresponding Clr type. /// Each argument QilExpression node should be annotated with the resulting ParameterBuilder. /// private void CreateFunctionMetadata(IListfuncList) { MethodInfo methInfo; Type[] paramTypes; string[] paramNames; Type typReturn; XmlILMethodAttributes methAttrs; foreach (QilFunction ndFunc in funcList) { paramTypes = new Type[ndFunc.Arguments.Count]; paramNames = new string[ndFunc.Arguments.Count]; // Loop through all other parameters and save their types in the array for (int arg = 0; arg < ndFunc.Arguments.Count; arg ++) { QilParameter ndParam = (QilParameter) ndFunc.Arguments[arg]; Debug.Assert(ndParam.NodeType == QilNodeType.Parameter); // Get the type of each argument as a Clr type paramTypes[arg] = XmlILTypeHelper.GetStorageType(ndParam.XmlType); // Get the name of each argument if (ndParam.DebugName != null) paramNames[arg] = ndParam.DebugName; } // Get the type of the return value if (XmlILConstructInfo.Read(ndFunc).PushToWriterLast) { // Push mode functions do not have a return value typReturn = typeof(void); } else { // Pull mode functions have a return value typReturn = XmlILTypeHelper.GetStorageType(ndFunc.XmlType); } // Create the method metadata methAttrs = ndFunc.SourceLine == null ? XmlILMethodAttributes.NonUser : XmlILMethodAttributes.None; methInfo = this.module.DefineMethod(ndFunc.DebugName, typReturn, paramTypes, paramNames, methAttrs); for (int arg = 0; arg < ndFunc.Arguments.Count; arg ++) { // Set location of parameter on Let node annotation XmlILAnnotation.Write(ndFunc.Arguments[arg]).ArgumentPosition = arg; } // Annotate function with the MethodInfo XmlILAnnotation.Write(ndFunc).FunctionBinding = methInfo; } } /// /// Generate metadata for a method that calculates a global value. /// private void CreateGlobalValueMetadata(IListglobalList) { MethodInfo methInfo; Type typReturn; XmlILMethodAttributes methAttrs; foreach (QilReference ndRef in globalList) { // public T GlobalValue() typReturn = XmlILTypeHelper.GetStorageType(ndRef.XmlType); methAttrs = ndRef.SourceLine == null ? XmlILMethodAttributes.NonUser : XmlILMethodAttributes.None; methInfo = this.module.DefineMethod(ndRef.DebugName.ToString(), typReturn, new Type[] {}, new string[] {}, methAttrs); // Annotate function with MethodBuilder XmlILAnnotation.Write(ndRef).FunctionBinding = methInfo; } } /// /// Generate the "Execute" method, which is the entry point to the query. /// private MethodInfo GenerateExecuteFunction(MethodInfo methExec, MethodInfo methRoot) { this.helper.MethodBegin(methExec, null, false); // Force some or all global values to be evaluated at start of query EvaluateGlobalValues(this.qil.GlobalVariableList); EvaluateGlobalValues(this.qil.GlobalParameterList); // Root(runtime); this.helper.LoadQueryRuntime(); this.helper.Call(methRoot); this.helper.MethodEnd(); return methExec; } ////// Create and generate various helper methods, which are called by the generated code. /// private void CreateHelperFunctions() { MethodInfo meth; Label lblClone; // public static XPathNavigator SyncToNavigator(XPathNavigator, XPathNavigator); meth = this.module.DefineMethod( "SyncToNavigator", typeof(XPathNavigator), new Type[] {typeof(XPathNavigator), typeof(XPathNavigator)}, new string[] {null, null}, XmlILMethodAttributes.NonUser | XmlILMethodAttributes.Raw); this.helper.MethodBegin(meth, null, false); // if (navigatorThis != null && navigatorThis.MoveTo(navigatorThat)) // return navigatorThis; lblClone = this.helper.DefineLabel(); this.helper.Emit(OpCodes.Ldarg_0); this.helper.Emit(OpCodes.Brfalse, lblClone); this.helper.Emit(OpCodes.Ldarg_0); this.helper.Emit(OpCodes.Ldarg_1); this.helper.Call(XmlILMethods.NavMoveTo); this.helper.Emit(OpCodes.Brfalse, lblClone); this.helper.Emit(OpCodes.Ldarg_0); this.helper.Emit(OpCodes.Ret); // LabelClone: // return navigatorThat.Clone(); this.helper.MarkLabel(lblClone); this.helper.Emit(OpCodes.Ldarg_1); this.helper.Call(XmlILMethods.NavClone); this.helper.MethodEnd(); } ////// Generate code to force evaluation of some or all global variables and/or parameters. /// private void EvaluateGlobalValues(IListiterList) { MethodInfo methInfo; foreach (QilIterator ndIter in iterList) { // Evaluate global if generating debug code, or if global might have side effects if (this.qil.IsDebug || OptimizerPatterns.Read(ndIter).MatchesPattern(OptimizerPatternName.MaybeSideEffects)) { // Get MethodInfo that evaluates the global value and discard its return value methInfo = XmlILAnnotation.Write(ndIter).FunctionBinding; Debug.Assert(methInfo != null, "MethodInfo for global value should have been created previously."); this.helper.LoadQueryRuntime(); this.helper.Call(methInfo); this.helper.Emit(OpCodes.Pop); } } } /// /// Create static constructor that initializes XmlQueryStaticData instance at runtime. /// public void CreateTypeInitializer(XmlQueryStaticData staticData) { byte[] data; Type[] ebTypes; FieldInfo fldInitData, fldData, fldTypes; ConstructorInfo cctor; staticData.GetObjectData(out data, out ebTypes); fldInitData = this.module.DefineInitializedData("__" + XmlQueryStaticData.DataFieldName, data); fldData = this.module.DefineField(XmlQueryStaticData.DataFieldName, typeof(object)); fldTypes = this.module.DefineField(XmlQueryStaticData.TypesFieldName, typeof(Type[])); cctor = this.module.DefineTypeInitializer(); this.helper.MethodBegin(cctor, null, false); // s_data = new byte[s_initData.Length] { s_initData }; this.helper.LoadInteger(data.Length); this.helper.Emit(OpCodes.Newarr, typeof(byte)); this.helper.Emit(OpCodes.Dup); this.helper.Emit(OpCodes.Ldtoken, fldInitData); this.helper.Call(XmlILMethods.InitializeArray); this.helper.Emit(OpCodes.Stsfld, fldData); if (ebTypes != null) { // Type[] types = new Type[s_ebTypes.Length]; LocalBuilder locTypes = this.helper.DeclareLocal("$$$types", typeof(Type[])); this.helper.LoadInteger(ebTypes.Length); this.helper.Emit(OpCodes.Newarr, typeof(Type)); this.helper.Emit(OpCodes.Stloc, locTypes); for (int idx = 0; idx < ebTypes.Length; idx++) { // types[idx] = ebTypes[idx]; this.helper.Emit(OpCodes.Ldloc, locTypes); this.helper.LoadInteger(idx); this.helper.LoadType(ebTypes[idx]); this.helper.Emit(OpCodes.Stelem_Ref); } // s_types = types; this.helper.Emit(OpCodes.Ldloc, locTypes); this.helper.Emit(OpCodes.Stsfld, fldTypes); } this.helper.MethodEnd(); } } ////// This is the executable command generated by the XmlILGenerator. /// internal class XmlILCommand : XmlCommand { private ExecuteDelegate delExec; private XmlQueryStaticData staticData; ////// Constructor. /// public XmlILCommand(ExecuteDelegate delExec, XmlQueryStaticData staticData) { Debug.Assert(delExec != null && staticData != null); this.delExec = delExec; this.staticData = staticData; } ////// Return execute delegate. /// public ExecuteDelegate ExecuteDelegate { get { return delExec; } } ////// Return query static data required by the runtime. /// public XmlQueryStaticData StaticData { get { return staticData; } } ////// Default document as XPathNavigator. /// public override void Execute(IXPathNavigable contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlWriter results) { if (results == null) throw new ArgumentNullException("results"); if (contextDocument != null) Execute(contextDocument.CreateNavigator(), dataSources, argumentList, results, false); else Execute(null, dataSources, argumentList, results, false); } ////// Default document as XPathNavigator. /// public override void Execute(IXPathNavigable contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, TextWriter results) { if (results == null) throw new ArgumentNullException("results"); Execute(contextDocument, dataSources, argumentList, XmlWriter.Create(results, this.staticData.DefaultWriterSettings)); } ////// Default document as XPathNavigator. /// public override void Execute(IXPathNavigable contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, Stream results) { if (results == null) throw new ArgumentNullException("results"); Execute(contextDocument, dataSources, argumentList, XmlWriter.Create(results, this.staticData.DefaultWriterSettings)); } ////// Executes the query by accessing datasources via the XmlResolver and using run-time parameters /// as provided by the XsltArgumentList. The default document is mapped into the XmlResolver with the /// provided name. The results are output to the provided XmlWriter. /// public void Execute(string contextDocumentUri, XmlResolver dataSources, XsltArgumentList argumentList, XmlWriter results) { if (results == null) throw new ArgumentNullException("results"); Execute(contextDocumentUri, dataSources, argumentList, results, false); } ////// Executes the query by accessing datasources via the XmlResolver and using /// run-time parameters as provided by the XsltArgumentList. The default document /// is mapped into the XmlResolver with the provided name. The results are returned /// as an IList. /// public IList Evaluate(string contextDocumentUri, XmlResolver dataSources, XsltArgumentList argumentList) { XmlCachedSequenceWriter seqwrt = new XmlCachedSequenceWriter(); Execute(contextDocumentUri, dataSources, argumentList, seqwrt); return seqwrt.ResultSequence; } ////// Executes the query by accessing datasources via the XmlResolver and using run-time parameters /// as provided by the XsltArgumentList. The default document is mapped into the XmlResolver with the /// provided name. The results are output to the provided XmlWriter. /// public override void Execute(XmlReader contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlWriter results) { if (results == null) throw new ArgumentNullException("results"); Execute(contextDocument, dataSources, argumentList, results, false); } ////// Executes the query by accessing datasources via the XmlResolver and using run-time parameters /// as provided by the XsltArgumentList. The default document is mapped into the XmlResolver with the /// provided name. The results are output to the provided TextWriter. /// public override void Execute(XmlReader contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, TextWriter results) { if (results == null) throw new ArgumentNullException("results"); Execute(contextDocument, dataSources, argumentList, XmlWriter.Create(results, this.staticData.DefaultWriterSettings), true); } ////// Executes the query by accessing datasources via the XmlResolver and using run-time parameters /// as provided by the XsltArgumentList. The default document is mapped into the XmlResolver with the /// provided name. The results are output to the provided Stream. /// public override void Execute(XmlReader contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, Stream results) { if (results == null) throw new ArgumentNullException("results"); Execute(contextDocument, dataSources, argumentList, XmlWriter.Create(results, this.staticData.DefaultWriterSettings), true); } ////// Executes the query by accessing datasources via the XmlResolver and using /// run-time parameters as provided by the XsltArgumentList. The default document /// is mapped into the XmlResolver with the provided name. The results are returned /// as an IList. /// public override IList Evaluate(XmlReader contextDocument, XmlResolver dataSources, XsltArgumentList argumentList) { XmlCachedSequenceWriter seqwrt = new XmlCachedSequenceWriter(); Execute(contextDocument, dataSources, argumentList, seqwrt); return seqwrt.ResultSequence; } ////// Execute the dynamic assembly generated by the XmlILGenerator. /// private void Execute(object defaultDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlWriter writer, bool closeWriter) { try { // Try to extract a RawWriter XmlWellFormedWriter wellFormedWriter = writer as XmlWellFormedWriter; if (wellFormedWriter != null && wellFormedWriter.WriteState == WriteState.Start && wellFormedWriter.Settings.ConformanceLevel != ConformanceLevel.Document) { // Extracted RawWriter from WellFormedWriter Execute(defaultDocument, dataSources, argumentList, new XmlMergeSequenceWriter(wellFormedWriter.RawWriter)); } else { // Wrap Writer in RawWriter Execute(defaultDocument, dataSources, argumentList, new XmlMergeSequenceWriter(new XmlRawWriterWrapper(writer))); } } finally { // Close Writers that are created by XmlILGenerator; flush external writers if (closeWriter) writer.Close(); else writer.Flush(); } } ////// Execute the dynamic assembly generated by the XmlILGenerator. /// private void Execute(object defaultDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlSequenceWriter results) { Debug.Assert(results != null); // Ensure that dataSources is always non-null if (dataSources == null) dataSources = XmlNullResolver.Singleton; this.delExec(new XmlQueryRuntime(this.staticData, defaultDocument, dataSources, argumentList, results)); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //[....] //----------------------------------------------------------------------------- using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Security; using System.Xml.XPath; using System.Xml.Xsl.IlGen; using System.Xml.Xsl.Qil; using System.Xml.Xsl.Runtime; namespace System.Xml.Xsl { internal delegate void ExecuteDelegate(XmlQueryRuntime runtime); ////// This internal class is the entry point for creating Msil assemblies from QilExpression. /// ////// Generate will return an AssemblyBuilder with the following setup: /// Assembly Name = "MS.Internal.Xml.CompiledQuery" /// Module Dll Name = "MS.Internal.Xml.CompiledQuery.dll" /// public class MS.Internal.Xml.CompiledQuery.Test { /// public static void Execute(XmlQueryRuntime runtime); /// public static void Root(XmlQueryRuntime runtime); /// private static ... UserMethod1(XmlQueryRuntime runtime, ...); /// ... /// private static ... UserMethodN(XmlQueryRuntime runtime, ...); /// } /// /// XmlILGenerator incorporates a number of different technologies in order to generate efficient code that avoids caching /// large result sets in memory: /// /// 1. Code Iterators - Query results are computed using a set of composable, interlocking iterators that alone perform a /// simple task, but together execute complex queries. The iterators are actually little blocks of code /// that are connected to each other using a series of jumps. Because each iterator is not instantiated /// as a separate object, the number of objects and number of function calls is kept to a minimum during /// execution. Also, large result sets are often computed incrementally, with each iterator performing one step in a /// pipeline of sequence items. /// /// 2. Analyzers - During code generation, QilToMsil traverses the semantic tree representation of the query (QIL) several times. /// As visits to each node in the tree start and end, various Analyzers are invoked. These Analyzers incrementally /// collect and store information that is later used to generate faster and smaller code. /// internal class XmlILGenerator { private QilExpression qil; private GenerateHelper helper; private XmlILOptimizerVisitor optVisitor; private XmlILVisitor xmlIlVisitor; private XmlILModule module; ////// Always output debug information in debug mode. /// public XmlILGenerator() { } ////// Given the logical query plan (QilExpression) generate a physical query plan (MSIL) that can be executed. /// public XmlILCommand Generate(QilExpression query, TypeBuilder typeBldr) { MethodInfo methRoot, methExec; bool useLRE, emitSymbols; XmlQueryStaticData staticData; ExecuteDelegate delExec; XmlILMethodAttributes methAttrs; this.qil = query; useLRE = !this.qil.IsDebug && (typeBldr == null); emitSymbols = this.qil.IsDebug; // In debug code, ensure that input QIL is correct QilValidationVisitor.Validate(this.qil); // Trace Qil before optimization XmlILTrace.WriteQil(this.qil, "qilbefore.xml"); // Trace optimizations XmlILTrace.TraceOptimizations(this.qil, "qilopt.xml"); if (XmlILTrace.IsEnabled) { // Dump assembly to disk; can't do this when using LRE useLRE = false; } // Optimize and annotate the Qil graph this.optVisitor = new XmlILOptimizerVisitor(this.qil, !this.qil.IsDebug); this.qil = this.optVisitor.Optimize(); // In debug code, ensure that output QIL is correct QilValidationVisitor.Validate(this.qil); // Trace Qil after optimization XmlILTrace.WriteQil(this.qil, "qilafter.xml"); try { XmlILModule.CreateModulePermissionSet.Assert(); // Create module in which methods will be generated if (typeBldr != null) this.module = new XmlILModule(typeBldr); else this.module = new XmlILModule(useLRE, emitSymbols); // Create a code generation helper for the module; enable optimizations if IsDebug is false this.helper = new GenerateHelper(this.module, this.qil.IsDebug); // Create helper methods CreateHelperFunctions(); // Create metadata for the Execute function, which is the entry point to the query // public static void Execute(XmlQueryRuntime); methExec = this.module.DefineMethod("Execute", typeof(void), new Type[] {}, new string[] {}, XmlILMethodAttributes.NonUser); // Create metadata for the root expression // public void Root() Debug.Assert(this.qil.Root != null); methAttrs = (this.qil.Root.SourceLine == null) ? XmlILMethodAttributes.NonUser : XmlILMethodAttributes.None; methRoot = this.module.DefineMethod("Root", typeof(void), new Type[] {}, new string[] {}, methAttrs); // Declare all early bound function objects foreach (EarlyBoundInfo info in this.qil.EarlyBoundTypes) this.helper.StaticData.DeclareEarlyBound(info.NamespaceUri, info.EarlyBoundType); // Create metadata for each QilExpression function that has at least one caller CreateFunctionMetadata(this.qil.FunctionList); // Create metadata for each QilExpression global variable and parameter CreateGlobalValueMetadata(this.qil.GlobalVariableList); CreateGlobalValueMetadata(this.qil.GlobalParameterList); // Generate Execute method GenerateExecuteFunction(methExec, methRoot); // Visit the QilExpression graph this.xmlIlVisitor = new XmlILVisitor(); this.xmlIlVisitor.Visit(this.qil, this.helper, methRoot); // Collect all static information required by the runtime staticData = new XmlQueryStaticData( this.qil.DefaultWriterSettings, this.qil.WhitespaceRules, this.helper.StaticData); // Create static constructor that initializes XmlQueryStaticData instance at runtime if (typeBldr != null) CreateTypeInitializer(staticData); // Finish up creation of the type this.module.BakeMethods(); // Create delegate over "Execute" method delExec = (ExecuteDelegate) this.module.CreateDelegate("Execute", typeof(ExecuteDelegate)); return new XmlILCommand(delExec, staticData); } finally { CodeAccessPermission.RevertAssert(); } } ////// Create MethodBuilder metadata for the specified QilExpression function. Annotate ndFunc with the /// MethodBuilder. Also, each QilExpression argument type should be converted to a corresponding Clr type. /// Each argument QilExpression node should be annotated with the resulting ParameterBuilder. /// private void CreateFunctionMetadata(IListfuncList) { MethodInfo methInfo; Type[] paramTypes; string[] paramNames; Type typReturn; XmlILMethodAttributes methAttrs; foreach (QilFunction ndFunc in funcList) { paramTypes = new Type[ndFunc.Arguments.Count]; paramNames = new string[ndFunc.Arguments.Count]; // Loop through all other parameters and save their types in the array for (int arg = 0; arg < ndFunc.Arguments.Count; arg ++) { QilParameter ndParam = (QilParameter) ndFunc.Arguments[arg]; Debug.Assert(ndParam.NodeType == QilNodeType.Parameter); // Get the type of each argument as a Clr type paramTypes[arg] = XmlILTypeHelper.GetStorageType(ndParam.XmlType); // Get the name of each argument if (ndParam.DebugName != null) paramNames[arg] = ndParam.DebugName; } // Get the type of the return value if (XmlILConstructInfo.Read(ndFunc).PushToWriterLast) { // Push mode functions do not have a return value typReturn = typeof(void); } else { // Pull mode functions have a return value typReturn = XmlILTypeHelper.GetStorageType(ndFunc.XmlType); } // Create the method metadata methAttrs = ndFunc.SourceLine == null ? XmlILMethodAttributes.NonUser : XmlILMethodAttributes.None; methInfo = this.module.DefineMethod(ndFunc.DebugName, typReturn, paramTypes, paramNames, methAttrs); for (int arg = 0; arg < ndFunc.Arguments.Count; arg ++) { // Set location of parameter on Let node annotation XmlILAnnotation.Write(ndFunc.Arguments[arg]).ArgumentPosition = arg; } // Annotate function with the MethodInfo XmlILAnnotation.Write(ndFunc).FunctionBinding = methInfo; } } /// /// Generate metadata for a method that calculates a global value. /// private void CreateGlobalValueMetadata(IListglobalList) { MethodInfo methInfo; Type typReturn; XmlILMethodAttributes methAttrs; foreach (QilReference ndRef in globalList) { // public T GlobalValue() typReturn = XmlILTypeHelper.GetStorageType(ndRef.XmlType); methAttrs = ndRef.SourceLine == null ? XmlILMethodAttributes.NonUser : XmlILMethodAttributes.None; methInfo = this.module.DefineMethod(ndRef.DebugName.ToString(), typReturn, new Type[] {}, new string[] {}, methAttrs); // Annotate function with MethodBuilder XmlILAnnotation.Write(ndRef).FunctionBinding = methInfo; } } /// /// Generate the "Execute" method, which is the entry point to the query. /// private MethodInfo GenerateExecuteFunction(MethodInfo methExec, MethodInfo methRoot) { this.helper.MethodBegin(methExec, null, false); // Force some or all global values to be evaluated at start of query EvaluateGlobalValues(this.qil.GlobalVariableList); EvaluateGlobalValues(this.qil.GlobalParameterList); // Root(runtime); this.helper.LoadQueryRuntime(); this.helper.Call(methRoot); this.helper.MethodEnd(); return methExec; } ////// Create and generate various helper methods, which are called by the generated code. /// private void CreateHelperFunctions() { MethodInfo meth; Label lblClone; // public static XPathNavigator SyncToNavigator(XPathNavigator, XPathNavigator); meth = this.module.DefineMethod( "SyncToNavigator", typeof(XPathNavigator), new Type[] {typeof(XPathNavigator), typeof(XPathNavigator)}, new string[] {null, null}, XmlILMethodAttributes.NonUser | XmlILMethodAttributes.Raw); this.helper.MethodBegin(meth, null, false); // if (navigatorThis != null && navigatorThis.MoveTo(navigatorThat)) // return navigatorThis; lblClone = this.helper.DefineLabel(); this.helper.Emit(OpCodes.Ldarg_0); this.helper.Emit(OpCodes.Brfalse, lblClone); this.helper.Emit(OpCodes.Ldarg_0); this.helper.Emit(OpCodes.Ldarg_1); this.helper.Call(XmlILMethods.NavMoveTo); this.helper.Emit(OpCodes.Brfalse, lblClone); this.helper.Emit(OpCodes.Ldarg_0); this.helper.Emit(OpCodes.Ret); // LabelClone: // return navigatorThat.Clone(); this.helper.MarkLabel(lblClone); this.helper.Emit(OpCodes.Ldarg_1); this.helper.Call(XmlILMethods.NavClone); this.helper.MethodEnd(); } ////// Generate code to force evaluation of some or all global variables and/or parameters. /// private void EvaluateGlobalValues(IListiterList) { MethodInfo methInfo; foreach (QilIterator ndIter in iterList) { // Evaluate global if generating debug code, or if global might have side effects if (this.qil.IsDebug || OptimizerPatterns.Read(ndIter).MatchesPattern(OptimizerPatternName.MaybeSideEffects)) { // Get MethodInfo that evaluates the global value and discard its return value methInfo = XmlILAnnotation.Write(ndIter).FunctionBinding; Debug.Assert(methInfo != null, "MethodInfo for global value should have been created previously."); this.helper.LoadQueryRuntime(); this.helper.Call(methInfo); this.helper.Emit(OpCodes.Pop); } } } /// /// Create static constructor that initializes XmlQueryStaticData instance at runtime. /// public void CreateTypeInitializer(XmlQueryStaticData staticData) { byte[] data; Type[] ebTypes; FieldInfo fldInitData, fldData, fldTypes; ConstructorInfo cctor; staticData.GetObjectData(out data, out ebTypes); fldInitData = this.module.DefineInitializedData("__" + XmlQueryStaticData.DataFieldName, data); fldData = this.module.DefineField(XmlQueryStaticData.DataFieldName, typeof(object)); fldTypes = this.module.DefineField(XmlQueryStaticData.TypesFieldName, typeof(Type[])); cctor = this.module.DefineTypeInitializer(); this.helper.MethodBegin(cctor, null, false); // s_data = new byte[s_initData.Length] { s_initData }; this.helper.LoadInteger(data.Length); this.helper.Emit(OpCodes.Newarr, typeof(byte)); this.helper.Emit(OpCodes.Dup); this.helper.Emit(OpCodes.Ldtoken, fldInitData); this.helper.Call(XmlILMethods.InitializeArray); this.helper.Emit(OpCodes.Stsfld, fldData); if (ebTypes != null) { // Type[] types = new Type[s_ebTypes.Length]; LocalBuilder locTypes = this.helper.DeclareLocal("$$$types", typeof(Type[])); this.helper.LoadInteger(ebTypes.Length); this.helper.Emit(OpCodes.Newarr, typeof(Type)); this.helper.Emit(OpCodes.Stloc, locTypes); for (int idx = 0; idx < ebTypes.Length; idx++) { // types[idx] = ebTypes[idx]; this.helper.Emit(OpCodes.Ldloc, locTypes); this.helper.LoadInteger(idx); this.helper.LoadType(ebTypes[idx]); this.helper.Emit(OpCodes.Stelem_Ref); } // s_types = types; this.helper.Emit(OpCodes.Ldloc, locTypes); this.helper.Emit(OpCodes.Stsfld, fldTypes); } this.helper.MethodEnd(); } } ////// This is the executable command generated by the XmlILGenerator. /// internal class XmlILCommand : XmlCommand { private ExecuteDelegate delExec; private XmlQueryStaticData staticData; ////// Constructor. /// public XmlILCommand(ExecuteDelegate delExec, XmlQueryStaticData staticData) { Debug.Assert(delExec != null && staticData != null); this.delExec = delExec; this.staticData = staticData; } ////// Return execute delegate. /// public ExecuteDelegate ExecuteDelegate { get { return delExec; } } ////// Return query static data required by the runtime. /// public XmlQueryStaticData StaticData { get { return staticData; } } ////// Default document as XPathNavigator. /// public override void Execute(IXPathNavigable contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlWriter results) { if (results == null) throw new ArgumentNullException("results"); if (contextDocument != null) Execute(contextDocument.CreateNavigator(), dataSources, argumentList, results, false); else Execute(null, dataSources, argumentList, results, false); } ////// Default document as XPathNavigator. /// public override void Execute(IXPathNavigable contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, TextWriter results) { if (results == null) throw new ArgumentNullException("results"); Execute(contextDocument, dataSources, argumentList, XmlWriter.Create(results, this.staticData.DefaultWriterSettings)); } ////// Default document as XPathNavigator. /// public override void Execute(IXPathNavigable contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, Stream results) { if (results == null) throw new ArgumentNullException("results"); Execute(contextDocument, dataSources, argumentList, XmlWriter.Create(results, this.staticData.DefaultWriterSettings)); } ////// Executes the query by accessing datasources via the XmlResolver and using run-time parameters /// as provided by the XsltArgumentList. The default document is mapped into the XmlResolver with the /// provided name. The results are output to the provided XmlWriter. /// public void Execute(string contextDocumentUri, XmlResolver dataSources, XsltArgumentList argumentList, XmlWriter results) { if (results == null) throw new ArgumentNullException("results"); Execute(contextDocumentUri, dataSources, argumentList, results, false); } ////// Executes the query by accessing datasources via the XmlResolver and using /// run-time parameters as provided by the XsltArgumentList. The default document /// is mapped into the XmlResolver with the provided name. The results are returned /// as an IList. /// public IList Evaluate(string contextDocumentUri, XmlResolver dataSources, XsltArgumentList argumentList) { XmlCachedSequenceWriter seqwrt = new XmlCachedSequenceWriter(); Execute(contextDocumentUri, dataSources, argumentList, seqwrt); return seqwrt.ResultSequence; } ////// Executes the query by accessing datasources via the XmlResolver and using run-time parameters /// as provided by the XsltArgumentList. The default document is mapped into the XmlResolver with the /// provided name. The results are output to the provided XmlWriter. /// public override void Execute(XmlReader contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlWriter results) { if (results == null) throw new ArgumentNullException("results"); Execute(contextDocument, dataSources, argumentList, results, false); } ////// Executes the query by accessing datasources via the XmlResolver and using run-time parameters /// as provided by the XsltArgumentList. The default document is mapped into the XmlResolver with the /// provided name. The results are output to the provided TextWriter. /// public override void Execute(XmlReader contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, TextWriter results) { if (results == null) throw new ArgumentNullException("results"); Execute(contextDocument, dataSources, argumentList, XmlWriter.Create(results, this.staticData.DefaultWriterSettings), true); } ////// Executes the query by accessing datasources via the XmlResolver and using run-time parameters /// as provided by the XsltArgumentList. The default document is mapped into the XmlResolver with the /// provided name. The results are output to the provided Stream. /// public override void Execute(XmlReader contextDocument, XmlResolver dataSources, XsltArgumentList argumentList, Stream results) { if (results == null) throw new ArgumentNullException("results"); Execute(contextDocument, dataSources, argumentList, XmlWriter.Create(results, this.staticData.DefaultWriterSettings), true); } ////// Executes the query by accessing datasources via the XmlResolver and using /// run-time parameters as provided by the XsltArgumentList. The default document /// is mapped into the XmlResolver with the provided name. The results are returned /// as an IList. /// public override IList Evaluate(XmlReader contextDocument, XmlResolver dataSources, XsltArgumentList argumentList) { XmlCachedSequenceWriter seqwrt = new XmlCachedSequenceWriter(); Execute(contextDocument, dataSources, argumentList, seqwrt); return seqwrt.ResultSequence; } ////// Execute the dynamic assembly generated by the XmlILGenerator. /// private void Execute(object defaultDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlWriter writer, bool closeWriter) { try { // Try to extract a RawWriter XmlWellFormedWriter wellFormedWriter = writer as XmlWellFormedWriter; if (wellFormedWriter != null && wellFormedWriter.WriteState == WriteState.Start && wellFormedWriter.Settings.ConformanceLevel != ConformanceLevel.Document) { // Extracted RawWriter from WellFormedWriter Execute(defaultDocument, dataSources, argumentList, new XmlMergeSequenceWriter(wellFormedWriter.RawWriter)); } else { // Wrap Writer in RawWriter Execute(defaultDocument, dataSources, argumentList, new XmlMergeSequenceWriter(new XmlRawWriterWrapper(writer))); } } finally { // Close Writers that are created by XmlILGenerator; flush external writers if (closeWriter) writer.Close(); else writer.Flush(); } } ////// Execute the dynamic assembly generated by the XmlILGenerator. /// private void Execute(object defaultDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlSequenceWriter results) { Debug.Assert(results != null); // Ensure that dataSources is always non-null if (dataSources == null) dataSources = XmlNullResolver.Singleton; this.delExec(new XmlQueryRuntime(this.staticData, defaultDocument, dataSources, argumentList, results)); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SqlLiftIndependentRowExpressions.cs
- BuildDependencySet.cs
- MemberCollection.cs
- TableMethodGenerator.cs
- CodeAccessSecurityEngine.cs
- RelatedPropertyManager.cs
- BevelBitmapEffect.cs
- VisualStateChangedEventArgs.cs
- DataContractSerializerOperationGenerator.cs
- PkcsMisc.cs
- HtmlTernaryTree.cs
- FixedElement.cs
- FastPropertyAccessor.cs
- NativeMethodsOther.cs
- LinkConverter.cs
- SchemaTableOptionalColumn.cs
- HtmlButton.cs
- DirtyTextRange.cs
- ToRequest.cs
- TreeView.cs
- TransformationRules.cs
- _CookieModule.cs
- ServerIdentity.cs
- CurrentChangingEventManager.cs
- TableDetailsCollection.cs
- DialogResultConverter.cs
- OdbcConnectionFactory.cs
- TransformerInfo.cs
- TypeExtension.cs
- FrameworkPropertyMetadata.cs
- ObjectTag.cs
- ParameterCollection.cs
- SBCSCodePageEncoding.cs
- ParameterReplacerVisitor.cs
- ExceptionHandler.cs
- CodeTypeDeclarationCollection.cs
- LineSegment.cs
- FieldToken.cs
- BinaryNode.cs
- Timer.cs
- ProtocolsSection.cs
- SearchForVirtualItemEventArgs.cs
- AsymmetricKeyExchangeFormatter.cs
- SqlResolver.cs
- DynamicFilterExpression.cs
- Underline.cs
- remotingproxy.cs
- DataListItemEventArgs.cs
- Identity.cs
- DataRelation.cs
- OleDbEnumerator.cs
- EndpointConfigContainer.cs
- HwndMouseInputProvider.cs
- DataTemplateSelector.cs
- FixedSOMElement.cs
- KerberosSecurityTokenAuthenticator.cs
- Crypto.cs
- HttpHandlersSection.cs
- FolderLevelBuildProviderAppliesToAttribute.cs
- FrameSecurityDescriptor.cs
- PropertyManager.cs
- EntityStoreSchemaGenerator.cs
- ListViewDeletedEventArgs.cs
- CanExecuteRoutedEventArgs.cs
- Misc.cs
- FormsAuthenticationUserCollection.cs
- MiniModule.cs
- WebPartZoneBase.cs
- TraceContextRecord.cs
- PackWebRequestFactory.cs
- _Rfc2616CacheValidators.cs
- RemotingException.cs
- DataTableExtensions.cs
- TextCompositionManager.cs
- ExpressionConverter.cs
- ImportDesigner.xaml.cs
- WorkflowRuntimeService.cs
- InvalidOperationException.cs
- ConfigsHelper.cs
- DataBindingExpressionBuilder.cs
- ListControl.cs
- Base64Stream.cs
- SafeWaitHandle.cs
- HandledMouseEvent.cs
- XmlDictionary.cs
- AdPostCacheSubstitution.cs
- ZipIOLocalFileDataDescriptor.cs
- EncoderNLS.cs
- AssociatedControlConverter.cs
- CapabilitiesPattern.cs
- SendKeys.cs
- UniformGrid.cs
- HostingEnvironment.cs
- ResourceWriter.cs
- OleDbPermission.cs
- ObjectViewEntityCollectionData.cs
- DBSchemaRow.cs
- DropShadowEffect.cs
- DBBindings.cs
- SQLInt32Storage.cs