speeding up xslt in gtk-doc

Stefan Kost <[email protected]>
Newsgroups gmane.comp.gnome.lib.xslt
Message-ID <[email protected]>
hi,

I am still not happy with the time it takes for gtk-doc to generate the
html. I did some profiling and tired various changes. Its not too
impressive. Just posting them here for feedback and comment on the
directions of what would be acceptable or not. I technically have commit
rights, so I can push things once they are ready. If patch 0002 looks
like a good idea, I can extend it for other accessors.

Stefan

Test case was generating the html for gstreamer-core api docs

real       user       sys
------------------------------ before
1m22.872s  1m17.317s  0m1.444s
1m19.261s  1m17.437s  0m1.384s
1m19.770s  1m17.417s  0m1.264s
------------------------------ 0001-xpath-annotate-branch-prediction.patch
1m18.123s  1m16.677s  0m1.256s
1m18.684s  1m17.181s  0m1.292s
1m18.887s  1m17.217s  0m1.364s
------------------------------
0002-xpath-split-traversal-into-init-and-next-functions.patch
1m18.537s  1m16.925s  0m1.388s
1m18.616s  1m16.913s  0m1.412s
1m18.249s  1m16.653s  0m1.328s
------------------------------
0003-xpath-avoid-a-memcpy-on-the-expense-of-temporarily-w.patch
1m17.481s  1m16.137s  0m1.208s
1m17.977s  1m16.481s  0m1.328s
1m17.791s  1m16.413s  0m1.232s

_______________________________________________
xslt mailing list, project page http://xmlsoft.org/XSLT/
[email protected]
http://mail.gnome.org/mailman/listinfo/xslt
0001-xpath-annotate-branch-prediction.patch (text/x-patch, 12.6 KB)
From 144d36fbdd4ff3fec27f50189617bdeb8979a4bf Mon Sep 17 00:00:00 2001
From: Stefan Kost <[email protected]>
Date: Tue, 3 May 2011 17:21:57 +0300
Subject: [PATCH 1/4] xpath: annotate branch prediction

---
 include/libxml/xpathInternals.h |   29 ++++++++++++++------
 xpath.c                         |   56 ++++++++++++++++++++------------------
 2 files changed, 49 insertions(+), 36 deletions(-)

diff --git a/include/libxml/xpathInternals.h b/include/libxml/xpathInternals.h
index dcd5243..f384e1a 100644
--- a/include/libxml/xpathInternals.h
+++ b/include/libxml/xpathInternals.h
@@ -21,6 +21,17 @@
 extern "C" {
 #endif
 
+/*
+ * Ideally have this for whole libxml2
+ */
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define XML_LIKELY(expr) (__builtin_expect ((expr), 1))
+#define XML_UNLIKELY(expr) (__builtin_expect ((expr), 0))
+#else
+#define XML_LIKELY(expr) (expr)
+#define XML_UNLIKELY(expr) (expr)
+#endif
+
 /************************************************************************
  *									*
  *			Helpers						*
@@ -237,7 +248,7 @@ XMLPUBFUN void * XMLCALL
  * Macro to return from the function if an XPath error was detected.
  */
 #define CHECK_ERROR							\
-    if (ctxt->error != XPATH_EXPRESSION_OK) return
+    if (XML_UNLIKELY (ctxt->error != XPATH_EXPRESSION_OK)) return
 
 /**
  * CHECK_ERROR0:
@@ -245,7 +256,7 @@ XMLPUBFUN void * XMLCALL
  * Macro to return 0 from the function if an XPath error was detected.
  */
 #define CHECK_ERROR0							\
-    if (ctxt->error != XPATH_EXPRESSION_OK) return(0)
+    if (XML_UNLIKELY (ctxt->error != XPATH_EXPRESSION_OK)) return(0)
 
 /**
  * XP_ERROR:
@@ -273,7 +284,7 @@ XMLPUBFUN void * XMLCALL
  * type.
  */
 #define CHECK_TYPE(typeval)						\
-    if ((ctxt->value == NULL) || (ctxt->value->type != typeval))	\
+    if (XML_UNLIKELY ((ctxt->value == NULL) || (ctxt->value->type != typeval)))	\
         XP_ERROR(XPATH_INVALID_TYPE)
 
 /**
@@ -284,7 +295,7 @@ XMLPUBFUN void * XMLCALL
  * type. Return(0) in case of failure
  */
 #define CHECK_TYPE0(typeval)						\
-    if ((ctxt->value == NULL) || (ctxt->value->type != typeval))	\
+    if (XML_UNLIKELY ((ctxt->value == NULL) || (ctxt->value->type != typeval)))	\
         XP_ERROR0(XPATH_INVALID_TYPE)
 
 /**
@@ -294,8 +305,8 @@ XMLPUBFUN void * XMLCALL
  * Macro to check that the number of args passed to an XPath function matches.
  */
 #define CHECK_ARITY(x)							\
-    if (ctxt == NULL) return;						\
-    if (nargs != (x))							\
+    if (XML_UNLIKELY (ctxt == NULL)) return;						\
+    if (XML_UNLIKELY (nargs != (x)))							\
         XP_ERROR(XPATH_INVALID_ARITY);
 
 /**
@@ -304,7 +315,7 @@ XMLPUBFUN void * XMLCALL
  * Macro to try to cast the value on the top of the XPath stack to a string.
  */
 #define CAST_TO_STRING							\
-    if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING))	\
+    if (XML_LIKELY ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING)))	\
         xmlXPathStringFunction(ctxt, 1);
 
 /**
@@ -313,7 +324,7 @@ XMLPUBFUN void * XMLCALL
  * Macro to try to cast the value on the top of the XPath stack to a number.
  */
 #define CAST_TO_NUMBER							\
