From d22332a9ee43fbb1a50848730dc5f4fc8974e42b Mon Sep 17 00:00:00 2001 From: "sicking%bigfoot.com" Date: Mon, 31 Mar 2003 09:02:17 +0000 Subject: [PATCH] Documentation update. More ideas for faster XPath git-svn-id: svn://10.0.0.236/trunk@140444 18797224-902f-48f8-a5cc-f745e15eee43 --- .../transformiix/docs/optimized-xpath.html | 226 +++++++++--------- 1 file changed, 107 insertions(+), 119 deletions(-) diff --git a/mozilla/extensions/transformiix/docs/optimized-xpath.html b/mozilla/extensions/transformiix/docs/optimized-xpath.html index c5bbc96156c..41e3fffba10 100644 --- a/mozilla/extensions/transformiix/docs/optimized-xpath.html +++ b/mozilla/extensions/transformiix/docs/optimized-xpath.html @@ -85,6 +85,42 @@

Stage 3

+

Summary

+

+ Refcount ExprResults to reduce the number of objects + created during evaluation. +

+ +

Details

+

+ Right now every subexpression creates a new object during evaluation. + If we refcounted objects we would be often be able to reuse the same + objects across multiple evaluations. We should also keep global + result-objects for true and false, that way expressions that return + bool-values would never have to create any objects. +

+ +

+ This does however require that the returned objects arn't modified + since they might be used elsewhere. This is not a big problem in the + current code where we pretty much only modify nodesets in a couple + of places. +

+ +

+ To be able to reuse objects across subexpressions we chould have an + ExprResult::ensureModifyable-function. This would + return the same object if the refcount is 1, and create a new object + to return otherwise. This is especially usefull for nodesets which + would be mostly used by a single object at a time. But it could be + just as usefull for other types, though then we might need a + ExprResult::ensureModifyableOfType(ExprResult::ResultType)-function + that only returned itself if it has a refcount of 1 and is of the + requsted type. +

+ +

Stage 4

+

Summary

Speed up evaluation of XPath expressions by using specialized @@ -133,71 +169,48 @@

Class:

- Steps along the attribute axis which doesn't contain wildcards -

Example:

- @foo -

What we do today:

- Walk through the attributes NamedNodeMap and filter each node using a NameTest. -

What we could do:

- Call getAttributeNode (or actually getAttributeNodeNS) on the contextnode and return a nodeset containing just the returned node, or an empty nodeset if NULL is returned. -

Class:

- Union expressions where each expression consists of a LocationStep and all LocationSteps have the same axis. None of the LocationSteps have any predicates (well, this could be relaxed a bit) -

Example:

- foo | bar | baz -

What we do today:

- Evaluate each LocationStep separately and thus walk the same path through the document each time. During the walking the NodeTest is applied to filter out the correct nodes. The resulting nodesets are then merged and thus we generate orderInfo objects for most nodes. -

What we could do:

- Have just one LocationStep object which contains a NodeTest that is a "UnionNodeTest" which contains a list of NodeTests. The UnionNodeTest then tests each NodeTest until it finds one that returns true. If none do then false is returned. This results in just one walk along the axis and no need to generate any orderInfo objects. -

Class:

- Steps where the predicates isn't context-node-list sensitive. -

Example:

- foo[@bar] -

What we do today:

- Build a nodeset of all nodes that match 'foo' and then filter the nodeset through the predicate and thus do some node shuffling. -

What we could do:

