Bug 691001 part 1. Hoist property check out of tight loop / prevent unnecessary Namespace object creation. r=brendan
authorAndrew Paprocki <andrew@ishiboo.com>
Mon, 24 Oct 2011 21:45:17 -0400
changeset 79743 2fef1412e0e8ec4ef8b60f0c4194907ac17bc58f
parent 79742 8f1b74f0b569841beb197ea4c38a2b3772ea455b
child 79744 bdbdde9ab432abde409bf1be9322bff54b4e925c
push idunknown
push userunknown
push dateunknown
reviewersbrendan
bugs691001
milestone10.0a1
Bug 691001 part 1. Hoist property check out of tight loop / prevent unnecessary Namespace object creation. r=brendan
js/src/jsxml.cpp
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -2371,29 +2371,26 @@ namespace_match(const void *a, const voi
     return EqualStrings(nsa->getNameURI(), nsb->getNameURI());
 }
 
 /* ECMA-357 10.2.1 and 10.2.2 */
 #define TO_SOURCE_FLAG 0x80000000
 
 static JSString *
 XMLToXMLString(JSContext *cx, JSXML *xml, const JSXMLArray *ancestorNSes,
-               uint32 indentLevel)
-{
-    JSBool pretty, indentKids;
+               uint32 indentLevel, JSBool pretty)
+{
+    JSBool indentKids;
     StringBuffer sb(cx);
     JSString *str;
     JSLinearString *prefix, *nsuri;
     uint32 i, n, nextIndentLevel;
     JSObject *ns, *ns2;
     AutoNamespaceArray empty(cx), decls(cx), ancdecls(cx);
 
-    if (!GetBooleanXMLSetting(cx, js_prettyPrinting_str, &pretty))
-        return NULL;
-
     if (pretty) {
         if (!sb.appendN(' ', indentLevel & ~TO_SOURCE_FLAG))
             return NULL;
     }
 
     str = NULL;
 
     switch (xml->xml_class) {
@@ -2428,17 +2425,17 @@ XMLToXMLString(JSContext *cx, JSXML *xml
             JSXMLArrayCursor cursor(&xml->xml_kids);
             i = 0;
             while (JSXML *kid = (JSXML *) cursor.getNext()) {
                 if (pretty && i != 0) {
                     if (!sb.append('\n'))
                         return NULL;
                 }
 
-                JSString *kidstr = XMLToXMLString(cx, kid, ancestorNSes, indentLevel);
+                JSString *kidstr = XMLToXMLString(cx, kid, ancestorNSes, indentLevel, pretty);
                 if (!kidstr || !sb.append(kidstr))
                     return NULL;
                 ++i;
             }
         }
 
         if (sb.empty())
             return cx->runtime->emptyString;
@@ -2447,18 +2444,26 @@ XMLToXMLString(JSContext *cx, JSXML *xml
       default:;
     }
 
     /* After this point, control must flow through label out: to exit. */
     if (!js_EnterLocalRootScope(cx))
         return NULL;
 
     /* ECMA-357 10.2.1 step 8 onward: handle ToXMLString on an XML element. */
-    if (!ancestorNSes)
+    if (!ancestorNSes) {
+        // Ensure a namespace with empty strings exists in the initial array,
+        // otherwise every call to GetNamespace() when running toString() on
+        // an XML object with no namespace defined will create a new Namespace
+        // object on every call.
+        JSObject *emptyns = NewXMLNamespace(cx, cx->runtime->emptyString, cx->runtime->emptyString, JS_FALSE);
+        if (!emptyns || !XMLARRAY_APPEND(cx, &empty.array, emptyns))
+            goto out;
         ancestorNSes = &empty.array;
+    }
 
     /* Clone in-scope namespaces not in ancestorNSes into decls. */
     {
         JSXMLArrayCursor cursor(&xml->xml_namespaces);
         while ((ns = (JSObject *) cursor.getNext()) != NULL) {
             if (!IsDeclared(ns))
                 continue;
             if (!XMLARRAY_HAS_MEMBER(ancestorNSes, ns, namespace_identity)) {
@@ -2687,17 +2692,17 @@ XMLToXMLString(JSContext *cx, JSXML *xml
         {
             JSXMLArrayCursor cursor(&xml->xml_kids);
             while (JSXML *kid = (JSXML *) cursor.getNext()) {
                 if (pretty && indentKids) {
                     if (!sb.append('\n'))
                         goto out;
                 }
 
-                JSString *kidstr = XMLToXMLString(cx, kid, &ancdecls.array, nextIndentLevel);
+                JSString *kidstr = XMLToXMLString(cx, kid, &ancdecls.array, nextIndentLevel, pretty);
                 if (!kidstr)
                     goto out;
 
                 if (!sb.append(kidstr))
                     goto out;
             }
         }
 
@@ -2752,20 +2757,24 @@ ToXMLString(JSContext *cx, jsval v, uint
             return NULL;
         JSString *str = js_ValueToString(cx, v);
         if (!str)
             return NULL;
         StringBuffer sb(cx);
         return EscapeElementValue(cx, sb, str, toSourceFlag);
     }
 
+    JSBool pretty;
+    if (!GetBooleanXMLSetting(cx, js_prettyPrinting_str, &pretty))
+        return NULL;
+
     /* Handle non-element cases in this switch, returning from each case. */
     JS::Anchor<JSObject *> anch(obj);
     JSXML *xml = reinterpret_cast<JSXML *>(obj->getPrivate());
-    return XMLToXMLString(cx, xml, NULL, toSourceFlag | 0);
+    return XMLToXMLString(cx, xml, NULL, toSourceFlag | 0, pretty);
 }
 
 static JSObject *
 ToAttributeName(JSContext *cx, jsval v)
 {
     JSLinearString *uri, *prefix;
     JSObject *obj;
     Class *clasp;