-    if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_NUMBER))	\
+    if (XML_LIKELY ((ctxt->value != NULL) && (ctxt->value->type != XPATH_NUMBER)))	\
         xmlXPathNumberFunction(ctxt, 1);
 
 /**
@@ -322,7 +333,7 @@ XMLPUBFUN void * XMLCALL
  * Macro to try to cast the value on the top of the XPath stack to a boolean.
  */
 #define CAST_TO_BOOLEAN							\
-    if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_BOOLEAN))	\
+    if (XML_LIKELY ((ctxt->value != NULL) && (ctxt->value->type != XPATH_BOOLEAN)))	\
         xmlXPathBooleanFunction(ctxt, 1);
 
 /*
diff --git a/xpath.c b/xpath.c
index 608fe00..579db1b 100644
--- a/xpath.c
+++ b/xpath.c
@@ -2410,7 +2410,7 @@ valuePop(xmlXPathParserContextPtr ctxt)
 {
     xmlXPathObjectPtr ret;
 
-    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->valueNr <= 0)))
         return (NULL);
     ctxt->valueNr--;
     if (ctxt->valueNr > 0)
@@ -2433,8 +2433,9 @@ valuePop(xmlXPathParserContextPtr ctxt)
 int
 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
 {
-    if ((ctxt == NULL) || (value == NULL)) return(-1);
-    if (ctxt->valueNr >= ctxt->valueMax) {
+    if (XML_UNLIKELY((ctxt == NULL) || (value == NULL)))
+        return(-1);
+    if (XML_UNLIKELY(ctxt->valueNr >= ctxt->valueMax)) {
         xmlXPathObjectPtr *tmp;
 
         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
@@ -7524,7 +7525,7 @@ typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
  */
 xmlNodePtr
 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
     if (cur == NULL)
         return(ctxt->context->node);
     return(NULL);
@@ -7542,10 +7543,11 @@ xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  */
 xmlNodePtr
 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
