1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Globalization;
7 using System.Xml;
8 using System.Xml.XPath;
9 using System.Xml.Schema;
10 using System.Text;
11 using System.IO;
12 using System.Collections;
13 using System.Collections.Generic;
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Security;
17 using System.Diagnostics;
18 using System.Xml.Xsl.Qil;
19 using System.Xml.Xsl.Runtime;
20 using System.Runtime.Versioning;
21 
22 namespace System.Xml.Xsl.IlGen
23 {
24     /// <summary>
25     /// List of all XmlIL runtime constructors.
26     /// </summary>
27     internal class XmlILStorageMethods
28     {
29         // Aggregates
30         public MethodInfo AggAvg;
31         public MethodInfo AggAvgResult;
32         public MethodInfo AggCreate;
33         public MethodInfo AggIsEmpty;
34         public MethodInfo AggMax;
35         public MethodInfo AggMaxResult;
36         public MethodInfo AggMin;
37         public MethodInfo AggMinResult;
38         public MethodInfo AggSum;
39         public MethodInfo AggSumResult;
40 
41         // Sequences
42         public Type SeqType;
43         public FieldInfo SeqEmpty;
44         public MethodInfo SeqReuse;
45         public MethodInfo SeqReuseSgl;
46         public MethodInfo SeqAdd;
47         public MethodInfo SeqSortByKeys;
48 
49         // IList<>
50         public Type IListType;
51         public MethodInfo IListCount;
52         public MethodInfo IListItem;
53 
54         // XPathItem
55         public MethodInfo ValueAs;
56 
57         // ToAtomicValue
58         public MethodInfo ToAtomicValue;
59 
XmlILStorageMethods(Type storageType)60         public XmlILStorageMethods(Type storageType)
61         {
62             // Aggregates
63             if (storageType == typeof(int) || storageType == typeof(long) ||
64                 storageType == typeof(decimal) || storageType == typeof(double))
65             {
66                 Type aggType = Type.GetType("System.Xml.Xsl.Runtime." + storageType.Name + "Aggregator");
67                 AggAvg = XmlILMethods.GetMethod(aggType, "Average");
68                 AggAvgResult = XmlILMethods.GetMethod(aggType, "get_AverageResult");
69                 AggCreate = XmlILMethods.GetMethod(aggType, "Create");
70                 AggIsEmpty = XmlILMethods.GetMethod(aggType, "get_IsEmpty");
71                 AggMax = XmlILMethods.GetMethod(aggType, "Maximum");
72                 AggMaxResult = XmlILMethods.GetMethod(aggType, "get_MaximumResult");
73                 AggMin = XmlILMethods.GetMethod(aggType, "Minimum");
74                 AggMinResult = XmlILMethods.GetMethod(aggType, "get_MinimumResult");
75                 AggSum = XmlILMethods.GetMethod(aggType, "Sum");
76                 AggSumResult = XmlILMethods.GetMethod(aggType, "get_SumResult");
77             }
78 
79             // Sequences
80             if (storageType == typeof(XPathNavigator))
81             {
82                 SeqType = typeof(XmlQueryNodeSequence);
83                 SeqAdd = XmlILMethods.GetMethod(SeqType, "AddClone");
84             }
85             else if (storageType == typeof(XPathItem))
86             {
87                 SeqType = typeof(XmlQueryItemSequence);
88                 SeqAdd = XmlILMethods.GetMethod(SeqType, "AddClone");
89             }
90             else
91             {
92                 SeqType = typeof(XmlQuerySequence<>).MakeGenericType(storageType);
93                 SeqAdd = XmlILMethods.GetMethod(SeqType, "Add");
94             }
95 
96             SeqEmpty = SeqType.GetField("Empty");
97             SeqReuse = XmlILMethods.GetMethod(SeqType, "CreateOrReuse", SeqType);
98             SeqReuseSgl = XmlILMethods.GetMethod(SeqType, "CreateOrReuse", SeqType, storageType);
99             SeqSortByKeys = XmlILMethods.GetMethod(SeqType, "SortByKeys");
100 
101             // IList<>
102             IListType = typeof(IList<>).MakeGenericType(storageType);
103             IListItem = XmlILMethods.GetMethod(IListType, "get_Item");
104             IListCount = XmlILMethods.GetMethod(typeof(ICollection<>).MakeGenericType(storageType), "get_Count");
105 
106             // XPathItem.ValueAsXXX
107             if (storageType == typeof(string))
108                 ValueAs = XmlILMethods.GetMethod(typeof(XPathItem), "get_Value");
109             else if (storageType == typeof(int))
110                 ValueAs = XmlILMethods.GetMethod(typeof(XPathItem), "get_ValueAsInt");
111             else if (storageType == typeof(long))
112                 ValueAs = XmlILMethods.GetMethod(typeof(XPathItem), "get_ValueAsLong");
113             else if (storageType == typeof(DateTime))
114                 ValueAs = XmlILMethods.GetMethod(typeof(XPathItem), "get_ValueAsDateTime");
115             else if (storageType == typeof(double))
116                 ValueAs = XmlILMethods.GetMethod(typeof(XPathItem), "get_ValueAsDouble");
117             else if (storageType == typeof(bool))
118                 ValueAs = XmlILMethods.GetMethod(typeof(XPathItem), "get_ValueAsBoolean");
119 
120             // XmlILStorageConverter.XXXToAtomicValue
121             if (storageType == typeof(byte[]))
122                 ToAtomicValue = XmlILMethods.GetMethod(typeof(XmlILStorageConverter), "BytesToAtomicValue");
123             else if (storageType != typeof(XPathItem) && storageType != typeof(XPathNavigator))
124                 ToAtomicValue = XmlILMethods.GetMethod(typeof(XmlILStorageConverter), storageType.Name + "ToAtomicValue");
125         }
126     }
127 
128     /// <summary>
129     /// List of all XmlIL runtime constructors.
130     /// </summary>
131     internal static class XmlILConstructors
132     {
133         public static readonly ConstructorInfo DecFromParts = GetConstructor(typeof(decimal), typeof(int), typeof(int), typeof(int), typeof(bool), typeof(byte));
134         public static readonly ConstructorInfo DecFromInt32 = GetConstructor(typeof(decimal), typeof(int));
135         public static readonly ConstructorInfo DecFromInt64 = GetConstructor(typeof(decimal), typeof(long));
136         public static readonly ConstructorInfo Debuggable = GetConstructor(typeof(DebuggableAttribute), typeof(DebuggableAttribute.DebuggingModes));
137         public static readonly ConstructorInfo NonUserCode = GetConstructor(typeof(DebuggerNonUserCodeAttribute));
138         public static readonly ConstructorInfo QName = GetConstructor(typeof(XmlQualifiedName), typeof(string), typeof(string));
139         public static readonly ConstructorInfo StepThrough = GetConstructor(typeof(DebuggerStepThroughAttribute));
140         public static readonly ConstructorInfo Transparent = GetConstructor(typeof(SecurityTransparentAttribute));
141 
GetConstructor(Type className)142         private static ConstructorInfo GetConstructor(Type className)
143         {
144             ConstructorInfo constrInfo = className.GetConstructor(new Type[] { });
145             Debug.Assert(constrInfo != null, "Constructor " + className + " cannot be null.");
146             return constrInfo;
147         }
148 
GetConstructor(Type className, params Type[] args)149         private static ConstructorInfo GetConstructor(Type className, params Type[] args)
150         {
151             ConstructorInfo constrInfo = className.GetConstructor(args);
152             Debug.Assert(constrInfo != null, "Constructor " + className + " cannot be null.");
153             return constrInfo;
154         }
155     }
156 
157 
158     /// <summary>
159     /// List of all XmlIL runtime methods.
160     /// </summary>
161     internal static class XmlILMethods
162     {
163         // Iterators
164         public static readonly MethodInfo AncCreate = GetMethod(typeof(AncestorIterator), "Create");
165         public static readonly MethodInfo AncNext = GetMethod(typeof(AncestorIterator), "MoveNext");
166         public static readonly MethodInfo AncDOCreate = GetMethod(typeof(AncestorDocOrderIterator), "Create");
167         public static readonly MethodInfo AncDONext = GetMethod(typeof(AncestorDocOrderIterator), "MoveNext");
168         public static readonly MethodInfo AttrContentCreate = GetMethod(typeof(AttributeContentIterator), "Create");
169         public static readonly MethodInfo AttrContentNext = GetMethod(typeof(AttributeContentIterator), "MoveNext");
170         public static readonly MethodInfo AttrCreate = GetMethod(typeof(AttributeIterator), "Create");
171         public static readonly MethodInfo AttrNext = GetMethod(typeof(AttributeIterator), "MoveNext");
172         public static readonly MethodInfo ContentCreate = GetMethod(typeof(ContentIterator), "Create");
173         public static readonly MethodInfo ContentNext = GetMethod(typeof(ContentIterator), "MoveNext");
174         public static readonly MethodInfo ContentMergeCreate = GetMethod(typeof(ContentMergeIterator), "Create");
175         public static readonly MethodInfo ContentMergeNext = GetMethod(typeof(ContentMergeIterator), "MoveNext");
176         public static readonly MethodInfo DescCreate = GetMethod(typeof(DescendantIterator), "Create");
177         public static readonly MethodInfo DescNext = GetMethod(typeof(DescendantIterator), "MoveNext");
178         public static readonly MethodInfo DescMergeCreate = GetMethod(typeof(DescendantMergeIterator), "Create");
179         public static readonly MethodInfo DescMergeNext = GetMethod(typeof(DescendantMergeIterator), "MoveNext");
180         public static readonly MethodInfo DiffCreate = GetMethod(typeof(DifferenceIterator), "Create");
181         public static readonly MethodInfo DiffNext = GetMethod(typeof(DifferenceIterator), "MoveNext");
182         public static readonly MethodInfo DodMergeCreate = GetMethod(typeof(DodSequenceMerge), "Create");
183         public static readonly MethodInfo DodMergeAdd = GetMethod(typeof(DodSequenceMerge), "AddSequence");
184         public static readonly MethodInfo DodMergeSeq = GetMethod(typeof(DodSequenceMerge), "MergeSequences");
185         public static readonly MethodInfo ElemContentCreate = GetMethod(typeof(ElementContentIterator), "Create");
186         public static readonly MethodInfo ElemContentNext = GetMethod(typeof(ElementContentIterator), "MoveNext");
187         public static readonly MethodInfo FollSibCreate = GetMethod(typeof(FollowingSiblingIterator), "Create");
188         public static readonly MethodInfo FollSibNext = GetMethod(typeof(FollowingSiblingIterator), "MoveNext");
189         public static readonly MethodInfo FollSibMergeCreate = GetMethod(typeof(FollowingSiblingMergeIterator), "Create");
190         public static readonly MethodInfo FollSibMergeNext = GetMethod(typeof(FollowingSiblingMergeIterator), "MoveNext");
191         public static readonly MethodInfo IdCreate = GetMethod(typeof(IdIterator), "Create");
192         public static readonly MethodInfo IdNext = GetMethod(typeof(IdIterator), "MoveNext");
193         public static readonly MethodInfo InterCreate = GetMethod(typeof(IntersectIterator), "Create");
194         public static readonly MethodInfo InterNext = GetMethod(typeof(IntersectIterator), "MoveNext");
195         public static readonly MethodInfo KindContentCreate = GetMethod(typeof(NodeKindContentIterator), "Create");
196         public static readonly MethodInfo KindContentNext = GetMethod(typeof(NodeKindContentIterator), "MoveNext");
197         public static readonly MethodInfo NmspCreate = GetMethod(typeof(NamespaceIterator), "Create");
198         public static readonly MethodInfo NmspNext = GetMethod(typeof(NamespaceIterator), "MoveNext");
199         public static readonly MethodInfo NodeRangeCreate = GetMethod(typeof(NodeRangeIterator), "Create");
200         public static readonly MethodInfo NodeRangeNext = GetMethod(typeof(NodeRangeIterator), "MoveNext");
201         public static readonly MethodInfo ParentCreate = GetMethod(typeof(ParentIterator), "Create");
202         public static readonly MethodInfo ParentNext = GetMethod(typeof(ParentIterator), "MoveNext");
203         public static readonly MethodInfo PrecCreate = GetMethod(typeof(PrecedingIterator), "Create");
204         public static readonly MethodInfo PrecNext = GetMethod(typeof(PrecedingIterator), "MoveNext");
205         public static readonly MethodInfo PreSibCreate = GetMethod(typeof(PrecedingSiblingIterator), "Create");
206         public static readonly MethodInfo PreSibNext = GetMethod(typeof(PrecedingSiblingIterator), "MoveNext");
207         public static readonly MethodInfo PreSibDOCreate = GetMethod(typeof(PrecedingSiblingDocOrderIterator), "Create");
208         public static readonly MethodInfo PreSibDONext = GetMethod(typeof(PrecedingSiblingDocOrderIterator), "MoveNext");
209         public static readonly MethodInfo SortKeyCreate = GetMethod(typeof(XmlSortKeyAccumulator), "Create");
210         public static readonly MethodInfo SortKeyDateTime = GetMethod(typeof(XmlSortKeyAccumulator), "AddDateTimeSortKey");
211         public static readonly MethodInfo SortKeyDecimal = GetMethod(typeof(XmlSortKeyAccumulator), "AddDecimalSortKey");
212         public static readonly MethodInfo SortKeyDouble = GetMethod(typeof(XmlSortKeyAccumulator), "AddDoubleSortKey");
213         public static readonly MethodInfo SortKeyEmpty = GetMethod(typeof(XmlSortKeyAccumulator), "AddEmptySortKey");
214         public static readonly MethodInfo SortKeyFinish = GetMethod(typeof(XmlSortKeyAccumulator), "FinishSortKeys");
215         public static readonly MethodInfo SortKeyInt = GetMethod(typeof(XmlSortKeyAccumulator), "AddIntSortKey");
216         public static readonly MethodInfo SortKeyInteger = GetMethod(typeof(XmlSortKeyAccumulator), "AddIntegerSortKey");
217         public static readonly MethodInfo SortKeyKeys = GetMethod(typeof(XmlSortKeyAccumulator), "get_Keys");
218         public static readonly MethodInfo SortKeyString = GetMethod(typeof(XmlSortKeyAccumulator), "AddStringSortKey");
219         public static readonly MethodInfo UnionCreate = GetMethod(typeof(UnionIterator), "Create");
220         public static readonly MethodInfo UnionNext = GetMethod(typeof(UnionIterator), "MoveNext");
221         public static readonly MethodInfo XPFollCreate = GetMethod(typeof(XPathFollowingIterator), "Create");
222         public static readonly MethodInfo XPFollNext = GetMethod(typeof(XPathFollowingIterator), "MoveNext");
223         public static readonly MethodInfo XPFollMergeCreate = GetMethod(typeof(XPathFollowingMergeIterator), "Create");
224         public static readonly MethodInfo XPFollMergeNext = GetMethod(typeof(XPathFollowingMergeIterator), "MoveNext");
225         public static readonly MethodInfo XPPrecCreate = GetMethod(typeof(XPathPrecedingIterator), "Create");
226         public static readonly MethodInfo XPPrecNext = GetMethod(typeof(XPathPrecedingIterator), "MoveNext");
227         public static readonly MethodInfo XPPrecDOCreate = GetMethod(typeof(XPathPrecedingDocOrderIterator), "Create");
228         public static readonly MethodInfo XPPrecDONext = GetMethod(typeof(XPathPrecedingDocOrderIterator), "MoveNext");
229         public static readonly MethodInfo XPPrecMergeCreate = GetMethod(typeof(XPathPrecedingMergeIterator), "Create");
230         public static readonly MethodInfo XPPrecMergeNext = GetMethod(typeof(XPathPrecedingMergeIterator), "MoveNext");
231 
232         // XmlQueryRuntime
233         public static readonly MethodInfo AddNewIndex = GetMethod(typeof(XmlQueryRuntime), "AddNewIndex");
234         public static readonly MethodInfo ChangeTypeXsltArg = GetMethod(typeof(XmlQueryRuntime), "ChangeTypeXsltArgument", typeof(int), typeof(object), typeof(Type));
235         public static readonly MethodInfo ChangeTypeXsltResult = GetMethod(typeof(XmlQueryRuntime), "ChangeTypeXsltResult");
236         public static readonly MethodInfo CompPos = GetMethod(typeof(XmlQueryRuntime), "ComparePosition");
237         public static readonly MethodInfo Context = GetMethod(typeof(XmlQueryRuntime), "get_ExternalContext");
238         public static readonly MethodInfo CreateCollation = GetMethod(typeof(XmlQueryRuntime), "CreateCollation");
239         public static readonly MethodInfo DocOrder = GetMethod(typeof(XmlQueryRuntime), "DocOrderDistinct");
240         public static readonly MethodInfo EndRtfConstr = GetMethod(typeof(XmlQueryRuntime), "EndRtfConstruction");
241         public static readonly MethodInfo EndSeqConstr = GetMethod(typeof(XmlQueryRuntime), "EndSequenceConstruction");
242         public static readonly MethodInfo FindIndex = GetMethod(typeof(XmlQueryRuntime), "FindIndex");
243         public static readonly MethodInfo GenId = GetMethod(typeof(XmlQueryRuntime), "GenerateId");
244         public static readonly MethodInfo GetAtomizedName = GetMethod(typeof(XmlQueryRuntime), "GetAtomizedName");
245         public static readonly MethodInfo GetCollation = GetMethod(typeof(XmlQueryRuntime), "GetCollation");
246         public static readonly MethodInfo GetEarly = GetMethod(typeof(XmlQueryRuntime), "GetEarlyBoundObject");
247         public static readonly MethodInfo GetNameFilter = GetMethod(typeof(XmlQueryRuntime), "GetNameFilter");
248         public static readonly MethodInfo GetOutput = GetMethod(typeof(XmlQueryRuntime), "get_Output");
249         public static readonly MethodInfo GetGlobalValue = GetMethod(typeof(XmlQueryRuntime), "GetGlobalValue");
250         public static readonly MethodInfo GetTypeFilter = GetMethod(typeof(XmlQueryRuntime), "GetTypeFilter");
251         public static readonly MethodInfo GlobalComputed = GetMethod(typeof(XmlQueryRuntime), "IsGlobalComputed");
252         public static readonly MethodInfo ItemMatchesCode = GetMethod(typeof(XmlQueryRuntime), "MatchesXmlType", typeof(XPathItem), typeof(XmlTypeCode));
253         public static readonly MethodInfo ItemMatchesType = GetMethod(typeof(XmlQueryRuntime), "MatchesXmlType", typeof(XPathItem), typeof(int));
254         public static readonly MethodInfo QNameEqualLit = GetMethod(typeof(XmlQueryRuntime), "IsQNameEqual", typeof(XPathNavigator), typeof(int), typeof(int));
255         public static readonly MethodInfo QNameEqualNav = GetMethod(typeof(XmlQueryRuntime), "IsQNameEqual", typeof(XPathNavigator), typeof(XPathNavigator));
256         public static readonly MethodInfo RtfConstr = GetMethod(typeof(XmlQueryRuntime), "TextRtfConstruction");
257         public static readonly MethodInfo SendMessage = GetMethod(typeof(XmlQueryRuntime), "SendMessage");
258         public static readonly MethodInfo SeqMatchesCode = GetMethod(typeof(XmlQueryRuntime), "MatchesXmlType", typeof(IList<XPathItem>), typeof(XmlTypeCode));
259         public static readonly MethodInfo SeqMatchesType = GetMethod(typeof(XmlQueryRuntime), "MatchesXmlType", typeof(IList<XPathItem>), typeof(int));
260         public static readonly MethodInfo SetGlobalValue = GetMethod(typeof(XmlQueryRuntime), "SetGlobalValue");
261         public static readonly MethodInfo StartRtfConstr = GetMethod(typeof(XmlQueryRuntime), "StartRtfConstruction");
262         public static readonly MethodInfo StartSeqConstr = GetMethod(typeof(XmlQueryRuntime), "StartSequenceConstruction");
263         public static readonly MethodInfo TagAndMappings = GetMethod(typeof(XmlQueryRuntime), "ParseTagName", typeof(string), typeof(int));
264         public static readonly MethodInfo TagAndNamespace = GetMethod(typeof(XmlQueryRuntime), "ParseTagName", typeof(string), typeof(string));
265         public static readonly MethodInfo ThrowException = GetMethod(typeof(XmlQueryRuntime), "ThrowException");
266         public static readonly MethodInfo XsltLib = GetMethod(typeof(XmlQueryRuntime), "get_XsltFunctions");
267 
268         // XmlQueryContext
269         public static readonly MethodInfo GetDataSource = GetMethod(typeof(XmlQueryContext), "GetDataSource");
270         public static readonly MethodInfo GetDefaultDataSource = GetMethod(typeof(XmlQueryContext), "get_DefaultDataSource");
271         public static readonly MethodInfo GetParam = GetMethod(typeof(XmlQueryContext), "GetParameter");
272         public static readonly MethodInfo InvokeXsltLate = GetMethod(typeof(XmlQueryContext), "InvokeXsltLateBoundFunction");
273 
274         // XmlILIndex
275         public static readonly MethodInfo IndexAdd = GetMethod(typeof(XmlILIndex), "Add");
276         public static readonly MethodInfo IndexLookup = GetMethod(typeof(XmlILIndex), "Lookup");
277 
278         // XPathItem
279         public static readonly MethodInfo ItemIsNode = GetMethod(typeof(XPathItem), "get_IsNode");
280         public static readonly MethodInfo Value = GetMethod(typeof(XPathItem), "get_Value");
281         public static readonly MethodInfo ValueAsAny = GetMethod(typeof(XPathItem), "ValueAs", typeof(Type), typeof(IXmlNamespaceResolver));
282 
283         // XPathNavigator
284         public static readonly MethodInfo NavClone = GetMethod(typeof(XPathNavigator), "Clone");
285         public static readonly MethodInfo NavLocalName = GetMethod(typeof(XPathNavigator), "get_LocalName");
286         public static readonly MethodInfo NavMoveAttr = GetMethod(typeof(XPathNavigator), "MoveToAttribute", typeof(string), typeof(string));
287         public static readonly MethodInfo NavMoveId = GetMethod(typeof(XPathNavigator), "MoveToId");
288         public static readonly MethodInfo NavMoveParent = GetMethod(typeof(XPathNavigator), "MoveToParent");
289         public static readonly MethodInfo NavMoveRoot = GetMethod(typeof(XPathNavigator), "MoveToRoot");
290         public static readonly MethodInfo NavMoveTo = GetMethod(typeof(XPathNavigator), "MoveTo");
291         public static readonly MethodInfo NavNmsp = GetMethod(typeof(XPathNavigator), "get_NamespaceURI");
292         public static readonly MethodInfo NavPrefix = GetMethod(typeof(XPathNavigator), "get_Prefix");
293         public static readonly MethodInfo NavSamePos = GetMethod(typeof(XPathNavigator), "IsSamePosition");
294         public static readonly MethodInfo NavType = GetMethod(typeof(XPathNavigator), "get_NodeType");
295 
296         // XmlQueryOutput methods
297         public static readonly MethodInfo StartElemLitName = GetMethod(typeof(XmlQueryOutput), "WriteStartElement", typeof(string), typeof(string), typeof(string));
298         public static readonly MethodInfo StartElemLocName = GetMethod(typeof(XmlQueryOutput), "WriteStartElementLocalName", typeof(string));
299         public static readonly MethodInfo EndElemStackName = GetMethod(typeof(XmlQueryOutput), "WriteEndElement");
300         public static readonly MethodInfo StartAttrLitName = GetMethod(typeof(XmlQueryOutput), "WriteStartAttribute", typeof(string), typeof(string), typeof(string));
301         public static readonly MethodInfo StartAttrLocName = GetMethod(typeof(XmlQueryOutput), "WriteStartAttributeLocalName", typeof(string));
302         public static readonly MethodInfo EndAttr = GetMethod(typeof(XmlQueryOutput), "WriteEndAttribute");
303         public static readonly MethodInfo Text = GetMethod(typeof(XmlQueryOutput), "WriteString");
304         public static readonly MethodInfo NoEntText = GetMethod(typeof(XmlQueryOutput), "WriteRaw", typeof(string));
305 
306         public static readonly MethodInfo StartTree = GetMethod(typeof(XmlQueryOutput), "StartTree");
307         public static readonly MethodInfo EndTree = GetMethod(typeof(XmlQueryOutput), "EndTree");
308 
309         public static readonly MethodInfo StartElemLitNameUn = GetMethod(typeof(XmlQueryOutput), "WriteStartElementUnchecked", typeof(string), typeof(string), typeof(string));
310         public static readonly MethodInfo StartElemLocNameUn = GetMethod(typeof(XmlQueryOutput), "WriteStartElementUnchecked", typeof(string));
311         public static readonly MethodInfo StartContentUn = GetMethod(typeof(XmlQueryOutput), "StartElementContentUnchecked");
312         public static readonly MethodInfo EndElemLitNameUn = GetMethod(typeof(XmlQueryOutput), "WriteEndElementUnchecked", typeof(string), typeof(string), typeof(string));
313         public static readonly MethodInfo EndElemLocNameUn = GetMethod(typeof(XmlQueryOutput), "WriteEndElementUnchecked", typeof(string));
314         public static readonly MethodInfo StartAttrLitNameUn = GetMethod(typeof(XmlQueryOutput), "WriteStartAttributeUnchecked", typeof(string), typeof(string), typeof(string));
315         public static readonly MethodInfo StartAttrLocNameUn = GetMethod(typeof(XmlQueryOutput), "WriteStartAttributeUnchecked", typeof(string));
316         public static readonly MethodInfo EndAttrUn = GetMethod(typeof(XmlQueryOutput), "WriteEndAttributeUnchecked");
317         public static readonly MethodInfo NamespaceDeclUn = GetMethod(typeof(XmlQueryOutput), "WriteNamespaceDeclarationUnchecked");
318         public static readonly MethodInfo TextUn = GetMethod(typeof(XmlQueryOutput), "WriteStringUnchecked");
319         public static readonly MethodInfo NoEntTextUn = GetMethod(typeof(XmlQueryOutput), "WriteRawUnchecked");
320 
321         public static readonly MethodInfo StartRoot = GetMethod(typeof(XmlQueryOutput), "WriteStartRoot");
322         public static readonly MethodInfo EndRoot = GetMethod(typeof(XmlQueryOutput), "WriteEndRoot");
323         public static readonly MethodInfo StartElemCopyName = GetMethod(typeof(XmlQueryOutput), "WriteStartElementComputed", typeof(XPathNavigator));
324         public static readonly MethodInfo StartElemMapName = GetMethod(typeof(XmlQueryOutput), "WriteStartElementComputed", typeof(string), typeof(int));
325         public static readonly MethodInfo StartElemNmspName = GetMethod(typeof(XmlQueryOutput), "WriteStartElementComputed", typeof(string), typeof(string));
326         public static readonly MethodInfo StartElemQName = GetMethod(typeof(XmlQueryOutput), "WriteStartElementComputed", typeof(XmlQualifiedName));
327         public static readonly MethodInfo StartAttrCopyName = GetMethod(typeof(XmlQueryOutput), "WriteStartAttributeComputed", typeof(XPathNavigator));
328         public static readonly MethodInfo StartAttrMapName = GetMethod(typeof(XmlQueryOutput), "WriteStartAttributeComputed", typeof(string), typeof(int));
329         public static readonly MethodInfo StartAttrNmspName = GetMethod(typeof(XmlQueryOutput), "WriteStartAttributeComputed", typeof(string), typeof(string));
330         public static readonly MethodInfo StartAttrQName = GetMethod(typeof(XmlQueryOutput), "WriteStartAttributeComputed", typeof(XmlQualifiedName));
331         public static readonly MethodInfo NamespaceDecl = GetMethod(typeof(XmlQueryOutput), "WriteNamespaceDeclaration");
332         public static readonly MethodInfo StartComment = GetMethod(typeof(XmlQueryOutput), "WriteStartComment");
333         public static readonly MethodInfo CommentText = GetMethod(typeof(XmlQueryOutput), "WriteCommentString");
334         public static readonly MethodInfo EndComment = GetMethod(typeof(XmlQueryOutput), "WriteEndComment");
335         public static readonly MethodInfo StartPI = GetMethod(typeof(XmlQueryOutput), "WriteStartProcessingInstruction");
336         public static readonly MethodInfo PIText = GetMethod(typeof(XmlQueryOutput), "WriteProcessingInstructionString");
337         public static readonly MethodInfo EndPI = GetMethod(typeof(XmlQueryOutput), "WriteEndProcessingInstruction");
338         public static readonly MethodInfo WriteItem = GetMethod(typeof(XmlQueryOutput), "WriteItem");
339         public static readonly MethodInfo CopyOf = GetMethod(typeof(XmlQueryOutput), "XsltCopyOf");
340         public static readonly MethodInfo StartCopy = GetMethod(typeof(XmlQueryOutput), "StartCopy");
341         public static readonly MethodInfo EndCopy = GetMethod(typeof(XmlQueryOutput), "EndCopy");
342 
343         // Datatypes
344         public static readonly MethodInfo DecAdd = GetMethod(typeof(decimal), "Add");
345         public static readonly MethodInfo DecCmp = GetMethod(typeof(decimal), "Compare", typeof(decimal), typeof(decimal));
346         public static readonly MethodInfo DecEq = GetMethod(typeof(decimal), "Equals", typeof(decimal), typeof(decimal));
347         public static readonly MethodInfo DecSub = GetMethod(typeof(decimal), "Subtract");
348         public static readonly MethodInfo DecMul = GetMethod(typeof(decimal), "Multiply");
349         public static readonly MethodInfo DecDiv = GetMethod(typeof(decimal), "Divide");
350         public static readonly MethodInfo DecRem = GetMethod(typeof(decimal), "Remainder");
351         public static readonly MethodInfo DecNeg = GetMethod(typeof(decimal), "Negate");
352         public static readonly MethodInfo QNameEq = GetMethod(typeof(XmlQualifiedName), "Equals");
353         public static readonly MethodInfo StrEq = GetMethod(typeof(string), "Equals", typeof(string), typeof(string));
354         public static readonly MethodInfo StrCat2 = GetMethod(typeof(string), "Concat", typeof(string), typeof(string));
355         public static readonly MethodInfo StrCat3 = GetMethod(typeof(string), "Concat", typeof(string), typeof(string), typeof(string));
356         public static readonly MethodInfo StrCat4 = GetMethod(typeof(string), "Concat", typeof(string), typeof(string), typeof(string), typeof(string));
357         public static readonly MethodInfo StrCmp = GetMethod(typeof(string), "CompareOrdinal", typeof(string), typeof(string));
358         public static readonly MethodInfo StrLen = GetMethod(typeof(string), "get_Length");
359 
360         // XsltConvert
361         public static readonly MethodInfo DblToDec = GetMethod(typeof(XsltConvert), "ToDecimal", typeof(double));
362         public static readonly MethodInfo DblToInt = GetMethod(typeof(XsltConvert), "ToInt", typeof(double));
363         public static readonly MethodInfo DblToLng = GetMethod(typeof(XsltConvert), "ToLong", typeof(double));
364         public static readonly MethodInfo DblToStr = GetMethod(typeof(XsltConvert), "ToString", typeof(double));
365         public static readonly MethodInfo DecToDbl = GetMethod(typeof(XsltConvert), "ToDouble", typeof(decimal));
366         public static readonly MethodInfo DTToStr = GetMethod(typeof(XsltConvert), "ToString", typeof(DateTime));
367         public static readonly MethodInfo IntToDbl = GetMethod(typeof(XsltConvert), "ToDouble", typeof(int));
368         public static readonly MethodInfo LngToDbl = GetMethod(typeof(XsltConvert), "ToDouble", typeof(long));
369         public static readonly MethodInfo StrToDbl = GetMethod(typeof(XsltConvert), "ToDouble", typeof(string));
370         public static readonly MethodInfo StrToDT = GetMethod(typeof(XsltConvert), "ToDateTime", typeof(string));
371 
372         public static readonly MethodInfo ItemToBool = GetMethod(typeof(XsltConvert), "ToBoolean", typeof(XPathItem));
373         public static readonly MethodInfo ItemToDbl = GetMethod(typeof(XsltConvert), "ToDouble", typeof(XPathItem));
374         public static readonly MethodInfo ItemToStr = GetMethod(typeof(XsltConvert), "ToString", typeof(XPathItem));
375         public static readonly MethodInfo ItemToNode = GetMethod(typeof(XsltConvert), "ToNode", typeof(XPathItem));
376         public static readonly MethodInfo ItemToNodes = GetMethod(typeof(XsltConvert), "ToNodeSet", typeof(XPathItem));
377 
378         public static readonly MethodInfo ItemsToBool = GetMethod(typeof(XsltConvert), "ToBoolean", typeof(IList<XPathItem>));
379         public static readonly MethodInfo ItemsToDbl = GetMethod(typeof(XsltConvert), "ToDouble", typeof(IList<XPathItem>));
380         public static readonly MethodInfo ItemsToNode = GetMethod(typeof(XsltConvert), "ToNode", typeof(IList<XPathItem>));
381         public static readonly MethodInfo ItemsToNodes = GetMethod(typeof(XsltConvert), "ToNodeSet", typeof(IList<XPathItem>));
382         public static readonly MethodInfo ItemsToStr = GetMethod(typeof(XsltConvert), "ToString", typeof(IList<XPathItem>));
383 
384         // StringConcat
385         public static readonly MethodInfo StrCatCat = GetMethod(typeof(StringConcat), "Concat");
386         public static readonly MethodInfo StrCatClear = GetMethod(typeof(StringConcat), "Clear");
387         public static readonly MethodInfo StrCatResult = GetMethod(typeof(StringConcat), "GetResult");
388         public static readonly MethodInfo StrCatDelim = GetMethod(typeof(StringConcat), "set_Delimiter");
389 
390         // XmlILStorageConverter
391         public static readonly MethodInfo NavsToItems = GetMethod(typeof(XmlILStorageConverter), "NavigatorsToItems");
392         public static readonly MethodInfo ItemsToNavs = GetMethod(typeof(XmlILStorageConverter), "ItemsToNavigators");
393 
394         // XmlQueryNodeSequence
395         public static readonly MethodInfo SetDod = GetMethod(typeof(XmlQueryNodeSequence), "set_IsDocOrderDistinct");
396 
397         // Miscellaneous
398         public static readonly MethodInfo GetTypeFromHandle = GetMethod(typeof(Type), "GetTypeFromHandle");
399         public static readonly MethodInfo InitializeArray = GetMethod(typeof(System.Runtime.CompilerServices.RuntimeHelpers), "InitializeArray");
400         public static readonly Dictionary<Type, XmlILStorageMethods> StorageMethods;
401 
XmlILMethods()402         static XmlILMethods()
403         {
404             StorageMethods = new Dictionary<Type, XmlILStorageMethods>();
405             StorageMethods[typeof(string)] = new XmlILStorageMethods(typeof(string));
406             StorageMethods[typeof(bool)] = new XmlILStorageMethods(typeof(bool));
407             StorageMethods[typeof(int)] = new XmlILStorageMethods(typeof(int));
408             StorageMethods[typeof(long)] = new XmlILStorageMethods(typeof(long));
409             StorageMethods[typeof(decimal)] = new XmlILStorageMethods(typeof(decimal));
410             StorageMethods[typeof(double)] = new XmlILStorageMethods(typeof(double));
411             StorageMethods[typeof(float)] = new XmlILStorageMethods(typeof(float));
412             StorageMethods[typeof(DateTime)] = new XmlILStorageMethods(typeof(DateTime));
413             StorageMethods[typeof(byte[])] = new XmlILStorageMethods(typeof(byte[]));
414             StorageMethods[typeof(XmlQualifiedName)] = new XmlILStorageMethods(typeof(XmlQualifiedName));
415             StorageMethods[typeof(TimeSpan)] = new XmlILStorageMethods(typeof(TimeSpan));
416             StorageMethods[typeof(XPathItem)] = new XmlILStorageMethods(typeof(XPathItem));
417             StorageMethods[typeof(XPathNavigator)] = new XmlILStorageMethods(typeof(XPathNavigator));
418         }
419 
GetMethod(Type className, string methName)420         public static MethodInfo GetMethod(Type className, string methName)
421         {
422             MethodInfo methInfo = className.GetMethod(methName);
423             Debug.Assert(methInfo != null, "Method " + className.Name + "." + methName + " cannot be null.");
424             return methInfo;
425         }
426 
GetMethod(Type className, string methName, params Type[] args)427         public static MethodInfo GetMethod(Type className, string methName, params Type[] args)
428         {
429             MethodInfo methInfo = className.GetMethod(methName, args);
430             Debug.Assert(methInfo != null, "Method " + methName + " cannot be null.");
431             return methInfo;
432         }
433     }
434 
435 
436     /// <summary>
437     /// When named nodes are constructed, there are several possible ways for their names to be created.
438     /// </summary>
439     internal enum GenerateNameType
440     {
441         LiteralLocalName,       // Local name is a literal string; namespace is null
442         LiteralName,            // All parts of the name are literal strings
443         CopiedName,             // Name should be copied from a navigator
444         TagNameAndMappings,     // Tagname contains prefix:localName and prefix is mapped to a namespace
445         TagNameAndNamespace,    // Tagname contains prefix:localName and namespace is provided
446         QName,                  // Name is computed QName (no prefix available)
447         StackName,              // Element name has already been pushed onto XmlQueryOutput stack
448     }
449 
450     /// <summary>
451     /// Contains helper methods used during the code generation phase.
452     /// </summary>
453     internal class GenerateHelper
454     {
455         private MethodBase _methInfo;
456         private ILGenerator _ilgen;
457         private LocalBuilder _locXOut;
458         private XmlILModule _module;
459         private bool _isDebug, _initWriters;
460         private StaticDataManager _staticData;
461         private ISourceLineInfo _lastSourceInfo;
462         private MethodInfo _methSyncToNav;
463 
464 #if DEBUG
465         private int _lblNum;
466         private Hashtable _symbols;
467         private int _numLocals;
468         private string _sourceFile;
469         private TextWriter _writerDump;
470 #endif
471 
472         /// <summary>
473         /// Cache metadata used during code-generation phase.
474         /// </summary>
475         // SxS note: Using hardcoded "dump.il" is an SxS issue. Since we are doing this ONLY in debug builds
476         // and only for tracing purposes and MakeVersionSafeName does not seem to be able to handle file
477         // extensions correctly I decided to suppress the SxS message (as advised by SxS guys).
GenerateHelper(XmlILModule module, bool isDebug)478         public GenerateHelper(XmlILModule module, bool isDebug)
479         {
480             _isDebug = isDebug;
481             _module = module;
482             _staticData = new StaticDataManager();
483 
484 #if DEBUG
485             if (XmlILTrace.IsEnabled)
486                 XmlILTrace.PrepareTraceWriter("dump.il");
487 #endif
488         }
489 
490         /// <summary>
491         /// Begin generating code within a new method.
492         /// </summary>
493         // SxS note: Using hardcoded "dump.il" is an SxS issue. Since we are doing this ONLY in debug builds
494         // and only for tracing purposes and MakeVersionSafeName does not seem to be able to handle file
495         // extensions correctly I decided to suppress the SxS message (as advised by SxS guys).
MethodBegin(MethodBase methInfo, ISourceLineInfo sourceInfo, bool initWriters)496         public void MethodBegin(MethodBase methInfo, ISourceLineInfo sourceInfo, bool initWriters)
497         {
498             _methInfo = methInfo;
499             _ilgen = XmlILModule.DefineMethodBody(methInfo);
500             _lastSourceInfo = null;
501 
502 #if DEBUG
503             if (XmlILTrace.IsEnabled)
504             {
505                 _numLocals = 0;
506                 _symbols = new Hashtable();
507                 _lblNum = 0;
508                 _sourceFile = null;
509 
510                 _writerDump = XmlILTrace.GetTraceWriter("dump.il");
511                 _writerDump.WriteLine(".method {0}()", methInfo.Name);
512                 _writerDump.WriteLine("{");
513             }
514 #endif
515 
516             if (_isDebug)
517             {
518                 DebugStartScope();
519 
520                 // DebugInfo: Sequence point just before generating code for this function
521                 if (sourceInfo != null)
522                 {
523                     // Don't call DebugSequencePoint, as it puts Nop *before* the sequence point.  That is
524                     // wrong in this case, because we need source line information to be emitted before any
525                     // IL instruction so that stepping into this function won't end up in the assembly window.
526                     // We still guarantee that:
527                     //   1. Two sequence points are never adjacent, since this is the 1st sequence point
528                     //   2. Stack depth is 0, since this is the very beginning of the method
529                     MarkSequencePoint(sourceInfo);
530                     Emit(OpCodes.Nop);
531                 }
532             }
533             else if (_module.EmitSymbols)
534             {
535                 // For a retail build, put source information on methods only
536                 if (sourceInfo != null)
537                 {
538                     MarkSequencePoint(sourceInfo);
539                     // Set this.lastSourceInfo back to null to prevent generating additional sequence points
540                     // in this method.
541                     _lastSourceInfo = null;
542                 }
543             }
544 
545             _initWriters = false;
546             if (initWriters)
547             {
548                 EnsureWriter();
549                 LoadQueryRuntime();
550                 Call(XmlILMethods.GetOutput);
551                 Emit(OpCodes.Stloc, _locXOut);
552             }
553         }
554 
555         /// <summary>
556         /// Generate "ret" instruction and branch fixup jump table.
557         /// </summary>
MethodEnd()558         public void MethodEnd()
559         {
560             Emit(OpCodes.Ret);
561 
562 #if DEBUG
563             if (XmlILTrace.IsEnabled)
564             {
565                 _writerDump.WriteLine("}");
566                 _writerDump.WriteLine("");
567                 _writerDump.Close();
568             }
569 #endif
570 
571             if (_isDebug)
572                 DebugEndScope();
573         }
574 
575 
576         //-----------------------------------------------
577         // Helper Global Methods
578         //-----------------------------------------------
579 
580         /// <summary>
581         /// Call a static method which attempts to reuse a navigator.
582         /// </summary>
CallSyncToNavigator()583         public void CallSyncToNavigator()
584         {
585             // Get helper method from module
586             if (_methSyncToNav == null)
587                 _methSyncToNav = _module.FindMethod("SyncToNavigator");
588 
589             Call(_methSyncToNav);
590         }
591 
592         //-----------------------------------------------
593         // StaticDataManager
594         //-----------------------------------------------
595 
596         /// <summary>
597         /// This internal class manages literal names, literal types, and storage for global variables.
598         /// </summary>
599         public StaticDataManager StaticData
600         {
601             get { return _staticData; }
602         }
603 
604 
605         //-----------------------------------------------
606         // Constants
607         //-----------------------------------------------
608 
609         /// <summary>
610         /// Generate the optimal Ldc_I4 instruction based on intVal.
611         /// </summary>
LoadInteger(int intVal)612         public void LoadInteger(int intVal)
613         {
614             OpCode opcode;
615 
616             if (intVal >= -1 && intVal < 9)
617             {
618                 switch (intVal)
619                 {
620                     case -1: opcode = OpCodes.Ldc_I4_M1; break;
621                     case 0: opcode = OpCodes.Ldc_I4_0; break;
622                     case 1: opcode = OpCodes.Ldc_I4_1; break;
623                     case 2: opcode = OpCodes.Ldc_I4_2; break;
624                     case 3: opcode = OpCodes.Ldc_I4_3; break;
625                     case 4: opcode = OpCodes.Ldc_I4_4; break;
626                     case 5: opcode = OpCodes.Ldc_I4_5; break;
627                     case 6: opcode = OpCodes.Ldc_I4_6; break;
628                     case 7: opcode = OpCodes.Ldc_I4_7; break;
629                     case 8: opcode = OpCodes.Ldc_I4_8; break;
630                     default: Debug.Assert(false); return;
631                 }
632                 Emit(opcode);
633             }
634             else if (intVal >= -128 && intVal <= 127)
635                 Emit(OpCodes.Ldc_I4_S, (sbyte)intVal);
636             else
637                 Emit(OpCodes.Ldc_I4, intVal);
638         }
639 
LoadBoolean(bool boolVal)640         public void LoadBoolean(bool boolVal)
641         {
642             Emit(boolVal ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
643         }
644 
LoadType(Type clrTyp)645         public void LoadType(Type clrTyp)
646         {
647             Emit(OpCodes.Ldtoken, clrTyp);
648             Call(XmlILMethods.GetTypeFromHandle);
649         }
650 
651 
652         //-----------------------------------------------
653         // Local variables
654         //-----------------------------------------------
655 
656         /// <summary>
657         /// Generate a new local variable.  Add a numeric suffix to name that ensures that all
658         /// local variable names will be unique (for readability).
659         /// </summary>
DeclareLocal(string name, Type type)660         public LocalBuilder DeclareLocal(string name, Type type)
661         {
662             LocalBuilder locBldr = _ilgen.DeclareLocal(type);
663 #if DEBUG
664             if (XmlILTrace.IsEnabled)
665             {
666                 _symbols.Add(locBldr, name + _numLocals.ToString(CultureInfo.InvariantCulture));
667                 _numLocals++;
668             }
669 #endif
670             return locBldr;
671         }
672 
LoadQueryRuntime()673         public void LoadQueryRuntime()
674         {
675             Emit(OpCodes.Ldarg_0);
676         }
677 
LoadQueryContext()678         public void LoadQueryContext()
679         {
680             Emit(OpCodes.Ldarg_0);
681             Call(XmlILMethods.Context);
682         }
683 
LoadXsltLibrary()684         public void LoadXsltLibrary()
685         {
686             Emit(OpCodes.Ldarg_0);
687             Call(XmlILMethods.XsltLib);
688         }
689 
LoadQueryOutput()690         public void LoadQueryOutput()
691         {
692             Emit(OpCodes.Ldloc, _locXOut);
693         }
694 
695 
696         //-----------------------------------------------
697         // Parameters
698         //-----------------------------------------------
699 
LoadParameter(int paramPos)700         public void LoadParameter(int paramPos)
701         {
702             switch (paramPos)
703             {
704                 case 0: Emit(OpCodes.Ldarg_0); break;
705                 case 1: Emit(OpCodes.Ldarg_1); break;
706                 case 2: Emit(OpCodes.Ldarg_2); break;
707                 case 3: Emit(OpCodes.Ldarg_3); break;
708                 default:
709                     if (paramPos <= 255)
710                     {
711                         Emit(OpCodes.Ldarg_S, (byte)paramPos);
712                     }
713                     else if (paramPos <= ushort.MaxValue)
714                     {
715                         Emit(OpCodes.Ldarg, paramPos);
716                     }
717                     else
718                     {
719                         throw new XslTransformException(SR.XmlIl_TooManyParameters);
720                     }
721                     break;
722             }
723         }
724 
SetParameter(object paramId)725         public void SetParameter(object paramId)
726         {
727             int paramPos = (int)paramId;
728 
729             if (paramPos <= 255)
730             {
731                 Emit(OpCodes.Starg_S, (byte)paramPos);
732             }
733             else if (paramPos <= ushort.MaxValue)
734             {
735                 Emit(OpCodes.Starg, (int)paramPos);
736             }
737             else
738             {
739                 throw new XslTransformException(SR.XmlIl_TooManyParameters);
740             }
741         }
742 
743         //-----------------------------------------------
744         // Labels
745         //-----------------------------------------------
746 
747         /// <summary>
748         /// Branch to lblBranch and anchor lblMark.  If lblBranch = lblMark, then no need
749         /// to generate a "br" to the next instruction.
750         /// </summary>
BranchAndMark(Label lblBranch, Label lblMark)751         public void BranchAndMark(Label lblBranch, Label lblMark)
752         {
753             if (!lblBranch.Equals(lblMark))
754             {
755                 EmitUnconditionalBranch(OpCodes.Br, lblBranch);
756             }
757             MarkLabel(lblMark);
758         }
759 
760 
761         //-----------------------------------------------
762         // Comparison
763         //-----------------------------------------------
764 
765         /// <summary>
766         /// Compare the top value on the stack with the specified i4 using the specified relational
767         /// comparison opcode, and branch to lblBranch if the result is true.
768         /// </summary>
TestAndBranch(int i4, Label lblBranch, OpCode opcodeBranch)769         public void TestAndBranch(int i4, Label lblBranch, OpCode opcodeBranch)
770         {
771             switch (i4)
772             {
773                 case 0:
774                     // Beq or Bne can be shortened to Brfalse or Brtrue if comparing to 0
775                     if (opcodeBranch.Value == OpCodes.Beq.Value)
776                         opcodeBranch = OpCodes.Brfalse;
777                     else if (opcodeBranch.Value == OpCodes.Beq_S.Value)
778                         opcodeBranch = OpCodes.Brfalse_S;
779                     else if (opcodeBranch.Value == OpCodes.Bne_Un.Value)
780                         opcodeBranch = OpCodes.Brtrue;
781                     else if (opcodeBranch.Value == OpCodes.Bne_Un_S.Value)
782                         opcodeBranch = OpCodes.Brtrue_S;
783                     else
784                         goto default;
785                     break;
786 
787                 default:
788                     // Cannot use shortcut, so push integer onto the stack
789                     LoadInteger(i4);
790                     break;
791             }
792 
793             Emit(opcodeBranch, lblBranch);
794         }
795 
796         /// <summary>
797         /// Assume a branch instruction has already been issued.  If isTrueBranch is true, then the
798         /// true path is linked to lblBranch.  Otherwise, the false path is linked to lblBranch.
799         /// Convert this "branching" boolean logic into an explicit push of 1 or 0 onto the stack.
800         /// </summary>
ConvBranchToBool(Label lblBranch, bool isTrueBranch)801         public void ConvBranchToBool(Label lblBranch, bool isTrueBranch)
802         {
803             Label lblDone = DefineLabel();
804 
805             Emit(isTrueBranch ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1);
806             EmitUnconditionalBranch(OpCodes.Br_S, lblDone);
807             MarkLabel(lblBranch);
808             Emit(isTrueBranch ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
809             MarkLabel(lblDone);
810         }
811 
812 
813         //-----------------------------------------------
814         // Frequently used method and function calls
815         //-----------------------------------------------
816 
TailCall(MethodInfo meth)817         public void TailCall(MethodInfo meth)
818         {
819             Emit(OpCodes.Tailcall);
820             Call(meth);
821             Emit(OpCodes.Ret);
822         }
823 
824         [Conditional("DEBUG")]
TraceCall(OpCode opcode, MethodInfo meth)825         private void TraceCall(OpCode opcode, MethodInfo meth)
826         {
827 #if DEBUG
828             if (XmlILTrace.IsEnabled)
829             {
830                 StringBuilder strBldr = new StringBuilder();
831                 bool isFirst = true;
832                 string retType = "";
833 
834                 if (!(meth is MethodBuilder))
835                 {
836                     foreach (ParameterInfo paramInfo in meth.GetParameters())
837                     {
838                         if (isFirst)
839                             isFirst = false;
840                         else
841                             strBldr.Append(", ");
842                         strBldr.Append(paramInfo.ParameterType.Name);
843                     }
844                     retType = meth.ReturnType.Name;
845                 }
846 
847                 _writerDump.WriteLine("  {0, -10} {1} {2}({3})", new object[] { opcode.Name, retType, meth.Name, strBldr.ToString() });
848             }
849 #endif
850         }
851 
Call(MethodInfo meth)852         public void Call(MethodInfo meth)
853         {
854             OpCode opcode = meth.IsVirtual || meth.IsAbstract ? OpCodes.Callvirt : OpCodes.Call;
855 
856             TraceCall(opcode, meth);
857             _ilgen.Emit(opcode, meth);
858 
859             if (_lastSourceInfo != null)
860             {
861                 // Emit a "no source" sequence point, otherwise the debugger would return to the wrong line
862                 // once the call has finished.  We are guaranteed not to emit adjacent sequence points because
863                 // the Call instruction precedes this sequence point, and a nop instruction precedes other
864                 // sequence points.
865                 MarkSequencePoint(SourceLineInfo.NoSource);
866             }
867         }
868 
Construct(ConstructorInfo constr)869         public void Construct(ConstructorInfo constr)
870         {
871             Emit(OpCodes.Newobj, constr);
872         }
873 
CallConcatStrings(int cStrings)874         public void CallConcatStrings(int cStrings)
875         {
876             switch (cStrings)
877             {
878                 case 0:
879                     Emit(OpCodes.Ldstr, "");
880                     break;
881                 case 1:
882                     break;
883                 case 2:
884                     Call(XmlILMethods.StrCat2);
885                     break;
886                 case 3:
887                     Call(XmlILMethods.StrCat3);
888                     break;
889                 case 4:
890                     Call(XmlILMethods.StrCat4);
891                     break;
892                 default:
893                     Debug.Assert(false, "Shouldn't be called");
894                     break;
895             }
896         }
897 
898         /// <summary>
899         /// Assume that an object reference is on the IL stack.  Change the static Clr type from "clrTypeSrc" to "clrTypeDst"
900         /// </summary>
TreatAs(Type clrTypeSrc, Type clrTypeDst)901         public void TreatAs(Type clrTypeSrc, Type clrTypeDst)
902         {
903             // If source = destination, then no-op
904             if (clrTypeSrc == clrTypeDst)
905                 return;
906 
907             if (clrTypeSrc.IsValueType)
908             {
909                 // If source is a value type, then destination may only be typeof(object), so box
910                 Debug.Assert(clrTypeDst == typeof(object), "Invalid cast, since value types do not allow inheritance.");
911                 Emit(OpCodes.Box, clrTypeSrc);
912             }
913             else if (clrTypeDst.IsValueType)
914             {
915                 // If destination type is value type, then source may only be typeof(object), so unbox
916                 Debug.Assert(clrTypeSrc == typeof(object), "Invalid cast, since value types do not allow inheritance.");
917                 Emit(OpCodes.Unbox, clrTypeDst);
918                 Emit(OpCodes.Ldobj, clrTypeDst);
919             }
920             else if (clrTypeDst != typeof(object))
921             {
922                 // If source is not a value type, and destination type is typeof(object), then no-op
923                 // Otherwise, use Castclass to change the static type
924                 Debug.Assert(clrTypeSrc.IsAssignableFrom(clrTypeDst) || clrTypeDst.IsAssignableFrom(clrTypeSrc),
925                              "Invalid cast, since source type and destination type are not in same inheritance hierarchy.");
926                 Emit(OpCodes.Castclass, clrTypeDst);
927             }
928         }
929 
930 
931         //-----------------------------------------------
932         // Datatype methods
933         //-----------------------------------------------
934 
ConstructLiteralDecimal(decimal dec)935         public void ConstructLiteralDecimal(decimal dec)
936         {
937             if (dec >= (decimal)int.MinValue && dec <= (decimal)int.MaxValue && decimal.Truncate(dec) == dec)
938             {
939                 // Decimal can be constructed from a 32-bit integer
940                 LoadInteger((int)dec);
941                 Construct(XmlILConstructors.DecFromInt32);
942             }
943             else
944             {
945                 int[] bits = Decimal.GetBits(dec);
946 
947                 LoadInteger(bits[0]);
948                 LoadInteger(bits[1]);
949                 LoadInteger(bits[2]);
950                 LoadBoolean(bits[3] < 0);
951                 LoadInteger(bits[3] >> 16);
952                 Construct(XmlILConstructors.DecFromParts);
953             }
954         }
955 
ConstructLiteralQName(string localName, string namespaceName)956         public void ConstructLiteralQName(string localName, string namespaceName)
957         {
958             Emit(OpCodes.Ldstr, localName);
959             Emit(OpCodes.Ldstr, namespaceName);
960             Construct(XmlILConstructors.QName);
961         }
962 
CallArithmeticOp(QilNodeType opType, XmlTypeCode code)963         public void CallArithmeticOp(QilNodeType opType, XmlTypeCode code)
964         {
965             MethodInfo meth = null;
966 
967             switch (code)
968             {
969                 case XmlTypeCode.Int:
970                 case XmlTypeCode.Integer:
971                 case XmlTypeCode.Double:
972                 case XmlTypeCode.Float:
973                     switch (opType)
974                     {
975                         case QilNodeType.Add: Emit(OpCodes.Add); break;
976                         case QilNodeType.Subtract: Emit(OpCodes.Sub); break;
977                         case QilNodeType.Multiply: Emit(OpCodes.Mul); break;
978                         case QilNodeType.Divide: Emit(OpCodes.Div); break;
979                         case QilNodeType.Modulo: Emit(OpCodes.Rem); break;
980                         case QilNodeType.Negate: Emit(OpCodes.Neg); break;
981                         default: Debug.Assert(false, opType + " must be an arithmetic operation."); break;
982                     }
983                     break;
984 
985                 case XmlTypeCode.Decimal:
986                     switch (opType)
987                     {
988                         case QilNodeType.Add: meth = XmlILMethods.DecAdd; break;
989                         case QilNodeType.Subtract: meth = XmlILMethods.DecSub; break;
990                         case QilNodeType.Multiply: meth = XmlILMethods.DecMul; break;
991                         case QilNodeType.Divide: meth = XmlILMethods.DecDiv; break;
992                         case QilNodeType.Modulo: meth = XmlILMethods.DecRem; break;
993                         case QilNodeType.Negate: meth = XmlILMethods.DecNeg; break;
994                         default: Debug.Assert(false, opType + " must be an arithmetic operation."); break;
995                     }
996 
997                     Call(meth);
998                     break;
999 
1000                 default:
1001                     Debug.Assert(false, "The " + opType + " arithmetic operation cannot be performed on values of type " + code + ".");
1002                     break;
1003             }
1004         }
1005 
CallCompareEquals(XmlTypeCode code)1006         public void CallCompareEquals(XmlTypeCode code)
1007         {
1008             MethodInfo meth = null;
1009 
1010             switch (code)
1011             {
1012                 case XmlTypeCode.String: meth = XmlILMethods.StrEq; break;
1013                 case XmlTypeCode.QName: meth = XmlILMethods.QNameEq; break;
1014                 case XmlTypeCode.Decimal: meth = XmlILMethods.DecEq; break;
1015                 default:
1016                     Debug.Assert(false, "Type " + code + " does not support the equals operation.");
1017                     break;
1018             }
1019 
1020             Call(meth);
1021         }
1022 
CallCompare(XmlTypeCode code)1023         public void CallCompare(XmlTypeCode code)
1024         {
1025             MethodInfo meth = null;
1026 
1027             switch (code)
1028             {
1029                 case XmlTypeCode.String: meth = XmlILMethods.StrCmp; break;
1030                 case XmlTypeCode.Decimal: meth = XmlILMethods.DecCmp; break;
1031                 default:
1032                     Debug.Assert(false, "Type " + code + " does not support the equals operation.");
1033                     break;
1034             }
1035 
1036             Call(meth);
1037         }
1038 
1039 
1040         //-----------------------------------------------
1041         // XmlQueryRuntime function calls
1042         //-----------------------------------------------
1043 
CallStartRtfConstruction(string baseUri)1044         public void CallStartRtfConstruction(string baseUri)
1045         {
1046             EnsureWriter();
1047             LoadQueryRuntime();
1048             Emit(OpCodes.Ldstr, baseUri);
1049             Emit(OpCodes.Ldloca, _locXOut);
1050             Call(XmlILMethods.StartRtfConstr);
1051         }
1052 
CallEndRtfConstruction()1053         public void CallEndRtfConstruction()
1054         {
1055             LoadQueryRuntime();
1056             Emit(OpCodes.Ldloca, _locXOut);
1057             Call(XmlILMethods.EndRtfConstr);
1058         }
1059 
CallStartSequenceConstruction()1060         public void CallStartSequenceConstruction()
1061         {
1062             EnsureWriter();
1063             LoadQueryRuntime();
1064             Emit(OpCodes.Ldloca, _locXOut);
1065             Call(XmlILMethods.StartSeqConstr);
1066         }
1067 
CallEndSequenceConstruction()1068         public void CallEndSequenceConstruction()
1069         {
1070             LoadQueryRuntime();
1071             Emit(OpCodes.Ldloca, _locXOut);
1072             Call(XmlILMethods.EndSeqConstr);
1073         }
1074 
CallGetEarlyBoundObject(int idxObj, Type clrType)1075         public void CallGetEarlyBoundObject(int idxObj, Type clrType)
1076         {
1077             LoadQueryRuntime();
1078             LoadInteger(idxObj);
1079             Call(XmlILMethods.GetEarly);
1080             TreatAs(typeof(object), clrType);
1081         }
1082 
CallGetAtomizedName(int idxName)1083         public void CallGetAtomizedName(int idxName)
1084         {
1085             LoadQueryRuntime();
1086             LoadInteger(idxName);
1087             Call(XmlILMethods.GetAtomizedName);
1088         }
1089 
CallGetNameFilter(int idxFilter)1090         public void CallGetNameFilter(int idxFilter)
1091         {
1092             LoadQueryRuntime();
1093             LoadInteger(idxFilter);
1094             Call(XmlILMethods.GetNameFilter);
1095         }
1096 
CallGetTypeFilter(XPathNodeType nodeType)1097         public void CallGetTypeFilter(XPathNodeType nodeType)
1098         {
1099             LoadQueryRuntime();
1100             LoadInteger((int)nodeType);
1101             Call(XmlILMethods.GetTypeFilter);
1102         }
1103 
CallParseTagName(GenerateNameType nameType)1104         public void CallParseTagName(GenerateNameType nameType)
1105         {
1106             if (nameType == GenerateNameType.TagNameAndMappings)
1107             {
1108                 Call(XmlILMethods.TagAndMappings);
1109             }
1110             else
1111             {
1112                 Debug.Assert(nameType == GenerateNameType.TagNameAndNamespace);
1113                 Call(XmlILMethods.TagAndNamespace);
1114             }
1115         }
1116 
CallGetGlobalValue(int idxValue, Type clrType)1117         public void CallGetGlobalValue(int idxValue, Type clrType)
1118         {
1119             LoadQueryRuntime();
1120             LoadInteger(idxValue);
1121             Call(XmlILMethods.GetGlobalValue);
1122             TreatAs(typeof(object), clrType);
1123         }
1124 
CallSetGlobalValue(Type clrType)1125         public void CallSetGlobalValue(Type clrType)
1126         {
1127             TreatAs(clrType, typeof(object));
1128             Call(XmlILMethods.SetGlobalValue);
1129         }
1130 
CallGetCollation(int idxName)1131         public void CallGetCollation(int idxName)
1132         {
1133             LoadQueryRuntime();
1134             LoadInteger(idxName);
1135             Call(XmlILMethods.GetCollation);
1136         }
1137 
EnsureWriter()1138         private void EnsureWriter()
1139         {
1140             // If write variable has not yet been initialized, do it now
1141             if (!_initWriters)
1142             {
1143                 _locXOut = DeclareLocal("$$$xwrtChk", typeof(XmlQueryOutput));
1144                 _initWriters = true;
1145             }
1146         }
1147 
1148 
1149         //-----------------------------------------------
1150         // XmlQueryContext function calls
1151         //-----------------------------------------------
1152 
CallGetParameter(string localName, string namespaceUri)1153         public void CallGetParameter(string localName, string namespaceUri)
1154         {
1155             LoadQueryContext();
1156             Emit(OpCodes.Ldstr, localName);
1157             Emit(OpCodes.Ldstr, namespaceUri);
1158             Call(XmlILMethods.GetParam);
1159         }
1160 
1161         //-----------------------------------------------
1162         // XmlQueryOutput function calls
1163         //-----------------------------------------------
1164 
CallStartTree(XPathNodeType rootType)1165         public void CallStartTree(XPathNodeType rootType)
1166         {
1167             LoadQueryOutput();
1168             LoadInteger((int)rootType);
1169             Call(XmlILMethods.StartTree);
1170         }
1171 
CallEndTree()1172         public void CallEndTree()
1173         {
1174             LoadQueryOutput();
1175             Call(XmlILMethods.EndTree);
1176         }
1177 
CallWriteStartRoot()1178         public void CallWriteStartRoot()
1179         {
1180             // Call XmlQueryOutput.WriteStartRoot
1181             LoadQueryOutput();
1182             Call(XmlILMethods.StartRoot);
1183         }
1184 
CallWriteEndRoot()1185         public void CallWriteEndRoot()
1186         {
1187             // Call XmlQueryOutput.WriteEndRoot
1188             LoadQueryOutput();
1189             Call(XmlILMethods.EndRoot);
1190         }
1191 
CallWriteStartElement(GenerateNameType nameType, bool callChk)1192         public void CallWriteStartElement(GenerateNameType nameType, bool callChk)
1193         {
1194             MethodInfo meth = null;
1195 
1196             // If runtime checks need to be made,
1197             if (callChk)
1198             {
1199                 // Then call XmlQueryOutput.WriteStartElement
1200                 switch (nameType)
1201                 {
1202                     case GenerateNameType.LiteralLocalName: meth = XmlILMethods.StartElemLocName; break;
1203                     case GenerateNameType.LiteralName: meth = XmlILMethods.StartElemLitName; break;
1204                     case GenerateNameType.CopiedName: meth = XmlILMethods.StartElemCopyName; break;
1205                     case GenerateNameType.TagNameAndMappings: meth = XmlILMethods.StartElemMapName; break;
1206                     case GenerateNameType.TagNameAndNamespace: meth = XmlILMethods.StartElemNmspName; break;
1207                     case GenerateNameType.QName: meth = XmlILMethods.StartElemQName; break;
1208                     default: Debug.Assert(false, nameType + " is invalid here."); break;
1209                 }
1210             }
1211             else
1212             {
1213                 // Else call XmlQueryOutput.WriteStartElementUnchecked
1214                 switch (nameType)
1215                 {
1216                     case GenerateNameType.LiteralLocalName: meth = XmlILMethods.StartElemLocNameUn; break;
1217                     case GenerateNameType.LiteralName: meth = XmlILMethods.StartElemLitNameUn; break;
1218                     default: Debug.Assert(false, nameType + " is invalid here."); break;
1219                 }
1220             }
1221 
1222             Call(meth);
1223         }
1224 
CallWriteEndElement(GenerateNameType nameType, bool callChk)1225         public void CallWriteEndElement(GenerateNameType nameType, bool callChk)
1226         {
1227             MethodInfo meth = null;
1228 
1229             // If runtime checks need to be made,
1230             if (callChk)
1231             {
1232                 // Then call XmlQueryOutput.WriteEndElement
1233                 meth = XmlILMethods.EndElemStackName;
1234             }
1235             else
1236             {
1237                 // Else call XmlQueryOutput.WriteEndElementUnchecked
1238                 switch (nameType)
1239                 {
1240                     case GenerateNameType.LiteralLocalName: meth = XmlILMethods.EndElemLocNameUn; break;
1241                     case GenerateNameType.LiteralName: meth = XmlILMethods.EndElemLitNameUn; break;
1242                     default: Debug.Assert(false, nameType + " is invalid here."); break;
1243                 }
1244             }
1245 
1246             Call(meth);
1247         }
1248 
CallStartElementContent()1249         public void CallStartElementContent()
1250         {
1251             LoadQueryOutput();
1252             Call(XmlILMethods.StartContentUn);
1253         }
1254 
CallWriteStartAttribute(GenerateNameType nameType, bool callChk)1255         public void CallWriteStartAttribute(GenerateNameType nameType, bool callChk)
1256         {
1257             MethodInfo meth = null;
1258 
1259             // If runtime checks need to be made,
1260             if (callChk)
1261             {
1262                 // Then call XmlQueryOutput.WriteStartAttribute
1263                 switch (nameType)
1264                 {
1265                     case GenerateNameType.LiteralLocalName: meth = XmlILMethods.StartAttrLocName; break;
1266                     case GenerateNameType.LiteralName: meth = XmlILMethods.StartAttrLitName; break;
1267                     case GenerateNameType.CopiedName: meth = XmlILMethods.StartAttrCopyName; break;
1268                     case GenerateNameType.TagNameAndMappings: meth = XmlILMethods.StartAttrMapName; break;
1269                     case GenerateNameType.TagNameAndNamespace: meth = XmlILMethods.StartAttrNmspName; break;
1270                     case GenerateNameType.QName: meth = XmlILMethods.StartAttrQName; break;
1271                     default: Debug.Assert(false, nameType + " is invalid here."); break;
1272                 }
1273             }
1274             else
1275             {
1276                 // Else call XmlQueryOutput.WriteStartAttributeUnchecked
1277                 switch (nameType)
1278                 {
1279                     case GenerateNameType.LiteralLocalName: meth = XmlILMethods.StartAttrLocNameUn; break;
1280                     case GenerateNameType.LiteralName: meth = XmlILMethods.StartAttrLitNameUn; break;
1281                     default: Debug.Assert(false, nameType + " is invalid here."); break;
1282                 }
1283             }
1284 
1285             Call(meth);
1286         }
1287 
CallWriteEndAttribute(bool callChk)1288         public void CallWriteEndAttribute(bool callChk)
1289         {
1290             LoadQueryOutput();
1291 
1292             // If runtime checks need to be made,
1293             if (callChk)
1294             {
1295                 // Then call XmlQueryOutput.WriteEndAttribute
1296                 Call(XmlILMethods.EndAttr);
1297             }
1298             else
1299             {
1300                 // Else call XmlQueryOutput.WriteEndAttributeUnchecked
1301                 Call(XmlILMethods.EndAttrUn);
1302             }
1303         }
1304 
CallWriteNamespaceDecl(bool callChk)1305         public void CallWriteNamespaceDecl(bool callChk)
1306         {
1307             // If runtime checks need to be made,
1308             if (callChk)
1309             {
1310                 // Then call XmlQueryOutput.WriteNamespaceDeclaration
1311                 Call(XmlILMethods.NamespaceDecl);
1312             }
1313             else
1314             {
1315                 // Else call XmlQueryOutput.WriteNamespaceDeclarationUnchecked
1316                 Call(XmlILMethods.NamespaceDeclUn);
1317             }
1318         }
1319 
CallWriteString(bool disableOutputEscaping, bool callChk)1320         public void CallWriteString(bool disableOutputEscaping, bool callChk)
1321         {
1322             // If runtime checks need to be made,
1323             if (callChk)
1324             {
1325                 // Then call XmlQueryOutput.WriteString, or XmlQueryOutput.WriteRaw
1326                 if (disableOutputEscaping)
1327                     Call(XmlILMethods.NoEntText);
1328                 else
1329                     Call(XmlILMethods.Text);
1330             }
1331             else
1332             {
1333                 // Else call XmlQueryOutput.WriteStringUnchecked, or XmlQueryOutput.WriteRawUnchecked
1334                 if (disableOutputEscaping)
1335                     Call(XmlILMethods.NoEntTextUn);
1336                 else
1337                     Call(XmlILMethods.TextUn);
1338             }
1339         }
1340 
CallWriteStartPI()1341         public void CallWriteStartPI()
1342         {
1343             Call(XmlILMethods.StartPI);
1344         }
1345 
CallWriteEndPI()1346         public void CallWriteEndPI()
1347         {
1348             LoadQueryOutput();
1349             Call(XmlILMethods.EndPI);
1350         }
1351 
CallWriteStartComment()1352         public void CallWriteStartComment()
1353         {
1354             LoadQueryOutput();
1355             Call(XmlILMethods.StartComment);
1356         }
1357 
CallWriteEndComment()1358         public void CallWriteEndComment()
1359         {
1360             LoadQueryOutput();
1361             Call(XmlILMethods.EndComment);
1362         }
1363 
1364 
1365         //-----------------------------------------------
1366         // Item caching methods
1367         //-----------------------------------------------
1368 
CallCacheCount(Type itemStorageType)1369         public void CallCacheCount(Type itemStorageType)
1370         {
1371             XmlILStorageMethods meth = XmlILMethods.StorageMethods[itemStorageType];
1372             Call(meth.IListCount);
1373         }
1374 
CallCacheItem(Type itemStorageType)1375         public void CallCacheItem(Type itemStorageType)
1376         {
1377             Call(XmlILMethods.StorageMethods[itemStorageType].IListItem);
1378         }
1379 
1380 
1381         //-----------------------------------------------
1382         // XPathItem properties and methods
1383         //-----------------------------------------------
1384 
CallValueAs(Type clrType)1385         public void CallValueAs(Type clrType)
1386         {
1387             MethodInfo meth;
1388 
1389             meth = XmlILMethods.StorageMethods[clrType].ValueAs;
1390             if (meth == null)
1391             {
1392                 // Call (Type) item.ValueAs(Type, null)
1393                 LoadType(clrType);
1394                 Emit(OpCodes.Ldnull);
1395                 Call(XmlILMethods.ValueAsAny);
1396 
1397                 // Unbox or down-cast
1398                 TreatAs(typeof(object), clrType);
1399             }
1400             else
1401             {
1402                 // Call strongly typed ValueAs method
1403                 Call(meth);
1404             }
1405         }
1406 
1407 
1408         //-----------------------------------------------
1409         // XmlSortKeyAccumulator methods
1410         //-----------------------------------------------
1411 
AddSortKey(XmlQueryType keyType)1412         public void AddSortKey(XmlQueryType keyType)
1413         {
1414             MethodInfo meth = null;
1415 
1416             if (keyType == null)
1417             {
1418                 meth = XmlILMethods.SortKeyEmpty;
1419             }
1420             else
1421             {
1422                 Debug.Assert(keyType.IsAtomicValue, "Sort key must have atomic value type.");
1423 
1424                 switch (keyType.TypeCode)
1425                 {
1426                     case XmlTypeCode.String: meth = XmlILMethods.SortKeyString; break;
1427                     case XmlTypeCode.Decimal: meth = XmlILMethods.SortKeyDecimal; break;
1428                     case XmlTypeCode.Integer: meth = XmlILMethods.SortKeyInteger; break;
1429                     case XmlTypeCode.Int: meth = XmlILMethods.SortKeyInt; break;
1430                     case XmlTypeCode.Boolean: meth = XmlILMethods.SortKeyInt; break;
1431                     case XmlTypeCode.Double: meth = XmlILMethods.SortKeyDouble; break;
1432                     case XmlTypeCode.DateTime: meth = XmlILMethods.SortKeyDateTime; break;
1433 
1434                     case XmlTypeCode.None:
1435                         // Empty sequence, so this path will never actually be taken
1436                         Emit(OpCodes.Pop);
1437                         meth = XmlILMethods.SortKeyEmpty;
1438                         break;
1439 
1440                     case XmlTypeCode.AnyAtomicType:
1441                         Debug.Assert(false, "Heterogenous sort key is not allowed.");
1442                         return;
1443 
1444                     default:
1445                         Debug.Assert(false, "Sorting over datatype " + keyType.TypeCode + " is not allowed.");
1446                         break;
1447                 }
1448             }
1449 
1450             Call(meth);
1451         }
1452 
1453 
1454         //-----------------------------------------------
1455         // Debugging information output
1456         //-----------------------------------------------
1457 
1458         /// <summary>
1459         /// Begin a new variable debugging scope.
1460         /// </summary>
DebugStartScope()1461         public void DebugStartScope()
1462         {
1463             _ilgen.BeginScope();
1464         }
1465 
1466         /// <summary>
1467         /// End a new debugging scope.
1468         /// </summary>
DebugEndScope()1469         public void DebugEndScope()
1470         {
1471             _ilgen.EndScope();
1472         }
1473 
1474         /// <summary>
1475         /// Correlate the current IL generation position with the current source position.
1476         /// </summary>
DebugSequencePoint(ISourceLineInfo sourceInfo)1477         public void DebugSequencePoint(ISourceLineInfo sourceInfo)
1478         {
1479             Debug.Assert(_isDebug && _lastSourceInfo != null);
1480             Debug.Assert(sourceInfo != null);
1481 
1482             // When emitting sequence points, be careful to always follow two rules:
1483             // 1. Never emit adjacent sequence points, as this messes up the debugger.  We guarantee this by
1484             //    always emitting a Nop before every sequence point.
1485             // 2. The runtime enforces a rule that BP sequence points can only appear at zero stack depth,
1486             //    or if a NOP instruction is placed before them.  We guarantee this by always emitting a Nop
1487             //    before every sequence point.
1488             //    <spec>http://devdiv/Documents/Whidbey/CLR/CurrentSpecs/Debugging%20and%20Profiling/JIT-Determined%20Sequence%20Points.doc</spec>
1489             Emit(OpCodes.Nop);
1490             MarkSequencePoint(sourceInfo);
1491         }
1492 
1493         private string _lastUriString = null;
1494         private string _lastFileName = null;
1495 
1496         // SQLBUDT 278010: debugger does not work with network paths in uri format, like file://server/share/dir/file
GetFileName(ISourceLineInfo sourceInfo)1497         private string GetFileName(ISourceLineInfo sourceInfo)
1498         {
1499             string uriString = sourceInfo.Uri;
1500             if ((object)uriString == (object)_lastUriString)
1501             {
1502                 return _lastFileName;
1503             }
1504 
1505             _lastUriString = uriString;
1506             _lastFileName = SourceLineInfo.GetFileName(uriString);
1507             return _lastFileName;
1508         }
1509 
MarkSequencePoint(ISourceLineInfo sourceInfo)1510         private void MarkSequencePoint(ISourceLineInfo sourceInfo)
1511         {
1512             Debug.Assert(_module.EmitSymbols);
1513 
1514             // Do not emit adjacent 0xfeefee sequence points, as that slows down stepping in the debugger
1515             if (sourceInfo.IsNoSource && _lastSourceInfo != null && _lastSourceInfo.IsNoSource)
1516             {
1517                 return;
1518             }
1519 
1520             string sourceFile = GetFileName(sourceInfo);
1521 
1522 #if DEBUG
1523             if (XmlILTrace.IsEnabled)
1524             {
1525                 if (sourceInfo.IsNoSource)
1526                     _writerDump.WriteLine("//[no source]");
1527                 else
1528                 {
1529                     if (sourceFile != _sourceFile)
1530                     {
1531                         _sourceFile = sourceFile;
1532                         _writerDump.WriteLine("// Source File '{0}'", _sourceFile);
1533                     }
1534                     _writerDump.WriteLine("//[{0},{1} -- {2},{3}]", sourceInfo.Start.Line, sourceInfo.Start.Pos, sourceInfo.End.Line, sourceInfo.End.Pos);
1535                 }
1536             }
1537 #endif
1538             //ISymbolDocumentWriter symDoc = this.module.AddSourceDocument(sourceFile);
1539             //this.ilgen.MarkSequencePoint(symDoc, sourceInfo.Start.Line, sourceInfo.Start.Pos, sourceInfo.End.Line, sourceInfo.End.Pos);
1540             _lastSourceInfo = sourceInfo;
1541         }
1542 
1543 
1544         //-----------------------------------------------
1545         // Pass through to ILGenerator
1546         //-----------------------------------------------
1547 
DefineLabel()1548         public Label DefineLabel()
1549         {
1550             Label lbl = _ilgen.DefineLabel();
1551 
1552 #if DEBUG
1553             if (XmlILTrace.IsEnabled)
1554                 _symbols.Add(lbl, ++_lblNum);
1555 #endif
1556 
1557             return lbl;
1558         }
1559 
MarkLabel(Label lbl)1560         public void MarkLabel(Label lbl)
1561         {
1562             if (_lastSourceInfo != null && !_lastSourceInfo.IsNoSource)
1563             {
1564                 // Emit a "no source" sequence point, otherwise the debugger would show
1565                 // a wrong line if we jumped to this label from another place
1566                 DebugSequencePoint(SourceLineInfo.NoSource);
1567             }
1568 
1569 #if DEBUG
1570             if (XmlILTrace.IsEnabled)
1571                 _writerDump.WriteLine("Label {0}:", _symbols[lbl]);
1572 #endif
1573 
1574             _ilgen.MarkLabel(lbl);
1575         }
1576 
Emit(OpCode opcode)1577         public void Emit(OpCode opcode)
1578         {
1579 #if DEBUG
1580             if (XmlILTrace.IsEnabled)
1581                 _writerDump.WriteLine("  {0}", opcode.Name);
1582 #endif
1583             _ilgen.Emit(opcode);
1584         }
1585 
Emit(OpCode opcode, byte byteVal)1586         public void Emit(OpCode opcode, byte byteVal)
1587         {
1588 #if DEBUG
1589             if (XmlILTrace.IsEnabled)
1590                 _writerDump.WriteLine("  {0, -10} {1}", opcode.Name, byteVal);
1591 #endif
1592             _ilgen.Emit(opcode, byteVal);
1593         }
1594 
Emit(OpCode opcode, ConstructorInfo constrInfo)1595         public void Emit(OpCode opcode, ConstructorInfo constrInfo)
1596         {
1597 #if DEBUG
1598             if (XmlILTrace.IsEnabled)
1599                 _writerDump.WriteLine("  {0, -10} {1}", opcode.Name, constrInfo);
1600 #endif
1601             _ilgen.Emit(opcode, constrInfo);
1602         }
1603 
Emit(OpCode opcode, double dblVal)1604         public void Emit(OpCode opcode, double dblVal)
1605         {
1606 #if DEBUG
1607             if (XmlILTrace.IsEnabled)
1608                 _writerDump.WriteLine("  {0, -10} {1}", opcode.Name, dblVal);
1609 #endif
1610             _ilgen.Emit(opcode, dblVal);
1611         }
1612 
Emit(OpCode opcode, FieldInfo fldInfo)1613         public void Emit(OpCode opcode, FieldInfo fldInfo)
1614         {
1615 #if DEBUG
1616             if (XmlILTrace.IsEnabled)
1617                 _writerDump.WriteLine("  {0, -10} {1}", opcode.Name, fldInfo.Name);
1618 #endif
1619             _ilgen.Emit(opcode, fldInfo);
1620         }
1621 
Emit(OpCode opcode, int intVal)1622         public void Emit(OpCode opcode, int intVal)
1623         {
1624             Debug.Assert(opcode.OperandType == OperandType.InlineI || opcode.OperandType == OperandType.InlineVar);
1625 #if DEBUG
1626             if (XmlILTrace.IsEnabled)
1627                 _writerDump.WriteLine("  {0, -10} {1}", opcode.Name, intVal);
1628 #endif
1629             _ilgen.Emit(opcode, intVal);
1630         }
1631 
Emit(OpCode opcode, long longVal)1632         public void Emit(OpCode opcode, long longVal)
1633         {
1634             Debug.Assert(opcode.OperandType == OperandType.InlineI8);
1635 #if DEBUG
1636             if (XmlILTrace.IsEnabled)
1637                 _writerDump.WriteLine("  {0, -10} {1}", opcode.Name, longVal);
1638 #endif
1639             _ilgen.Emit(opcode, longVal);
1640         }
1641 
Emit(OpCode opcode, Label lblVal)1642         public void Emit(OpCode opcode, Label lblVal)
1643         {
1644             Debug.Assert(!opcode.Equals(OpCodes.Br) && !opcode.Equals(OpCodes.Br_S), "Use EmitUnconditionalBranch and be careful not to emit unverifiable code.");
1645 #if DEBUG
1646             if (XmlILTrace.IsEnabled)
1647                 _writerDump.WriteLine("  {0, -10} Label {1}", opcode.Name, _symbols[lblVal]);
1648 #endif
1649             _ilgen.Emit(opcode, lblVal);
1650         }
1651 
Emit(OpCode opcode, Label[] arrLabels)1652         public void Emit(OpCode opcode, Label[] arrLabels)
1653         {
1654 #if DEBUG
1655             if (XmlILTrace.IsEnabled)
1656             {
1657                 _writerDump.Write("  {0, -10} (Label {1}", opcode.Name, arrLabels.Length != 0 ? _symbols[arrLabels[0]].ToString() : "");
1658                 for (int i = 1; i < arrLabels.Length; i++)
1659                 {
1660                     _writerDump.Write(", Label {0}", _symbols[arrLabels[i]]);
1661                 }
1662                 _writerDump.WriteLine(")");
1663             }
1664 #endif
1665             _ilgen.Emit(opcode, arrLabels);
1666         }
1667 
Emit(OpCode opcode, LocalBuilder locBldr)1668         public void Emit(OpCode opcode, LocalBuilder locBldr)
1669         {
1670 #if DEBUG
1671             if (XmlILTrace.IsEnabled)
1672                 _writerDump.WriteLine("  {0, -10} {1} ({2})", opcode.Name, _symbols[locBldr], locBldr.LocalType.Name);
1673 #endif
1674             _ilgen.Emit(opcode, locBldr);
1675         }
1676 
Emit(OpCode opcode, sbyte sbyteVal)1677         public void Emit(OpCode opcode, sbyte sbyteVal)
1678         {
1679 #if DEBUG
1680             if (XmlILTrace.IsEnabled)
1681                 _writerDump.WriteLine("  {0, -10} {1}", opcode.Name, sbyteVal);
1682 #endif
1683             _ilgen.Emit(opcode, sbyteVal);
1684         }
1685 
Emit(OpCode opcode, string strVal)1686         public void Emit(OpCode opcode, string strVal)
1687         {
1688 #if DEBUG
1689             if (XmlILTrace.IsEnabled)
1690                 _writerDump.WriteLine("  {0, -10} \"{1}\"", opcode.Name, strVal);
1691 #endif
1692             _ilgen.Emit(opcode, strVal);
1693         }
1694 
Emit(OpCode opcode, Type typVal)1695         public void Emit(OpCode opcode, Type typVal)
1696         {
1697 #if DEBUG
1698             if (XmlILTrace.IsEnabled)
1699                 _writerDump.WriteLine("  {0, -10} {1}", opcode.Name, typVal);
1700 #endif
1701             _ilgen.Emit(opcode, typVal);
1702         }
1703 
1704         /// <summary>
1705         /// Unconditional branch opcodes (OpCode.Br, OpCode.Br_S) can lead to unverifiable code in the following cases:
1706         ///
1707         ///   # DEAD CODE CASE
1708         ///     ldc_i4  1       # Stack depth == 1
1709         ///     br      Label2
1710         ///   Label1:
1711         ///     nop             # Dead code, so IL rules assume stack depth == 0.  This causes a verification error,
1712         ///                     # since next instruction has depth == 1
1713         ///   Label2:
1714         ///     pop             # Stack depth == 1
1715         ///     ret
1716         ///
1717         ///   # LATE BRANCH CASE
1718         ///     ldc_i4  1       # Stack depth == 1
1719         ///     br      Label2
1720         ///   Label1:
1721         ///     nop             # Not dead code, but since branch comes from below, IL rules assume stack depth = 0.
1722         ///                     # This causes a verification error, since next instruction has depth == 1
1723         ///   Label2:
1724         ///     pop             # Stack depth == 1
1725         ///     ret
1726         ///   Label3:
1727         ///     br      Label1  # Stack depth == 1
1728         ///
1729         /// This method works around the above limitations by using Brtrue or Brfalse in the following way:
1730         ///
1731         ///     ldc_i4  1       # Since this test is always true, this is a way of creating a path to the code that
1732         ///     brtrue  Label   # follows the brtrue instruction.
1733         ///
1734         ///     ldc_i4  1       # Since this test is always false, this is a way of creating a path to the code that
1735         ///     brfalse Label   # starts at Label.
1736         ///
1737         /// 1. If opcode == Brtrue or Brtrue_S, then 1 will be pushed and brtrue instruction will be generated.
1738         /// 2. If opcode == Brfalse or Brfalse_S, then 1 will be pushed and brfalse instruction will be generated.
1739         /// 3. If opcode == Br or Br_S, then a br instruction will be generated.
1740         /// </summary>
EmitUnconditionalBranch(OpCode opcode, Label lblTarget)1741         public void EmitUnconditionalBranch(OpCode opcode, Label lblTarget)
1742         {
1743             if (!opcode.Equals(OpCodes.Br) && !opcode.Equals(OpCodes.Br_S))
1744             {
1745                 Debug.Assert(opcode.Equals(OpCodes.Brtrue) || opcode.Equals(OpCodes.Brtrue_S) ||
1746                              opcode.Equals(OpCodes.Brfalse) || opcode.Equals(OpCodes.Brfalse_S));
1747                 Emit(OpCodes.Ldc_I4_1);
1748             }
1749 
1750 #if DEBUG
1751             if (XmlILTrace.IsEnabled)
1752                 _writerDump.WriteLine("  {0, -10} Label {1}", opcode.Name, _symbols[lblTarget]);
1753 #endif
1754             _ilgen.Emit(opcode, lblTarget);
1755 
1756             if (_lastSourceInfo != null && (opcode.Equals(OpCodes.Br) || opcode.Equals(OpCodes.Br_S)))
1757             {
1758                 // Emit a "no source" sequence point, otherwise the following label will be preceded
1759                 // with a dead Nop operation, which may lead to unverifiable code (SQLBUDT 423393).
1760                 // We are guaranteed not to emit adjacent sequence points because Br or Br_S
1761                 // instruction precedes this sequence point, and a Nop instruction precedes other
1762                 // sequence points.
1763                 MarkSequencePoint(SourceLineInfo.NoSource);
1764             }
1765         }
1766     }
1767 }
1768