File: QueryTreeBuilder.cs

package info (click to toggle)
mono 4.6.2.7%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 778,148 kB
  • ctags: 914,052
  • sloc: cs: 5,779,509; xml: 2,773,713; ansic: 432,645; sh: 14,749; makefile: 12,361; perl: 2,488; python: 1,434; cpp: 849; asm: 531; sql: 95; sed: 16; php: 1
file content (222 lines) | stat: -rw-r--r-- 8,816 bytes parent folder | download | duplicates (9)
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
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
    using System.Runtime;

    class QueryTreeBuilder
    {
        Diverger diverger;
        Opcode lastOpcode;

        internal QueryTreeBuilder()
        {
        }

        internal Opcode LastOpcode
        {
            get
            {
                return this.lastOpcode;
            }
        }

        internal Opcode Build(Opcode tree, OpcodeBlock newBlock)
        {
            if (null == tree)
            {
                this.lastOpcode = newBlock.Last;
                return newBlock.First;
            }

            this.diverger = new Diverger(tree, newBlock.First);

            if (!this.diverger.Find())
            {
                // The opcodes in newBlock already have equivalents or identical opcodes
                // in the query tree that can do the job
                Fx.Assert(this.diverger.TreePath.Count > 0, "");
                this.lastOpcode = this.diverger.TreePath[this.diverger.TreePath.Count - 1];
                return tree;
            }

            Fx.Assert(this.diverger.TreePath.Count == this.diverger.InsertPath.Count, "");

            // We can reuse opcodes upto this.diverger.TreePath[this.diverger.TreePath.Count - 1]
            // The remainder of the code in newBlock must be executed as is...
            if (null == this.diverger.TreeOpcode)
            {
                // We reached a leaf in the query tree
                // Simply add the remainder of the inserted code to the end of the tree path..
                this.diverger.TreePath[this.diverger.TreePath.Count - 1].Attach(this.diverger.InsertOpcode);
            }
            else
            {
                // Merge in the remaider of the new code block into the query tree
                // The first diverging opcodes follow the last entry in each path
                this.diverger.TreeOpcode.Add(this.diverger.InsertOpcode);
            }
            
            this.lastOpcode = newBlock.Last;
            if (this.diverger.InsertOpcode.IsMultipleResult())
            {
                // The complete new block was merged in, except for the the actual result opcode, which never
                // automatically merges. This means that the new block found all of its opcodes in common with 
                // the tree
                if (OpcodeID.Branch == this.diverger.TreeOpcode.ID)
                {
                    OpcodeList branches = (((BranchOpcode) this.diverger.TreeOpcode).Branches); 
                    for (int i = 0, count = branches.Count; i < count; ++i)
                    {
                        if (branches[i].IsMultipleResult())
                        {
                            this.lastOpcode = branches[i];
                            break;
                        }
                    }
                }
                else if (this.diverger.TreeOpcode.IsMultipleResult())
                {
                    this.lastOpcode = this.diverger.TreeOpcode;
                }
            }

            // Since we'll be diverging, any jumps that preceeded and leapt past the divergence point
            // will have to be branched
            this.FixupJumps();

            return tree;
        }

        void FixupJumps()
        {
            QueryBuffer<Opcode> treePath = this.diverger.TreePath;
            QueryBuffer<Opcode> insertPath = this.diverger.InsertPath;

            for (int i = 0; i < insertPath.Count; ++i)
            {
                if (insertPath[i].TestFlag(OpcodeFlags.Jump))
                {
                    Fx.Assert(treePath[i].ID == insertPath[i].ID, "");
                    JumpOpcode insertJump = (JumpOpcode) insertPath[i];
                    // Opcodes in 'insertPath' have equivalent opcodes in the query tree: i.e. the query tree contains an
                    // an equivalent execution path (upto the point of divergence naturally) that will produce in an identical
                    // result. The remainder of the query tree (anything that lies beyond the point of divergence) represents
                    // a distinct execution path and is grafted onto the tree as a new branch. In fact, we simply break off
                    // the remainder from the query being inserted and graft it onto the query tree.
                    // If there are jumps on the insert path that jump to opcodes NOT in the insert path, then the jumps
                    // will reach opcodes in the new branch we will add(see above). However, because the actual jump opcodes
                    // are shared (used as is from the query tree), the actual jump must also be branched. One jump will
                    // continue to jump to the original opcode and the second new one will jump to an opcode in the grafted branch.
                    if (-1 == insertPath.IndexOf(insertJump.Jump, i + 1))
                    {
                        Fx.Assert(insertJump.Jump.ID == OpcodeID.BlockEnd, "");

                        BlockEndOpcode jumpTo = (BlockEndOpcode) insertJump.Jump;
                        // no longer jumping from insertJump to jumpTo
                        insertJump.RemoveJump(jumpTo);

                        // Instead, jumping from treePath[i] to jumpTo
                        JumpOpcode treeJump = (JumpOpcode) treePath[i];
                        treeJump.AddJump(jumpTo);
                    }
                }
            }
        }

        // Can handle queries being merged into trees but not trees merged into trees.
        // In other words, no branch opcodes in the query being inserted
        internal struct Diverger
        {
            Opcode treeOpcode;
            QueryBuffer<Opcode> treePath;
            QueryBuffer<Opcode> insertPath;
            Opcode insertOpcode;

            internal Diverger(Opcode tree, Opcode insert)
            {
                this.treePath = new QueryBuffer<Opcode>(16);
                this.insertPath = new QueryBuffer<Opcode>(16);
                this.treeOpcode = tree;
                this.insertOpcode = insert;
            }

            internal Opcode InsertOpcode
            {
                get
                {
                    return this.insertOpcode;
                }
            }

            internal QueryBuffer<Opcode> InsertPath
            {
                get
                {
                    return this.insertPath;
                }
            }

            internal Opcode TreeOpcode
            {
                get
                {
                    return this.treeOpcode;
                }
            }

            internal QueryBuffer<Opcode> TreePath
            {
                get
                {
                    return this.treePath;
                }
            }

            // Stops at the last common node on each
            internal bool Find()
            {
                Opcode treeNext = null;
                while (true)
                {
                    if (null == this.treeOpcode && null == this.insertOpcode)
                    {
                        return false; // no diverge. both ran out at the same time
                    }
                    if (null == this.insertOpcode)
                    {
                        return false; // Ran out before tree did. No divergence.
                    }
                    if (null == this.treeOpcode)
                    {
                        return true; // tree ran out before insert. Divergence
                    }
                    if (this.treeOpcode.TestFlag(OpcodeFlags.Branch))
                    {
                        treeNext = this.treeOpcode.Locate(this.insertOpcode);
                        if (null == treeNext)
                        {
                            return true; // divergence
                        }
                        this.treeOpcode = treeNext;
                        treeNext = treeNext.Next;
                    }
                    else
                    {
                        if (!this.treeOpcode.Equals(this.insertOpcode))
                        {
                            return true; // divergence, obviously
                        }
                        treeNext = this.treeOpcode.Next;
                    }
                    // No divergence. Add to paths
                    this.treePath.Add(this.treeOpcode);
                    this.insertPath.Add(this.insertOpcode);
                    this.insertOpcode = this.insertOpcode.Next;
                    this.treeOpcode = treeNext;
                }
            }
        }
    }
}