Creates Msil code for an entire QilExpression graph. Code is generated in one of two modes: push or pull. In push mode, code is generated to push the values in an iterator to the XmlWriter interface. In pull mode, the values in an iterator are stored in a physical location such as the stack or a local variable by an iterator. The iterator is passive, and will just wait for a caller to pull the data and/or instruct the iterator to enumerate the next value.
Inheritance: System.Xml.Xsl.Qil.QilVisitor
Exemplo n.º 1
0
        /// <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.
        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(this.qil, "qilbefore.xml");

            // Trace optimizations
            XmlILTrace.TraceOptimizations(this.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(this.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), new Type[] { }, new 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), new Type[] { }, new 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);
        }