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;
}
}
}
}
}
|