/// <summary> /// Loop over all branches, trying to locate one that is equal to the given opcode /// If the branch is a branch itself, perform the locate recursively. /// </summary> /// <param name="opcode"></param> /// <returns></returns> internal override Opcode Locate(Opcode opcode) { Fx.Assert(!opcode.TestFlag(OpcodeFlags.Branch), ""); for (int i = 0, count = this.branches.Count; i < count; ++i) { Opcode branch = this.branches[i]; if (branch.TestFlag(OpcodeFlags.Branch)) { // The branch is itself a branch. Since branch opcodes serve as branches in the exection // path for a query, but don't comprise one of the opcodes used to actually perform it, we // recursively try to locate an equivalent opcode inside the branch Opcode subBranch = branch.Locate(opcode); if (null != subBranch) { return(subBranch); } } else if (branch.Equals(opcode)) { return(branch); } } return(null); }
void AddAlwaysBranch(QueryBranch literalBranch, Opcode next) { if (OpcodeID.Branch == next.ID) { BranchOpcode opcode = (BranchOpcode)next; OpcodeList branches = opcode.Branches; for (int i = 0; i < branches.Count; ++i) { Opcode branch = branches[i]; if (this.IsAlwaysBranch(branch)) { this.AlwaysBranches.AddInOrder(new QueryBranch(branch, literalBranch.ID)); } else { branch.Flags |= OpcodeFlags.NoContextCopy; } } } else { Fx.Assert(!next.TestFlag(OpcodeFlags.Branch), ""); if (this.IsAlwaysBranch(next)) { this.AlwaysBranches.AddInOrder(new QueryBranch(next, literalBranch.ID)); } else { next.Flags |= OpcodeFlags.NoContextCopy; } } }
private void InvokeMultiMatch(ProcessingContext context) { int counterMarker = context.Processor.CounterMarker; BranchContext context2 = new BranchContext(context); int count = this.resultTable.Count; int num3 = 0; while (num3 < count) { ProcessingContext context3; QueryBranchResult result = this.resultTable[num3]; QueryBranch branch = result.Branch; Opcode next = branch.Branch.Next; if (next.TestFlag(OpcodeFlags.NoContextCopy)) { context3 = context; } else { context3 = context2.Create(); } this.InitResults(context3); context3.Values[context3.TopArg[result.ValIndex]].Boolean = true; while (++num3 < count) { result = this.resultTable[num3]; if (branch.ID != result.Branch.ID) { break; } context3.Values[context3.TopArg[result.ValIndex]].Boolean = true; } try { context3.EvalCodeBlock(next); } catch (XPathNavigatorException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception.Process(next)); } catch (NavigatorInvalidBodyAccessException exception2) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception2.Process(next)); } context.Processor.CounterMarker = counterMarker; } context2.Release(); }
internal QueryBranch GetBranch(Opcode op) { if (op.TestFlag(OpcodeFlags.Literal)) { LiteralRelationOpcode opcode = this.ValidateOpcode(op); if (opcode != null) { QueryBranch branch = this.branchIndex[opcode.Literal]; if ((branch != null) && (branch.Branch.ID == op.ID)) { return(branch); } } } return(null); }
internal QueryBranch GetBranch(Opcode op) { if (op.TestFlag(OpcodeFlags.Literal)) { LiteralRelationOpcode relOp = this.ValidateOpcode(op); if (null != relOp) { QueryBranch branch = this.branchIndex[relOp.Literal]; if (null != branch && branch.Branch.ID == op.ID) { return(branch); } } } return(null); }
private bool IsAlwaysBranch(Opcode next) { JumpIfOpcode opcode = next as JumpIfOpcode; if (opcode != null) { if (opcode.Test) { Opcode opcode3; Opcode jump = opcode.Jump; if (jump == null) { return(false); } if (jump.TestFlag(OpcodeFlags.Branch)) { OpcodeList branches = ((BranchOpcode)jump).Branches; for (int i = 0; i < branches.Count; i++) { opcode3 = branches[i].Next; if ((opcode3 != null) && !opcode3.TestFlag(OpcodeFlags.Result)) { return(true); } } return(false); } opcode3 = opcode.Jump.Next; if ((opcode3 != null) && opcode3.TestFlag(OpcodeFlags.Result)) { return(false); } } return(true); } if (OpcodeID.BlockEnd == next.ID) { return(!next.Next.TestFlag(OpcodeFlags.Result)); } return(!next.TestFlag(OpcodeFlags.Result)); }
internal override Opcode Locate(Opcode opcode) { int num = 0; int count = this.branches.Count; while (num < count) { Opcode opcode2 = this.branches[num]; if (opcode2.TestFlag(OpcodeFlags.Branch)) { Opcode opcode3 = opcode2.Locate(opcode); if (opcode3 != null) { return(opcode3); } } else if (opcode2.Equals(opcode)) { return(opcode2); } num++; } return(null); }
private bool IsAlwaysBranch(Opcode next) { JumpIfOpcode opcode = next as JumpIfOpcode; if (opcode != null) { if (opcode.Test) { Opcode opcode3; Opcode jump = opcode.Jump; if (jump == null) { return false; } if (jump.TestFlag(OpcodeFlags.Branch)) { OpcodeList branches = ((BranchOpcode) jump).Branches; for (int i = 0; i < branches.Count; i++) { opcode3 = branches[i].Next; if ((opcode3 != null) && !opcode3.TestFlag(OpcodeFlags.Result)) { return true; } } return false; } opcode3 = opcode.Jump.Next; if ((opcode3 != null) && opcode3.TestFlag(OpcodeFlags.Result)) { return false; } } return true; } if (OpcodeID.BlockEnd == next.ID) { return !next.Next.TestFlag(OpcodeFlags.Result); } return !next.TestFlag(OpcodeFlags.Result); }
internal QueryBranch GetBranch(Opcode op) { if (op.TestFlag(OpcodeFlags.Literal)) { LiteralRelationOpcode opcode = this.ValidateOpcode(op); if (opcode != null) { QueryBranch branch = this.branchIndex[opcode.Literal]; if ((branch != null) && (branch.Branch.ID == op.ID)) { return branch; } } } return null; }
bool IsAlwaysBranch(Opcode next) { Fx.Assert(null != next, ""); // Opcodes subsequent to matching literals must obviously be branched to. // The question is whether we should branch to the opcodes following those literals that do *not* match. // Naturally, the answer depends on the sort of opcode that succeeds the literal. // // If the literal is within a boolean conjunction, the succeeding opcode will either be a JumpIfNot // Or a BlockEnd. // // -If the JumpIfNot is multiway, then always evaluate if it contains ANY non-result only opcodes. // -If JumpIfNot(False) -i.e. AND - only evaluate if the opcode succeeding the jump is NOT a result opcode. // -If JumpIfNot(True) - i.e. OR - always evaluate // // -If BlockEnd - evaluate only if not followed by a result // // When branching for matching literals, we push trues onto the ValueStack corresponding to the items that // matched. When branching for non-matching literals, we push ALL FALSE values... and then eval. // is it a the termination of a conditional? JumpIfOpcode jump = next as JumpIfOpcode; if (null != jump) { // Is the conditional JumpIfNot(False) = i.e. OR? if (!jump.Test) { return(true); } // Does the conditional actually jump to anything? Should never be the case, but paranoia demands.. Opcode jumpTo = jump.Jump; if (null == jumpTo) { return(false); } // Lets see where the jump will take us Opcode postJump; if (jumpTo.TestFlag(OpcodeFlags.Branch)) { // Multiway jump OpcodeList branches = ((BranchOpcode)jumpTo).Branches; for (int i = 0; i < branches.Count; ++i) { postJump = branches[i].Next; if (null != postJump && !postJump.TestFlag(OpcodeFlags.Result)) { // There is at least one jump here that leads to a non-result. // For now, this dooms everybody to being branched to, whether or not their respective literals // matched return(true); } } return(false); } // single jump postJump = jump.Jump.Next; if (null != postJump && postJump.TestFlag(OpcodeFlags.Result)) { return(false); } return(true); } // If the next opcode is a BlockEnd, then only bother processing if what follows the block is not a result if (OpcodeID.BlockEnd == next.ID) { Fx.Assert(null != next.Next, ""); return(!next.Next.TestFlag(OpcodeFlags.Result)); } // The literal is not inside a boolean conjunction // If the literal is not followed by a result, then we must do further processing after the branch return(!next.TestFlag(OpcodeFlags.Result)); }
void InvokeMultiMatch(ProcessingContext context) { int marker = context.Processor.CounterMarker; BranchContext branchContext = new BranchContext(context); // struct. quick. int resultTableCount = this.resultTable.Count; for (int i = 0; i < resultTableCount;) { QueryBranchResult result = this.resultTable[i]; QueryBranch branch = result.Branch; // Branches can arbitrarily alter context stacks, rendering them unuseable to other branches. // Therefore, before following a branch, we have to clone the context. Cloning is relatively efficient because // can avoid allocating memory in most cases. We cannot, unfortunately, avoid Array copies. // // Optimization: // We can avoid cloning altogether when we can predict that the branch does NOT tamper with the stack, // or does so in a predictable way. If we are sure that we can restore the stack easily after the branch // completes, we have no reason to copy the stack. ProcessingContext newContext; Opcode nextOpcode = branch.Branch.Next; if (nextOpcode.TestFlag(OpcodeFlags.NoContextCopy)) { newContext = context; } else { newContext = branchContext.Create(); } this.InitResults(newContext); // // Matches are sorted by their branch ID. // It is very possible that the a literal matches multiple times, especially when the value being // compared is a sequence. A literal may match multiple items in a single sequence // OR multiple items in multiple sequences. If there were 4 context sequences, the literal may have // matched one item each in 3 of them. The branchID for that literal will be present 3 times in the // resultTable. // Sorting the matches groups them by their branch Ids. We only want to take the branch ONCE, so now we // iterate over all the duplicate matches.. // result.ValIndex will give us the index of the value that was matched. Thus if the 3rd sequence // matched, ValIndex == 2 (0 based) newContext.Values[newContext.TopArg[result.ValIndex]].Boolean = true; while (++i < resultTableCount) { result = this.resultTable[i]; if (branch.ID == result.Branch.ID) { newContext.Values[newContext.TopArg[result.ValIndex]].Boolean = true; } else { break; } } try { newContext.EvalCodeBlock(nextOpcode); } catch (XPathNavigatorException e) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(nextOpcode)); } catch (NavigatorInvalidBodyAccessException e) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(nextOpcode)); } context.Processor.CounterMarker = marker; } branchContext.Release(); }