- Create a "PredicatedNodeTest" that contains a NodeTest and a list of predicates. The PredicatedNodeTest returns true if both the NodeTest returns true and all predicats evaluate to true. Then let the @@ -206,98 +219,66 @@ (Note how this combines nicely with the previous optimisation...) (Actually this can be done even if some predicates are context-list sensitive, but only up until the first that isn't.) -

Class:

- PathExprs that only contains steps that from the child:: and attribute:: axes. -

Example:

- foo/bar/baz -

What we do today:

- For each step we evaluate the step once for every node in a nodeset (for example for the second step the nodeset is the list of all "foo" children) and then merge the resulting nodesets while making sure that we keep the nodes in document order (and thus generate orderInfo objects). -

What we could do:

- The same thing except that we don't merge the resulting nodeset, but rather just concatenate them. We always know that the resulting nodesets are after each other in node order. -

Class:

- List of predicates where some predicate are not context-list sensitive -

Example:

- foo[position() > 3][@bar][.//baz][position() > size() div 2][.//@fud] -

What we do today:

- Apply each predicate separately requiring us to shuffle nodes five times in the above example. -

What we could do:

- Merge all predicates that are not node context-list sensitive into the previous predicate. The above predicate list could be merged into the following predicate list foo[(position() > 3) and (@bar) and (.//baz)][(position() > size() div 2) and (.//@fud)] Which only requires two node-shuffles -

Class:

- Predicates that are only context-list-position sensitive and not context-list-size sensitive -

Example:

- foo[position() > 5][position() mod 2] -

What we do today:

- Build the entire list of nodes that matches "foo" and then apply the predicates -

What we could do:

- Apply the predicates during the initial build of the first nodeset. We would have to keep track of how many nodes has passed each and somehow override the code that calculates the context-list-position. -

Class:

- Predicates that are constants -

Example:

- foo[5] -

What we do today:

- Perform the appropriate walk and build the entire nodeset. Then apply the predicate. -

What we could do:

- There are three types of constant results; 1) Numerical values 2) Results with a true boolean-value 3) Results with a false boolean value. In the case of 1) we should only step up until the n:th node (5 in above @@ -309,137 +290,144 @@ able to decide if it's a constant or not at parsetime. Note that while evaluating a LocationStep [//foo] can be considered constant. -

Class:

- PathExprs that contains '//' followed by an unpredicated child-step. -

Example:

- .//bar -

What we do today:

- We walk the entire subtree below the contextnode and at every node we evaluate the 'bar'-expression which walks all the children of the contextnode. This means that we'll walk the entire subtree twice. -

What we could do:

- Change the expression into "./descendant::bar". This means that we'll only walk the tree once. This can only be done if there are no predicates since the context-node-list will be different for predicates in the new expression. Note that this combines nicely with the "Steps where the predicates isn't context-node-list sensitive" optimization. -

Class:

- PathExprs where the first step is '.' -

Example:

- ./* -

What we do today:

- Evaluate the step "." which always returns the same node and then evaluate the rest of the PathExpr. -

What we could do:

- Remove the '.'-step and simply evaluate the other steps. In the example we could even remove the entire PathExpr-object and replace it with a single Step-object. -

Class:

- Steps along the attribute axis which doesn't contain wildcards and we only care about the boolean value. -

Example:

- foo[@bar], @foo or @bar -

What we do today:

- Evaluate the step and create a nodeset. Then get the bool-value of the nodeset by checking if the nodeset contain any nodes. -

What we could do:

- Simply check if the current element has an attribute of the requested name and return a bool-result. -

Class:

- Steps where we only care about the boolean value. -

Example:

- foo[processing-instruction()] -

What we do today:

- Evaluate the step and create a nodeset. Then get the bool-value of the nodeset by checking if the nodeset contain any nodes. -

What we could do:

- Walk along the axis until we find a node that matches the nodetest. If one is found we can stop the walking and return a true bool-result immediatly, otherwise a false bool-result is returned. It might not be worth implementing all axes unless we can reuse - code from the normal Step-code. - -

- -

Stage 4

- -

Summary

-

- Refcount ExprResults to reduce the number of objects - created during evaluation. -

- -

Details

-

- Right now every subexpression creates a new object during evaluation. - If we refcounted objects we would be often be able to reuse the same - objects across multiple evaluations. We should also keep global - result-objects for true and false, that way expressions that return - bool-values would never have to create any objects. + code from the normal Step-code. This could also be applied to + PathExprs by getting the boolvalue of the last step.

- This does however require that the returned objects arn't modified - since they might be used elsewhere. This is not a big problem in the - current code where we pretty much only modify nodesets in a couple - of places. +

Class:

+ Expressions where the value of an attribute is compared to + a literal. +

Example:

+ @bar = 'value' +

What we do today:

+ Evaluate the attribute-step and then compare the resulting nodeset + to the value. +

What we could do:

+ Get the attribute-value for the element and compare that directly + to the value. In the above example we would just call + getAttr('bar', kNameSpaceID_None) and compare the + resulting string with 'value'.

- To be able to reuse objects across subexpressions we chould have an - ExprResult::ensureModifyable-function. This would - return the same object if the refcount is 1, and create a new object - to return otherwise. This is especially usefull for nodesets which - would be mostly used by a single object at a time. But it could be - just as usefull for other types, though then we might need a - ExprResult::ensureModifyableOfType(ExprResult::ResultType)-function - that only returned itself if it has a refcount of 1 and is of the - requsted type. +

Class:

+ PathExprs where the last step has a predicate that is not + context-nodeset dependent and that contains a part that is not + context-node dependent. +

Example:

+ foo/*[@bar = current()/@bar] +

What we do today:

+

What we could do:

+ First evaluate "foo/*" and "current()/@bar". Then replace + "current()/@bar" with a literal (and possibly optimize) and filter + all nodes in the nodeset from "foo/*". +

+ +

+

Class:

+ local-name() or namespace-uri() compared to a literal +

Example:

+ local-name() = 'foo' +

What we do today:

+ evaluate the local-name function and compare the string-result to + the string-result of the literal. +

What we could do:

+ Atomize the literal (or get the namespaceID in case of + namespace-uri()) and then compare that to the atom-name of the + contextnode. This is primarily usefull when combined with the + previous class. +

+ +

+

Class:

+ Comparisons where one side is a nodeset and the other is not a + bool-value. +

Example:

+ //myElem = @baz +

What we do today:

+ Evaluate both sides and then compare them according to the spec. +

What we could do:

+ First of all we should start by evaluating the nodeset-side, if the + result is an empty nodeset false can be returned immediatly. + Otherwise we evaluate as normal. When both sides are nodesets we + should examine them and try to figure out which is faster to + evaluate. That expression should be evaluated first (probably + by making it the left-hand-side expression). +

+ +

+

Class:

+ Comparisons where one side is a PathExpr and the other is a + bool-value. +

Example:

+ baz = ($foo > $bar) +

What we do today:

+ Evaluate both sides and then compare them. +

What we could do:

+ Apply the "Steps where we only care about the boolean + value"-optimization on the PathExpr-side and then evaluate as usual.

Stage 5