/// <summary> /// Define a method in this module with the specified name and parameters. /// </summary> public MethodInfo DefineMethod(string name, Type returnType, Type[] paramTypes, string[] paramNames, XmlILMethodAttributes xmlAttrs) { MethodInfo methResult; int uniqueId = 1; string nameOrig = name; Type[] paramTypesNew; bool isRaw = (xmlAttrs & XmlILMethodAttributes.Raw) != 0; // Ensure that name is unique while (this.methods[name] != null) { // Add unique id to end of name in order to make it unique within this module uniqueId++; name = nameOrig + " (" + uniqueId + ")"; } if (!isRaw) { // XmlQueryRuntime is always 0th parameter paramTypesNew = new Type[paramTypes.Length + 1]; paramTypesNew[0] = typeof(XmlQueryRuntime); Array.Copy(paramTypes, 0, paramTypesNew, 1, paramTypes.Length); paramTypes = paramTypesNew; } if (!this.useLRE) { MethodBuilder methBldr; methBldr = this.typeBldr.DefineMethod( name, MethodAttributes.Private | MethodAttributes.Static, returnType, paramTypes); if (emitSymbols && (xmlAttrs & XmlILMethodAttributes.NonUser) != 0) { // Add DebuggerStepThroughAttribute and DebuggerNonUserCodeAttribute to non-user methods so that debugging is a better experience methBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.StepThrough, new object[] {})); methBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.NonUserCode, new object[] {})); } if (!isRaw) methBldr.DefineParameter(1, ParameterAttributes.None, RuntimeName); for (int i = 0; i < paramNames.Length; i++) { if (paramNames[i] != null && paramNames[i].Length != 0) methBldr.DefineParameter(i + (isRaw ? 1 : 2), ParameterAttributes.None, paramNames[i]); } methResult = methBldr; } else { DynamicMethod methDyn = new DynamicMethod(name, returnType, paramTypes, LREModule); methDyn.InitLocals = true; if (!isRaw) methDyn.DefineParameter(1, ParameterAttributes.None, RuntimeName); for (int i = 0; i < paramNames.Length; i++) { if (paramNames[i] != null && paramNames[i].Length != 0) methDyn.DefineParameter(i + (isRaw ? 1 : 2), ParameterAttributes.None, paramNames[i]); } methResult = methDyn; } // Index method by name this.methods[name] = methResult; return methResult; }
/// <summary> /// Define a method in this module with the specified name and parameters. /// </summary> public MethodInfo DefineMethod(string name, Type returnType, Type[] paramTypes, string?[] paramNames, XmlILMethodAttributes xmlAttrs) { MethodInfo methResult; int uniqueId = 1; string nameOrig = name; Type[] paramTypesNew; bool isRaw = (xmlAttrs & XmlILMethodAttributes.Raw) != 0; // Ensure that name is unique while (_methods[name] != null) { // Add unique id to end of name in order to make it unique within this module uniqueId++; name = $"{nameOrig} ({uniqueId})"; } if (!isRaw) { // XmlQueryRuntime is always 0th parameter paramTypesNew = new Type[paramTypes.Length + 1]; paramTypesNew[0] = typeof(XmlQueryRuntime); Array.Copy(paramTypes, 0, paramTypesNew, 1, paramTypes.Length); paramTypes = paramTypesNew; } if (!_useLRE) { MethodBuilder methBldr = _typeBldr !.DefineMethod( name, MethodAttributes.Private | MethodAttributes.Static, returnType, paramTypes); if (_emitSymbols && (xmlAttrs & XmlILMethodAttributes.NonUser) != 0) { // Add DebuggerStepThroughAttribute and DebuggerNonUserCodeAttribute to non-user methods so that debugging is a better experience methBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.StepThrough, Array.Empty <object>())); methBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.NonUserCode, Array.Empty <object>())); } if (!isRaw) { methBldr.DefineParameter(1, ParameterAttributes.None, RuntimeName); } for (int i = 0; i < paramNames.Length; i++) { if (paramNames[i] != null && paramNames[i] !.Length != 0) { methBldr.DefineParameter(i + (isRaw ? 1 : 2), ParameterAttributes.None, paramNames[i]); } } methResult = methBldr; } else { DynamicMethod methDyn = new DynamicMethod(name, returnType, paramTypes, s_LREModule); methDyn.InitLocals = true; methResult = methDyn; } // Index method by name _methods[name] = methResult; return(methResult); }
/// <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> /// Define a method in this module with the specified name and parameters. /// </summary> public MethodInfo DefineMethod(string name, Type returnType, Type[] paramTypes, string[] paramNames, XmlILMethodAttributes xmlAttrs) { MethodInfo methResult; int uniqueId = 1; string nameOrig = name; Type[] paramTypesNew; bool isRaw = (xmlAttrs & XmlILMethodAttributes.Raw) != 0; // Ensure that name is unique while (this.methods[name] != null) { // Add unique id to end of name in order to make it unique within this module uniqueId++; name = nameOrig + " (" + uniqueId + ")"; } if (!isRaw) { // XmlQueryRuntime is always 0th parameter paramTypesNew = new Type[paramTypes.Length + 1]; paramTypesNew[0] = typeof(XmlQueryRuntime); Array.Copy(paramTypes, 0, paramTypesNew, 1, paramTypes.Length); paramTypes = paramTypesNew; } if (!this.useLRE) { MethodBuilder methBldr; methBldr = this.typeBldr.DefineMethod( name, MethodAttributes.Public | MethodAttributes.Static, returnType, paramTypes); if (emitSymbols && (xmlAttrs & XmlILMethodAttributes.NonUser) != 0) { // Add DebuggerStepThroughAttribute and DebuggerNonUserCodeAttribute to non-user methods so that debugging is a better experience methBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.StepThrough, new object[] {})); methBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.NonUserCode, new object[] {})); } if (!isRaw) { methBldr.DefineParameter(1, ParameterAttributes.None, RuntimeName); } for (int i = 0; i < paramNames.Length; i++) { if (paramNames[i] != null && paramNames[i].Length != 0) { methBldr.DefineParameter(i + (isRaw ? 1 : 2), ParameterAttributes.None, paramNames[i]); } } methResult = methBldr; } else { try { // DynamicMethod constructor demands ReflectionEmit and ControlEvidence permission CreateMethodPermissionSet.Assert(); DynamicMethod methDyn = new DynamicMethod(name, returnType, paramTypes, LREModule); methDyn.InitLocals = true; if (!isRaw) { methDyn.DefineParameter(1, ParameterAttributes.None, RuntimeName); } for (int i = 0; i < paramNames.Length; i++) { if (paramNames[i] != null && paramNames[i].Length != 0) { methDyn.DefineParameter(i + (isRaw ? 1 : 2), ParameterAttributes.None, paramNames[i]); } } methResult = methDyn; } finally { CodeAccessPermission.RevertAssert(); } } // Index method by name this.methods[name] = methResult; return(methResult); }