-    if (cur == NULL) {
-	if (ctxt->context->node == NULL) return(NULL);
-	switch (ctxt->context->node->type) {
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
+    if (XML_UNLIKELY(cur == NULL)) {
+        cur = ctxt->context->node;
+	if (XML_UNLIKELY(cur == NULL)) return(NULL);
+	switch (cur->type) {
             case XML_ELEMENT_NODE:
             case XML_TEXT_NODE:
             case XML_CDATA_SECTION_NODE:
@@ -7555,7 +7557,7 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
             case XML_COMMENT_NODE:
             case XML_NOTATION_NODE:
             case XML_DTD_NODE:
-		return(ctxt->context->node->children);
+		return(cur->children);
             case XML_DOCUMENT_NODE:
             case XML_DOCUMENT_TYPE_NODE:
             case XML_DOCUMENT_FRAG_NODE:
@@ -7563,7 +7565,7 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 #ifdef LIBXML_DOCB_ENABLED
 	    case XML_DOCB_DOCUMENT_NODE:
 #endif
-		return(((xmlDocPtr) ctxt->context->node)->children);
+		return(((xmlDocPtr) cur)->children);
 	    case XML_ELEMENT_DECL:
 	    case XML_ATTRIBUTE_DECL:
 	    case XML_ENTITY_DECL:
@@ -7575,8 +7577,8 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 	}
 	return(NULL);
     }
-    if ((cur->type == XML_DOCUMENT_NODE) ||
-        (cur->type == XML_HTML_DOCUMENT_NODE))
+    if (XML_UNLIKELY((cur->type == XML_DOCUMENT_NODE) ||
+        (cur->type == XML_HTML_DOCUMENT_NODE)))
 	return(NULL);
     return(cur->next);
 }
@@ -7593,8 +7595,8 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  */
 static xmlNodePtr
 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
-    if (cur == NULL) {
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
+    if (XML_UNLIKELY(cur == NULL)) {
 	cur = ctxt->context->node;
 	if (cur == NULL) return(NULL);
 	/*
@@ -7745,7 +7747,7 @@ next_sibling:
  */
 xmlNodePtr
 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
     if (cur == NULL) {
 	if (ctxt->context->node == NULL)
 	    return(NULL);
@@ -7808,7 +7810,7 @@ xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  */
 xmlNodePtr
 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
     if (cur == NULL) {
 	if (ctxt->context->node == NULL)
 	    return(NULL);
@@ -7833,7 +7835,7 @@ xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  */
 xmlNodePtr
 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
     /*
      * the parent of an attribute or namespace node is the element
      * to which the attribute or namespace node is attached
@@ -7906,7 +7908,7 @@ xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  */
 xmlNodePtr
 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
     /*
      * the parent of an attribute or namespace node is the element
      * to which the attribute or namespace node is attached
@@ -8030,7 +8032,7 @@ xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  */
 xmlNodePtr
 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
     if (cur == NULL)
         return(ctxt->context->node);
     return(xmlXPathNextAncestor(ctxt, cur));
@@ -8049,7 +8051,7 @@ xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  */
 xmlNodePtr
 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
 	return(NULL);
@@ -8074,7 +8076,7 @@ xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  */
 xmlNodePtr
 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
 	return(NULL);
@@ -8105,7 +8107,7 @@ xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  */
 xmlNodePtr
 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
         return(cur->children);
@@ -8169,7 +8171,7 @@ xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
 xmlNodePtr
 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
 {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
     if (cur == NULL) {
         cur = ctxt->context->node;
         if (cur->type == XML_NAMESPACE_DECL)
@@ -8215,7 +8217,7 @@ static xmlNodePtr
 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
                               xmlNodePtr cur)
 {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
     if (cur == NULL) {
         cur = ctxt->context->node;
         if (cur == NULL)
@@ -8258,7 +8260,7 @@ xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
  */
 xmlNodePtr
 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
         if (ctxt->context->tmpNsList != NULL)
@@ -8295,7 +8297,7 @@ xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  */
 xmlNodePtr
 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
-    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
     if (ctxt->context->node == NULL)
 	return(NULL);
     if (ctxt->context->node->type != XML_ELEMENT_NODE)
@@ -9740,7 +9742,7 @@ xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
     xmlChar *ret;
     int count = 0;
 
-    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
+    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->cur == NULL))) return(NULL);
     /*
      * Accelerator for simple ASCII names
      */
-- 
1.7.1
0002-xpath-split-traversal-into-init-and-next-functions.patch (text/x-patch, 4.9 KB)
From c25ad12939a227dd0ae7cb0c4efd3e27f6e05e8b Mon Sep 17 00:00:00 2001
From: Stefan Kost <[email protected]>
Date: Tue, 3 May 2011 17:22:40 +0300
Subject: [PATCH 2/4] xpath: split traversal into init and next functions

This avoid us checking cur=NULL in next().
---
 xpath.c |   98 ++++++++++++++++++++++++++++++++++++--------------------------
 1 files changed, 57 insertions(+), 41 deletions(-)

diff --git a/xpath.c b/xpath.c
index 579db1b..476ac9d 100644
--- a/xpath.c
+++ b/xpath.c
@@ -7487,6 +7487,12 @@ xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
  *									*
  ************************************************************************/
 
+ /*
+ * A function to initialize traversal.
+ */
+typedef xmlNodePtr (*xmlXPathTraversalStartFunction)
+                    (xmlXPathParserContextPtr ctxt);
+
 /*
  * A traversal function enumerates nodes along an axis.
  * Initially it must be called with NULL, and it indicates
@@ -7584,6 +7590,51 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
 }
 
 /**
+ * xmlXPathFirstChildElement:
+ * @ctxt:  the XPath Parser context
+ *
+ * Init traversal for the "child" direction and nodes of type element.
+ * The child axis contains the children of the context node in document order.
+ *
+ * Returns the first element following that axis
+ */
+static xmlNodePtr
+xmlXPathFirstChildElement(xmlXPathParserContextPtr ctxt) {
+    xmlNodePtr cur = ctxt->context->node;
+
+    if (XML_UNLIKELY(cur == NULL)) return(NULL);
+    /*
+    * Get the first element child.
+    */
+    switch (cur->type) {
+        case XML_ELEMENT_NODE:
+        case XML_DOCUMENT_FRAG_NODE:
+        case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
+        case XML_ENTITY_NODE:
+            cur = cur->children;
+            if (cur != NULL) {
+                if (cur->type == XML_ELEMENT_NODE)
+                    return(cur);
+                do {
+                    cur = cur->next;
+                } while ((cur != NULL) &&
+                    (cur->type != XML_ELEMENT_NODE));
+                return(cur);
+            }
+            return(NULL);
+        case XML_DOCUMENT_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+#ifdef LIBXML_DOCB_ENABLED
+        case XML_DOCB_DOCUMENT_NODE:
+#endif
+            return(xmlDocGetRootElement((xmlDocPtr) cur));
+        default:
+            return(NULL);
+    }
+    return(NULL);
+}
+
+/**
  * xmlXPathNextChildElement:
  * @ctxt:  the XPath Parser context
  * @cur:  the current node in the traversal
@@ -7595,40 +7646,6 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  */
 static xmlNodePtr
 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
-    if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
-    if (XML_UNLIKELY(cur == NULL)) {
-	cur = ctxt->context->node;
-	if (cur == NULL) return(NULL);
-	/*
-	* Get the first element child.
-	*/
-	switch (cur->type) {
-            case XML_ELEMENT_NODE:
-	    case XML_DOCUMENT_FRAG_NODE:
-	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
-            case XML_ENTITY_NODE:
-		cur = cur->children;
-		if (cur != NULL) {
-		    if (cur->type == XML_ELEMENT_NODE)
-			return(cur);
-		    do {
-			cur = cur->next;
-		    } while ((cur != NULL) &&
-			(cur->type != XML_ELEMENT_NODE));
-		    return(cur);
-		}
-		return(NULL);
-            case XML_DOCUMENT_NODE:
-            case XML_HTML_DOCUMENT_NODE:
-#ifdef LIBXML_DOCB_ENABLED
-	    case XML_DOCB_DOCUMENT_NODE:
-#endif
-		return(xmlDocGetRootElement((xmlDocPtr) cur));
-	    default:
-		return(NULL);
-	}
-	return(NULL);
-    }
     /*
     * Get the next sibling element node.
     */
@@ -11979,6 +11996,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
     int hasPredicateRange, hasAxisRange, pos, size, newSize;
     int breakOnFirstHit;
 
+    xmlXPathTraversalStartFunction next_i = NULL;
     xmlXPathTraversalFunction next = NULL;
     /* compound axis traversal */
     xmlXPathTraversalFunctionExt outerNext = NULL;
@@ -12044,6 +12062,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
 		/*
 		* Optimization if an element node type is 'element'.
 		*/
+		next_i = xmlXPathFirstChildElement;
 		next = xmlXPathNextChildElement;
 	    } else
 		next = xmlXPathNextChild;
@@ -12205,13 +12224,9 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
 	* Traverse the axis and test the nodes.
 	*/
 	pos = 0;
-	cur = NULL;
+	cur = next_i ? next_i(ctxt) : next(ctxt, NULL);
 	hasNsNodes = 0;
-        do {
-            cur = next(ctxt, cur);
-            if (cur == NULL)
-                break;
-
+        while (cur) {
 	    /*
 	    * QUESTION TODO: What does the "first" and "last" stuff do?
 	    */
@@ -12390,7 +12405,8 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
                     }
                     break;
 	    } /* switch(test) */
-        } while (cur != NULL);
+            cur = next(ctxt, cur);
+        };
 
 	goto apply_predicates;
 
-- 
1.7.1
0003-xpath-avoid-a-memcpy-on-the-expense-of-temporarily-w.patch (text/x-patch, 910 B)
From 7066379eb1ef02f68f1cf66168771e13b39cc765 Mon Sep 17 00:00:00 2001
From: Stefan Kost <[email protected]>
Date: Tue, 3 May 2011 17:25:39 +0300
Subject: [PATCH 4/4] xpath: avoid a memcpy on the expense of temporarily wasting memory

Just allocate a target buffer and fill, instead of printing to a temp buffer and
then dup'ing.
---
 xpath.c |    7 +++----
 1 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/xpath.c b/xpath.c
index 6b2f627..384a36c 100644
--- a/xpath.c
+++ b/xpath.c
@@ -5586,10 +5586,9 @@ xmlXPathCastNumberToString (double val) {
 	    ret = xmlStrdup((const xmlChar *) "0");
 	} else {
 	    /* could be improved */
-	    char buf[100];
-	    xmlXPathFormatNumber(val, buf, 99);
-	    buf[99] = 0;
-	    ret = xmlStrdup((const xmlChar *) buf);
+	    ret = xmlMalloc(100);
+	    xmlXPathFormatNumber(val, ret, 99);
+	    ret[99] = 0;
 	}
     }
     return(ret);
-- 
1.7.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.