/// <summary> /// Trace ILGen optimizations and log them to "fileName". /// </summary> public static void TraceOptimizations(QilExpression qil, string fileName) { if (!IsEnabled) { return; } XmlWriter w = XmlWriter.Create(s_dirName + "\\" + fileName); w.WriteStartDocument(); w.WriteProcessingInstruction("xml-stylesheet", "href='qilo.xslt' type='text/xsl'"); w.WriteStartElement("QilOptimizer"); w.WriteAttributeString("timestamp", DateTime.Now.ToString(CultureInfo.InvariantCulture)); WriteQilRewrite(qil, w, null); try { // Then, rewrite the graph until "done" or some max value is reached. for (int i = 1; i < MAX_REWRITES; i++) { QilExpression qilTemp = (QilExpression)(new QilCloneVisitor(qil.Factory).Clone(qil)); XmlILOptimizerVisitor visitor = new XmlILOptimizerVisitor(qilTemp, !qilTemp.IsDebug); visitor.Threshold = i; qilTemp = visitor.Optimize(); // In debug code, ensure that QIL after N steps is correct QilValidationVisitor.Validate(qilTemp); // Trace the rewrite WriteQilRewrite(qilTemp, w, OptimizationToString(visitor.LastReplacement)); if (visitor.ReplacementCount < i) { break; } } } catch (Exception e) { if (!XmlException.IsCatchableException(e)) { throw; } w.WriteElementString("Exception", null, e.ToString()); throw; } finally { w.WriteEndElement(); w.WriteEndDocument(); w.Flush(); w.Close(); } }
internal static void PrintQil(object qil, XmlWriter xw, bool printComments, bool printTypes, bool printLineInfo) { QilExpression qilExpr = (QilExpression)qil; QilXmlWriter.Options options = QilXmlWriter.Options.None; QilValidationVisitor.Validate(qilExpr); if (printComments) { options |= QilXmlWriter.Options.Annotations; } if (printTypes) { options |= QilXmlWriter.Options.TypeInfo; } if (printLineInfo) { options |= QilXmlWriter.Options.LineInfo; } QilXmlWriter qw = new QilXmlWriter(xw, options); qw.ToXml(qilExpr); xw.Flush(); }
/// <summary> /// Given the logical query plan (QilExpression) generate a physical query plan (MSIL) that can be executed. /// </summary> // SxS Note: The way the trace file names are created (hardcoded) is NOT SxS safe. However the files are // created only for internal tracing purposes. In addition XmlILTrace class is not compiled into retail // builds. As a result it is fine to suppress the FxCop SxS warning. // TODO-NULLABLE: missing [return: NotNullIfNull("typeBldr")] public XmlILCommand?Generate(QilExpression query, TypeBuilder?typeBldr) { _qil = query; bool useLRE = ( !_qil.IsDebug && (typeBldr == null) #if DEBUG && !XmlILTrace.IsEnabled // Dump assembly to disk; can't do this when using LRE #endif ); bool emitSymbols = _qil.IsDebug; // In debug code, ensure that input QIL is correct QilValidationVisitor.Validate(_qil); #if DEBUG // Trace Qil before optimization XmlILTrace.WriteQil(_qil, "qilbefore.xml"); // Trace optimizations XmlILTrace.TraceOptimizations(_qil, "qilopt.xml"); #endif // Optimize and annotate the Qil graph _optVisitor = new XmlILOptimizerVisitor(_qil, !_qil.IsDebug); _qil = _optVisitor.Optimize(); // In debug code, ensure that output QIL is correct QilValidationVisitor.Validate(_qil); #if DEBUG // Trace Qil after optimization XmlILTrace.WriteQil(_qil, "qilafter.xml"); #endif // Create module in which methods will be generated if (typeBldr != null) { _module = new XmlILModule(typeBldr); } else { _module = new XmlILModule(useLRE, emitSymbols); } // Create a code generation helper for the module; enable optimizations if IsDebug is false _helper = new GenerateHelper(_module, _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); MethodInfo methExec = _module.DefineMethod("Execute", typeof(void), Array.Empty <Type>(), Array.Empty <string>(), XmlILMethodAttributes.NonUser); // Create metadata for the root expression // public void Root() Debug.Assert(_qil.Root != null); XmlILMethodAttributes methAttrs = (_qil.Root.SourceLine == null) ? XmlILMethodAttributes.NonUser : XmlILMethodAttributes.None; MethodInfo methRoot = _module.DefineMethod("Root", typeof(void), Array.Empty <Type>(), Array.Empty <string>(), methAttrs); // Declare all early bound function objects foreach (EarlyBoundInfo info in _qil.EarlyBoundTypes) { _helper.StaticData.DeclareEarlyBound(info.NamespaceUri, info.EarlyBoundType); } // Create metadata for each QilExpression function that has at least one caller CreateFunctionMetadata(_qil.FunctionList); // Create metadata for each QilExpression global variable and parameter CreateGlobalValueMetadata(_qil.GlobalVariableList); CreateGlobalValueMetadata(_qil.GlobalParameterList); // Generate Execute method GenerateExecuteFunction(methExec, methRoot); // Visit the QilExpression graph _xmlIlVisitor = new XmlILVisitor(); _xmlIlVisitor.Visit(_qil, _helper, methRoot); // Collect all static information required by the runtime XmlQueryStaticData staticData = new XmlQueryStaticData( _qil.DefaultWriterSettings, _qil.WhitespaceRules, _helper.StaticData ); // Create static constructor that initializes XmlQueryStaticData instance at runtime if (typeBldr != null) { CreateTypeInitializer(staticData); // Finish up creation of the type _module.BakeMethods(); return(null); } else { // Finish up creation of the type _module.BakeMethods(); // Create delegate over "Execute" method ExecuteDelegate delExec = (ExecuteDelegate)_module.CreateDelegate("Execute", typeof(ExecuteDelegate)); return(new XmlILCommand(delExec, staticData)); } }
/// <summary> /// Given the logical query plan (QilExpression) generate a physical query plan (MSIL) that can be executed. /// </summary> public XmlCommand Generate(QilExpression query, AssemblyName asmName) { MethodInfo methRoot, methExec; bool useLRE, emitSymbols; ExecuteDelegate delExec; XmlILMethodAttributes methAttrs; this.qil = query; useLRE = !this.qil.IsDebug && (asmName == 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"); // Create module in which methods will be generated this.module = new XmlILModule(useLRE, emitSymbols, asmName); // 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 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); // 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); // Create Execute method methExec = CreateExecuteFunction(methRoot); // Visit the QilExpression graph this.xmlIlVisitor = new XmlILVisitor(); this.xmlIlVisitor.Visit(this.qil, this.helper, methRoot); this.module.BakeMethods(); // Create delegate over "Execute" method delExec = (ExecuteDelegate)this.module.CreateDelegate("Execute", typeof(ExecuteDelegate)); return(new XmlILCommand(delExec, this.qil, this.helper.StaticData)); }