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