Welcome to mirror list, hosted at ThFree Co, Russian Federation.

OptimizerPatterns.cs « IlGen « Xsl « Xml « System « System.Data.SqlXml « referencesource « class « mcs - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 85589508b48ee722712b0f21bbd568c4088a777b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
//------------------------------------------------------------------------------
// <copyright file="OptimizerPatterns.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Xml.Xsl.Qil;

namespace System.Xml.Xsl.IlGen {

    internal enum OptimizerPatternName {
        None,
        DodReverse,                         // (Dod $reverse-axis:*)
        EqualityIndex,                      // ILGen will build an equality index when this pattern is recognized
        FilterAttributeKind,                // (Filter $iter:(Content *) (IsType $iter Attribute))
        FilterContentKind,                  // (Filter $iter:* (IsType $iter $kind:*))
        FilterElements,                     // (Filter $iter:* (And (IsType $iter Element) (NameOf $iter (LiteralQName * * *))))
        IsDocOrderDistinct,                 // True if the annotated expression always returns nodes in document order, with no duplicates
        IsPositional,                       // True if the annotated iterator should track current position during iteration
        JoinAndDod,                         // (Dod (Loop $path1:* $path2:*)), where $path2.ContextNode = $path1
        MaxPosition,                        // True if the position range of the annoted iterator or length expression has a maximum
        SameDepth,                          // True if the annotated expression always returns nodes at the same depth in the tree
        Step,                               // True if the annotated expression returns nodes from one of the simple axis operators, or from a union of Content operators
        SingleTextRtf,                      // (RtfCtor (TextCtor *) *)
        Axis,                               // (AnyAxis *)
        MaybeSideEffects,                   // True if annotated expression might have side effects
        TailCall,                           // (Invoke * *) True if invocation can be compiled as using .tailcall
        DodMerge,                           // (Dod (Loop * (Invoke * *))), where invoked function returns nodes in document order
        IsReferenced,                       // True if the annotated global iterator is referenced at least once
    }

    internal enum OptimizerPatternArgument {
        StepNode = 0,                       // Step, QilNode: The QilNode of the inner step expression (Content, DescendantOrSelf, XPathFollowing, Union, etc.)
        StepInput = 1,                      // Step, QilNode: The expression from which navigation begins

        ElementQName = 2,                   // FilterElements, QilLiteral: All but elements of this QName are filtered by FilterElements expression

        KindTestType = 2,                   // FilterContentKind, XmlType: All but nodes of this XmlType are filtered by FilterContentKind expression

        IndexedNodes = 0,                   // EqualityIndex, QilNode: Expression that returns the nodes to be indexed
        KeyExpression = 1,                  // EqualityIndex, QilNode: Expression that returns the keys for the index

        DodStep = 2,                        // JoinAndDod | DodReverse, QilNode: Last step in a JoinAndDod expression, or only step in DodReverse expression

        MaxPosition = 2,                    // MaxPosition, int: Maximum position of the annotated iterator or length expression

        RtfText = 2,                        // SingleTextRtf, QilNode: Expression that constructs the text of the simple text Rtf
    }

    /// <summary>
    /// As the Qil graph is traversed, patterns are identified.  Subtrees that match these patterns are
    /// annotated with this class, which identifies the matching patterns and their arguments.
    /// </summary>
    internal class OptimizerPatterns : IQilAnnotation {
        private static readonly int PatternCount = Enum.GetValues(typeof(OptimizerPatternName)).Length;

        private int patterns;               // Set of patterns that the annotated Qil node and its subtree matches
        private bool isReadOnly;            // True if setters are disabled in the case of singleton OptimizerPatterns
        private object arg0, arg1, arg2;    // Arguments to the matching patterns

        private static volatile OptimizerPatterns ZeroOrOneDefault;
        private static volatile OptimizerPatterns MaybeManyDefault;
        private static volatile OptimizerPatterns DodDefault;

        /// <summary>
        /// Get OptimizerPatterns annotation for the specified node.  Lazily create if necessary.
        /// </summary>
        public static OptimizerPatterns Read(QilNode nd) {
            XmlILAnnotation ann = nd.Annotation as XmlILAnnotation;
            OptimizerPatterns optPatt = (ann != null) ? ann.Patterns : null;

            if (optPatt == null) {
                if (!nd.XmlType.MaybeMany) {
                    // Expressions with ZeroOrOne cardinality should always report IsDocOrderDistinct and NoContainedNodes
                    if (ZeroOrOneDefault == null) {
                        optPatt = new OptimizerPatterns();
                        optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct);
                        optPatt.AddPattern(OptimizerPatternName.SameDepth);
                        optPatt.isReadOnly = true;

                        ZeroOrOneDefault = optPatt;
                    }
                    else {
                        optPatt = ZeroOrOneDefault;
                    }
                }
                else if (nd.XmlType.IsDod) {
                    if (DodDefault == null) {
                        optPatt = new OptimizerPatterns();
                        optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct);
                        optPatt.isReadOnly = true;

                        DodDefault = optPatt;
                    }
                    else {
                        optPatt = DodDefault;
                    }
                }
                else {
                    if (MaybeManyDefault == null) {
                        optPatt = new OptimizerPatterns();
                        optPatt.isReadOnly = true;

                        MaybeManyDefault = optPatt;
                    }
                    else {
                        optPatt = MaybeManyDefault;
                    }
                }
            }

