/// <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);
}
}