Bug 753885 - Part 3: Expose XML global constructors only if JSOPTION_ALLOW_XML is set. r=Waldo.
authorJason Orendorff <jorendorff@mozilla.com>
Wed, 30 May 2012 15:05:59 -0500
changeset 95289 a780bb0de69526f27a0d48f89ceb6cf77fe3e88a
parent 95288 9be14c2b115eb9f985d86987ba06dc9b548ce303
child 95290 29a18a93721dd7ff571563a89f3eb14ba9e7a2a9
push id10045
push userjorendorff@mozilla.com
push dateWed, 30 May 2012 20:14:45 +0000
treeherdermozilla-inbound@29a18a93721d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs753885
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 753885 - Part 3: Expose XML global constructors only if JSOPTION_ALLOW_XML is set. r=Waldo.
js/src/jit-test/tests/basic/bug753885-2.js
js/src/jsapi.cpp
js/src/jsapi.h
js/src/vm/GlobalObject.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug753885-2.js
@@ -0,0 +1,24 @@
+// XML-specific classes do not resolve unless JSOPTION_ALLOW_XML is enabled.
+
+assertEq(options().split(",").indexOf("allow_xml") >= 0, true);
+options("allow_xml");
+
+var xmlnames = ["XML", "XMLList", "isXMLName", "QName", "Namespace"];
+for (var name of xmlnames)
+    assertEq(name in this, false);
+
+var globals = Object.getOwnPropertyNames(this);
+for (var name of xmlnames)
+    assertEq(globals.indexOf(name), -1);
+
+var g = newGlobal('new-compartment');
+for (var name of xmlnames)
+    assertEq(name in g, false);
+
+// Turn it back on and check that the XML classes magically appear.
+options("allow_xml");
+assertEq("QName" in this, true);
+
+globals = Object.getOwnPropertyNames(this);
+for (var name of xmlnames)
+    assertEq(globals.indexOf(name) >= 0, true);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1924,28 +1924,28 @@ JS_ResolveStandardClass(JSContext *cx, J
     JSStdName *stdnm;
     unsigned i;
 
     RootedObject obj(cx, obj_);
 
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
-    *resolved = JS_FALSE;
+    *resolved = false;
 
     rt = cx->runtime;
     if (!rt->hasContexts() || !JSID_IS_ATOM(id))
-        return JS_TRUE;
+        return true;
 
     idstr = JSID_TO_STRING(id);
 
     /* Check whether we're resolving 'undefined', and define it if so. */
     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
     if (idstr == atom) {
-        *resolved = JS_TRUE;
+        *resolved = true;
         return obj->defineProperty(cx, atom->asPropertyName(), UndefinedValue(),
                                    JS_PropertyStub, JS_StrictPropertyStub,
                                    JSPROP_PERMANENT | JSPROP_READONLY);
     }
 
     /* Try for class constructors/prototypes named by well-known atoms. */
     stdnm = NULL;
     for (i = 0; standard_class_atoms[i].init; i++) {
@@ -1958,96 +1958,110 @@ JS_ResolveStandardClass(JSContext *cx, J
     }
 
     if (!stdnm) {
         /* Try less frequently used top-level functions and constants. */
         for (i = 0; standard_class_names[i].init; i++) {
             JS_ASSERT(standard_class_names[i].clasp);
             atom = StdNameToPropertyName(cx, &standard_class_names[i]);
             if (!atom)
-                return JS_FALSE;
+                return false;
             if (idstr == atom) {
                 stdnm = &standard_class_names[i];
                 break;
             }
         }
 
         if (!stdnm && !obj->getProto()) {
             /*
              * Try even less frequently used names delegated from the global
              * object to Object.prototype, but only if the Object class hasn't
              * yet been initialized.
              */
             for (i = 0; object_prototype_names[i].init; i++) {
                 JS_ASSERT(object_prototype_names[i].clasp);
                 atom = StdNameToPropertyName(cx, &object_prototype_names[i]);
                 if (!atom)
-                    return JS_FALSE;
+                    return false;
                 if (idstr == atom) {
                     stdnm = &object_prototype_names[i];
                     break;
                 }
             }
         }
     }
 
     if (stdnm) {
         /*
          * If this standard class is anonymous, then we don't want to resolve
          * by name.
          */
         JS_ASSERT(obj->isGlobal());
         if (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS)
-            return JS_TRUE;
+            return true;
 
         if (IsStandardClassResolved(obj, stdnm->clasp))
-            return JS_TRUE;
+            return true;
+
+#if JS_HAS_XML_SUPPORT
+        if ((stdnm->init == js_InitXMLClass ||
+             stdnm->init == js_InitNamespaceClass ||
+             stdnm->init == js_InitQNameClass) &&
+            !VersionHasAllowXML(cx->findVersion()))
+        {
+            return true;
+        }
+#endif
 
         if (!stdnm->init(cx, obj))
-            return JS_FALSE;
-        *resolved = JS_TRUE;
+            return false;
+        *resolved = true;
     }
-    return JS_TRUE;
+    return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj_)
 {
-    JSRuntime *rt;
-    unsigned i;
-
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj_);
-    rt = cx->runtime;
 
     RootedObject obj(cx, obj_);
 
     /*
      * Check whether we need to bind 'undefined' and define it if so.
      * Since ES5 15.1.1.3 undefined can't be deleted.
      */
-    PropertyName *name = rt->atomState.typeAtoms[JSTYPE_VOID];
+    PropertyName *name = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
     if (!obj->nativeContains(cx, NameToId(name)) &&
         !obj->defineProperty(cx, name, UndefinedValue(),
                              JS_PropertyStub, JS_StrictPropertyStub,
                              JSPROP_PERMANENT | JSPROP_READONLY)) {
-        return JS_FALSE;
+        return false;
     }
 
     /* Initialize any classes that have not been initialized yet. */
-    for (i = 0; standard_class_atoms[i].init; i++) {
-        if (!js::IsStandardClassResolved(obj, standard_class_atoms[i].clasp) &&
-            !standard_class_atoms[i].init(cx, obj))
+    for (unsigned i = 0; standard_class_atoms[i].init; i++) {
+        const JSStdName &stdnm = standard_class_atoms[i];
+        if (!js::IsStandardClassResolved(obj, stdnm.clasp) &&
+#if JS_HAS_XML_SUPPORT
+            ((stdnm.init != js_InitXMLClass &&
+              stdnm.init != js_InitNamespaceClass &&
+              stdnm.init != js_InitQNameClass) ||
+             VersionHasAllowXML(cx->findVersion()))
+#endif
+            )
         {
-                return JS_FALSE;
+            if (!stdnm.init(cx, obj))
+                return false;
         }
     }
 
-    return JS_TRUE;
+    return true;
 }
 
 static JSIdArray *
 NewIdArray(JSContext *cx, int length)
 {
     JSIdArray *ida;
 
     ida = (JSIdArray *)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2725,17 +2725,20 @@ JS_StringToVersion(const char *string);
                                                    promises to execute compiled
                                                    script once only; enables
                                                    compile-time scope chain
                                                    resolution of consts. */
 #define JSOPTION_ATLINE         JS_BIT(5)       /* //@line number ["filename"]
                                                    option supported for the
                                                    XUL preprocessor and kindred
                                                    beasts. */
-#define JSOPTION_ALLOW_XML      JS_BIT(6)       /* enable E4X syntax (deprecated) */
+#define JSOPTION_ALLOW_XML      JS_BIT(6)       /* enable E4X syntax (deprecated)
+                                                   and define the E4X-related
+                                                   globals: XML, XMLList,
+                                                   Namespace, etc. */
 #define JSOPTION_MOAR_XML       JS_BIT(7)       /* enable E4X even in versions
                                                    that don't normally get it;
                                                    parse <!-- --> as a token,
                                                    not backward compatible with
                                                    the comment-hiding hack used
                                                    in HTML script tags. */
 #define JSOPTION_DONT_REPORT_UNCAUGHT                                   \
                                 JS_BIT(8)       /* When returning from the
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -277,17 +277,17 @@ GlobalObject::initStandardClasses(JSCont
            js_InitExceptionClasses(cx, global) &&
            js_InitMathClass(cx, global) &&
            js_InitNumberClass(cx, global) &&
            js_InitJSONClass(cx, global) &&
            js_InitRegExpClass(cx, global) &&
            js_InitStringClass(cx, global) &&
            js_InitTypedArrayClasses(cx, global) &&
 #if JS_HAS_XML_SUPPORT
-           js_InitXMLClasses(cx, global) &&
+           (!VersionHasAllowXML(cx->findVersion()) || js_InitXMLClasses(cx, global)) &&
 #endif
 #if JS_HAS_GENERATORS
            js_InitIteratorClasses(cx, global) &&
 #endif
            js_InitDateClass(cx, global) &&
            js_InitWeakMapClass(cx, global) &&
            js_InitProxyClass(cx, global) &&
            js_InitMapClass(cx, global) &&