            return optPatt;
        }

        /// <summary>
        /// Create and initialize OptimizerPatterns annotation for the specified node.
        /// </summary>
        public static OptimizerPatterns Write(QilNode nd) {
            XmlILAnnotation ann = XmlILAnnotation.Write(nd);
            OptimizerPatterns optPatt = ann.Patterns;

            if (optPatt == null || optPatt.isReadOnly) {
                optPatt = new OptimizerPatterns();
                ann.Patterns = optPatt;

                if (!nd.XmlType.MaybeMany) {
                    optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct);
                    optPatt.AddPattern(OptimizerPatternName.SameDepth);
                }
                else if (nd.XmlType.IsDod) {
                    optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct);
                }
            }

            return optPatt;
        }

        /// <summary>
        /// Create and initialize OptimizerPatterns annotation for the specified node.
        /// </summary>
        public static void Inherit(QilNode ndSrc, QilNode ndDst, OptimizerPatternName pattern) {
            OptimizerPatterns annSrc = OptimizerPatterns.Read(ndSrc);

            if (annSrc.MatchesPattern(pattern)) {
                OptimizerPatterns annDst = OptimizerPatterns.Write(ndDst);
                annDst.AddPattern(pattern);

                // Inherit pattern arguments
                switch (pattern) {
                    case OptimizerPatternName.Step:
                        annDst.AddArgument(OptimizerPatternArgument.StepNode, annSrc.GetArgument(OptimizerPatternArgument.StepNode));
                        annDst.AddArgument(OptimizerPatternArgument.StepInput, annSrc.GetArgument(OptimizerPatternArgument.StepInput));
                        break;

                    case OptimizerPatternName.FilterElements:
                        annDst.AddArgument(OptimizerPatternArgument.ElementQName, annSrc.GetArgument(OptimizerPatternArgument.ElementQName));
                        break;

                    case OptimizerPatternName.FilterContentKind:
                        annDst.AddArgument(OptimizerPatternArgument.KindTestType, annSrc.GetArgument(OptimizerPatternArgument.KindTestType));
                        break;

                    case OptimizerPatternName.EqualityIndex:
                        annDst.AddArgument(OptimizerPatternArgument.IndexedNodes, annSrc.GetArgument(OptimizerPatternArgument.IndexedNodes));
                        annDst.AddArgument(OptimizerPatternArgument.KeyExpression, annSrc.GetArgument(OptimizerPatternArgument.KeyExpression));
                        break;

                    case OptimizerPatternName.DodReverse:
                    case OptimizerPatternName.JoinAndDod:
                        annDst.AddArgument(OptimizerPatternArgument.DodStep, annSrc.GetArgument(OptimizerPatternArgument.DodStep));
                        break;

                    case OptimizerPatternName.MaxPosition:
                        annDst.AddArgument(OptimizerPatternArgument.MaxPosition, annSrc.GetArgument(OptimizerPatternArgument.MaxPosition));
                        break;

                    case OptimizerPatternName.SingleTextRtf:
                        annDst.AddArgument(OptimizerPatternArgument.RtfText, annSrc.GetArgument(OptimizerPatternArgument.RtfText));
                        break;
                }
            }
        }

        /// <summary>
        /// Add an argument to one of the matching patterns.
        /// </summary>
        public void AddArgument(OptimizerPatternArgument argId, object arg) {
            Debug.Assert(!this.isReadOnly, "This OptimizerPatterns instance is read-only.");

            switch ((int) argId) {
                case 0: this.arg0 = arg; break;
                case 1: this.arg1 = arg; break;
                case 2: this.arg2 = arg; break;
                default:
                    Debug.Assert(false, "Cannot handle more than 2 arguments.");
                    break;
            }
        }

        /// <summary>
        /// Get an argument of one of the matching patterns.
        /// </summary>
        public object GetArgument(OptimizerPatternArgument argNum) {
            object arg = null;

            switch ((int) argNum) {
                case 0: arg = this.arg0; break;
                case 1: arg = this.arg1; break;
                case 2: arg = this.arg2; break;
            }

            Debug.Assert(arg != null, "There is no '" + argNum + "' argument.");
            return arg;
        }

        /// <summary>
        /// Add a pattern to the list of patterns that the annotated node matches.
        /// </summary>
        public void AddPattern(OptimizerPatternName pattern) {
            Debug.Assert(Enum.IsDefined(typeof(OptimizerPatternName), pattern));
            Debug.Assert((int) pattern < 32);
            Debug.Assert(!this.isReadOnly, "This OptimizerPatterns instance is read-only.");
            this.patterns |= (1 << (int) pattern);
        }

        /// <summary>
        /// Return true if the annotated node matches the specified pattern.
        /// </summary>
        public bool MatchesPattern(OptimizerPatternName pattern) {
            Debug.Assert(Enum.IsDefined(typeof(OptimizerPatternName), pattern));
            return (this.patterns & (1 << (int) pattern)) != 0;
        }

        /// <summary>
        /// Return name of this annotation.
        /// </summary>
        public virtual string Name {
            get { return "Patterns"; }
        }

        /// <summary>
        /// Return string representation of this annotation.
        /// </summary>
        public override string ToString() {
            string s = "";

            for (int pattNum = 0; pattNum < PatternCount; pattNum++) {
                if (MatchesPattern((OptimizerPatternName) pattNum)) {
                    if (s.Length != 0)
                        s += ", ";

                    s += ((OptimizerPatternName) pattNum).ToString();
                }
            }

            return s;
        }
    }
}