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