1 //------------------------------------------------------------------------------
2 // <copyright file="OptimizerPatterns.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 using System.Diagnostics;
9 using System.Xml.Xsl.Qil;
11 namespace System.Xml.Xsl.IlGen {
13 internal enum OptimizerPatternName {
15 DodReverse, // (Dod $reverse-axis:*)
16 EqualityIndex, // ILGen will build an equality index when this pattern is recognized
17 FilterAttributeKind, // (Filter $iter:(Content *) (IsType $iter Attribute))
18 FilterContentKind, // (Filter $iter:* (IsType $iter $kind:*))
19 FilterElements, // (Filter $iter:* (And (IsType $iter Element) (NameOf $iter (LiteralQName * * *))))
20 IsDocOrderDistinct, // True if the annotated expression always returns nodes in document order, with no duplicates
21 IsPositional, // True if the annotated iterator should track current position during iteration
22 JoinAndDod, // (Dod (Loop $path1:* $path2:*)), where $path2.ContextNode = $path1
23 MaxPosition, // True if the position range of the annoted iterator or length expression has a maximum
24 SameDepth, // True if the annotated expression always returns nodes at the same depth in the tree
25 Step, // True if the annotated expression returns nodes from one of the simple axis operators, or from a union of Content operators
26 SingleTextRtf, // (RtfCtor (TextCtor *) *)
28 MaybeSideEffects, // True if annotated expression might have side effects
29 TailCall, // (Invoke * *) True if invocation can be compiled as using .tailcall
30 DodMerge, // (Dod (Loop * (Invoke * *))), where invoked function returns nodes in document order
31 IsReferenced, // True if the annotated global iterator is referenced at least once
34 internal enum OptimizerPatternArgument {
35 StepNode = 0, // Step, QilNode: The QilNode of the inner step expression (Content, DescendantOrSelf, XPathFollowing, Union, etc.)
36 StepInput = 1, // Step, QilNode: The expression from which navigation begins
38 ElementQName = 2, // FilterElements, QilLiteral: All but elements of this QName are filtered by FilterElements expression
40 KindTestType = 2, // FilterContentKind, XmlType: All but nodes of this XmlType are filtered by FilterContentKind expression
42 IndexedNodes = 0, // EqualityIndex, QilNode: Expression that returns the nodes to be indexed
43 KeyExpression = 1, // EqualityIndex, QilNode: Expression that returns the keys for the index
45 DodStep = 2, // JoinAndDod | DodReverse, QilNode: Last step in a JoinAndDod expression, or only step in DodReverse expression
47 MaxPosition = 2, // MaxPosition, int: Maximum position of the annotated iterator or length expression
49 RtfText = 2, // SingleTextRtf, QilNode: Expression that constructs the text of the simple text Rtf
53 /// As the Qil graph is traversed, patterns are identified. Subtrees that match these patterns are
54 /// annotated with this class, which identifies the matching patterns and their arguments.
56 internal class OptimizerPatterns : IQilAnnotation {
57 private static readonly int PatternCount = Enum.GetValues(typeof(OptimizerPatternName)).Length;
59 private int patterns; // Set of patterns that the annotated Qil node and its subtree matches
60 private bool isReadOnly; // True if setters are disabled in the case of singleton OptimizerPatterns
61 private object arg0, arg1, arg2; // Arguments to the matching patterns
63 private static volatile OptimizerPatterns ZeroOrOneDefault;
64 private static volatile OptimizerPatterns MaybeManyDefault;
65 private static volatile OptimizerPatterns DodDefault;
68 /// Get OptimizerPatterns annotation for the specified node. Lazily create if necessary.
70 public static OptimizerPatterns Read(QilNode nd) {
71 XmlILAnnotation ann = nd.Annotation as XmlILAnnotation;
72 OptimizerPatterns optPatt = (ann != null) ? ann.Patterns : null;
74 if (optPatt == null) {
75 if (!nd.XmlType.MaybeMany) {
76 // Expressions with ZeroOrOne cardinality should always report IsDocOrderDistinct and NoContainedNodes
77 if (ZeroOrOneDefault == null) {
78 optPatt = new OptimizerPatterns();
79 optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct);
80 optPatt.AddPattern(OptimizerPatternName.SameDepth);
81 optPatt.isReadOnly = true;
83 ZeroOrOneDefault = optPatt;
86 optPatt = ZeroOrOneDefault;
89 else if (nd.XmlType.IsDod) {
90 if (DodDefault == null) {
91 optPatt = new OptimizerPatterns();
92 optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct);
93 optPatt.isReadOnly = true;
102 if (MaybeManyDefault == null) {
103 optPatt = new OptimizerPatterns();
104 optPatt.isReadOnly = true;
106 MaybeManyDefault = optPatt;
109 optPatt = MaybeManyDefault;
118 /// Create and initialize OptimizerPatterns annotation for the specified node.
120 public static OptimizerPatterns Write(QilNode nd) {
121 XmlILAnnotation ann = XmlILAnnotation.Write(nd);
122 OptimizerPatterns optPatt = ann.Patterns;
124 if (optPatt == null || optPatt.isReadOnly) {
125 optPatt = new OptimizerPatterns();
126 ann.Patterns = optPatt;
128 if (!nd.XmlType.MaybeMany) {
129 optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct);
130 optPatt.AddPattern(OptimizerPatternName.SameDepth);
132 else if (nd.XmlType.IsDod) {
133 optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct);
141 /// Create and initialize OptimizerPatterns annotation for the specified node.
143 public static void Inherit(QilNode ndSrc, QilNode ndDst, OptimizerPatternName pattern) {
144 OptimizerPatterns annSrc = OptimizerPatterns.Read(ndSrc);
146 if (annSrc.MatchesPattern(pattern)) {
147 OptimizerPatterns annDst = OptimizerPatterns.Write(ndDst);
148 annDst.AddPattern(pattern);
150 // Inherit pattern arguments
152 case OptimizerPatternName.Step:
153 annDst.AddArgument(OptimizerPatternArgument.StepNode, annSrc.GetArgument(OptimizerPatternArgument.StepNode));
154 annDst.AddArgument(OptimizerPatternArgument.StepInput, annSrc.GetArgument(OptimizerPatternArgument.StepInput));
157 case OptimizerPatternName.FilterElements:
158 annDst.AddArgument(OptimizerPatternArgument.ElementQName, annSrc.GetArgument(OptimizerPatternArgument.ElementQName));
161 case OptimizerPatternName.FilterContentKind:
162 annDst.AddArgument(OptimizerPatternArgument.KindTestType, annSrc.GetArgument(OptimizerPatternArgument.KindTestType));
165 case OptimizerPatternName.EqualityIndex:
166 annDst.AddArgument(OptimizerPatternArgument.IndexedNodes, annSrc.GetArgument(OptimizerPatternArgument.IndexedNodes));
167 annDst.AddArgument(OptimizerPatternArgument.KeyExpression, annSrc.GetArgument(OptimizerPatternArgument.KeyExpression));
170 case OptimizerPatternName.DodReverse:
171 case OptimizerPatternName.JoinAndDod:
172 annDst.AddArgument(OptimizerPatternArgument.DodStep, annSrc.GetArgument(OptimizerPatternArgument.DodStep));
175 case OptimizerPatternName.MaxPosition:
176 annDst.AddArgument(OptimizerPatternArgument.MaxPosition, annSrc.GetArgument(OptimizerPatternArgument.MaxPosition));
179 case OptimizerPatternName.SingleTextRtf:
180 annDst.AddArgument(OptimizerPatternArgument.RtfText, annSrc.GetArgument(OptimizerPatternArgument.RtfText));
187 /// Add an argument to one of the matching patterns.
189 public void AddArgument(OptimizerPatternArgument argId, object arg) {
190 Debug.Assert(!this.isReadOnly, "This OptimizerPatterns instance is read-only.");
192 switch ((int) argId) {
193 case 0: this.arg0 = arg; break;
194 case 1: this.arg1 = arg; break;
195 case 2: this.arg2 = arg; break;
197 Debug.Assert(false, "Cannot handle more than 2 arguments.");
203 /// Get an argument of one of the matching patterns.
205 public object GetArgument(OptimizerPatternArgument argNum) {
208 switch ((int) argNum) {
209 case 0: arg = this.arg0; break;
210 case 1: arg = this.arg1; break;
211 case 2: arg = this.arg2; break;
214 Debug.Assert(arg != null, "There is no '" + argNum + "' argument.");
219 /// Add a pattern to the list of patterns that the annotated node matches.
221 public void AddPattern(OptimizerPatternName pattern) {
222 Debug.Assert(Enum.IsDefined(typeof(OptimizerPatternName), pattern));
223 Debug.Assert((int) pattern < 32);
224 Debug.Assert(!this.isReadOnly, "This OptimizerPatterns instance is read-only.");
225 this.patterns |= (1 << (int) pattern);
229 /// Return true if the annotated node matches the specified pattern.
231 public bool MatchesPattern(OptimizerPatternName pattern) {
232 Debug.Assert(Enum.IsDefined(typeof(OptimizerPatternName), pattern));
233 return (this.patterns & (1 << (int) pattern)) != 0;
237 /// Return name of this annotation.
239 public virtual string Name {
240 get { return "Patterns"; }
244 /// Return string representation of this annotation.
246 public override string ToString() {
249 for (int pattNum = 0; pattNum < PatternCount; pattNum++) {
250 if (MatchesPattern((OptimizerPatternName) pattNum)) {
254 s += ((OptimizerPatternName) pattNum).ToString();