Bug 1268034 - Part 4: Delay modifying global constructor/prototype slots for classes other than Function and Object. r=jorendorff
authorTooru Fujisawa <arai_a@mac.com>
Thu, 19 May 2016 20:47:07 +0900
changeset 298111 1e198b4ccab26156c3dd6417b2ee08d53ab622dd
parent 298110 9c2a58d84d498bd8841f3bd88e6091ebcba58818
child 298112 b8d15a27d1ecb0a533011438eb5f39599b9521ee
push id30270
push userryanvm@gmail.com
push dateThu, 19 May 2016 16:47:16 +0000
treeherdermozilla-central@1806d405c871 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1268034
milestone49.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 1268034 - Part 4: Delay modifying global constructor/prototype slots for classes other than Function and Object. r=jorendorff
js/src/jit-test/tests/auto-regress/bug1268034.js
js/src/jit-test/tests/auto-regress/bug1269074.js
js/src/vm/GlobalObject.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/auto-regress/bug1268034.js
@@ -0,0 +1,7 @@
+if (!('oomTest' in this))
+    quit();
+
+oomTest(function() {
+    offThreadCompileScript("");
+});
+"".match();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/auto-regress/bug1269074.js
@@ -0,0 +1,6 @@
+// |jit-test| allow-oom
+
+if (!('oomTest' in this))
+    quit();
+
+evalcx('oomTest(function() { Array(...""); })', newGlobal());
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -171,64 +171,70 @@ GlobalObject::resolveConstructor(JSConte
         MOZ_ASSERT(!haveSpec);
         return init(cx, global);
     }
 
     //
     // Ok, we're doing it with a class spec.
     //
 
+    bool isObjectOrFunction = key == JSProto_Function || key == JSProto_Object;
+
     // We need to create the prototype first, and immediately stash it in the
     // slot. This is so the following bootstrap ordering is possible:
     // * Object.prototype
     // * Function.prototype
     // * Function
     // * Object
     //
     // We get the above when Object is resolved before Function. If Function
     // is resolved before Object, we'll end up re-entering resolveConstructor
-    // for Function, which is a problem. So if Function is being resolved before
-    // Object.prototype exists, we just resolve Object instead, since we know that
-    // Function will also be resolved before we return.
+    // for Function, which is a problem. So if Function is being resolved
+    // before Object.prototype exists, we just resolve Object instead, since we
+    // know that Function will also be resolved before we return.
     if (key == JSProto_Function && global->getPrototype(JSProto_Object).isUndefined())
         return resolveConstructor(cx, global, JSProto_Object);
 
     // We don't always have a prototype (i.e. Math and JSON). If we don't,
     // |createPrototype|, |prototypeFunctions|, and |prototypeProperties|
     // should all be null.
     RootedObject proto(cx);
     if (ClassObjectCreationOp createPrototype = clasp->specCreatePrototypeHook()) {
         proto = createPrototype(cx, key);
         if (!proto)
             return false;
 
-        // Make sure that creating the prototype didn't recursively resolve our
-        // own constructor. We can't just assert that there's no prototype; OOMs
-        // can result in incomplete resolutions in which the prototype is saved
-        // but not the constructor. So use the same criteria that protects entry
-        // into this function.
-        MOZ_ASSERT(!global->isStandardClassResolved(key));
+        if (isObjectOrFunction) {
+            // Make sure that creating the prototype didn't recursively resolve
+            // our own constructor. We can't just assert that there's no
+            // prototype; OOMs can result in incomplete resolutions in which
+            // the prototype is saved but not the constructor. So use the same
+            // criteria that protects entry into this function.
+            MOZ_ASSERT(!global->isStandardClassResolved(key));
 
-        global->setPrototype(key, ObjectValue(*proto));
+            global->setPrototype(key, ObjectValue(*proto));
+        }
     }
 
     // Create the constructor.
     RootedObject ctor(cx, clasp->specCreateConstructorHook()(cx, key));
     if (!ctor)
         return false;
 
     RootedId id(cx, NameToId(ClassName(key, cx)));
-    if (clasp->specShouldDefineConstructor()) {
-        if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0))
-            return false;
+    if (isObjectOrFunction) {
+        if (clasp->specShouldDefineConstructor()) {
+            if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0))
+                return false;
+        }
+
+        global->setConstructor(key, ObjectValue(*ctor));
+        global->setConstructorPropertySlot(key, ObjectValue(*ctor));
     }
 
-    global->setConstructor(key, ObjectValue(*ctor));
-    global->setConstructorPropertySlot(key, ObjectValue(*ctor));
-
     // Define any specified functions and properties, unless we're a dependent
     // standard class (in which case they live on the prototype), or we're
     // operating on the self-hosting global, in which case we don't want any
     // functions and properties on the builtins and their prototypes.
     if (!StandardClassIsDependent(key) && !cx->runtime()->isSelfHostingGlobal(global)) {
         if (const JSFunctionSpec* funs = clasp->specPrototypeFunctions()) {
             if (!JS_DefineFunctions(cx, proto, funs))
                 return false;
@@ -252,16 +258,33 @@ GlobalObject::resolveConstructor(JSConte
         return false;
 
     // Call the post-initialization hook, if provided.
     if (FinishClassInitOp finishInit = clasp->specFinishInitHook()) {
         if (!finishInit(cx, ctor, proto))
             return false;
     }
 
+    if (!isObjectOrFunction) {
+        // Any operations that modifies the global object should be placed
+        // after any other fallible operations.
+
+        // Fallible operation that modifies the global object.
+        if (clasp->specShouldDefineConstructor()) {
+            if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0))
+                return false;
+        }
+
+        // Infallible operations that modify the global object.
+        global->setConstructor(key, ObjectValue(*ctor));
+        global->setConstructorPropertySlot(key, ObjectValue(*ctor));
+        if (proto)
+            global->setPrototype(key, ObjectValue(*proto));
+    }
+
     if (clasp->specShouldDefineConstructor()) {
         // Stash type information, so that what we do here is equivalent to
         // initBuiltinConstructor.
         AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
     }
 
     return true;
 }