Bug 1268034 - Part 1: Reset constructor slot of GlobalObject to undefined when it fails to initialize constructor. r=till
authorTooru Fujisawa <arai_a@mac.com>
Fri, 29 Apr 2016 18:24:20 +0900
changeset 295430 d31171af48e4fe4e0e35e6e96b4c76504a7ee091
parent 295429 2fd4339f19c1a4687ebc45acaf6e0e46536d6e0e
child 295431 05c1151be7a7821136263bb46d887bf8e99ce64d
push id30223
push userkwierso@gmail.com
push dateFri, 29 Apr 2016 21:57:49 +0000
treeherdermozilla-central@2b7c421063ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
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 1: Reset constructor slot of GlobalObject to undefined when it fails to initialize constructor. r=till
js/src/jit-test/tests/auto-regress/bug1268034.js
js/src/vm/GlobalObject.cpp
js/src/vm/GlobalObject.h
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();
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -216,19 +216,42 @@ GlobalObject::resolveConstructor(JSConte
         return false;
 
     RootedId id(cx, NameToId(ClassName(key, cx)));
     if (clasp->specShouldDefineConstructor()) {
         if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0))
             return false;
     }
 
+    // Set the constructor slot here to make it usable from JS_DefineFunctions,
+    // especially with JSProto_Function, as Function.prototype.toString is also
+    // a function.
+    // All failure cases from here should reset them to undefined, to avoid
+    // leaving partially initiallized object in the constructor slot.
     global->setConstructor(key, ObjectValue(*ctor));
     global->setConstructorPropertySlot(key, ObjectValue(*ctor));
 
+    if (!defineConstructorPropertiesAndLinkPrototype(cx, global, key, clasp, id,
+                                                     ctor, proto))
+    {
+        global->setConstructor(key, UndefinedValue());
+        global->setConstructorPropertySlot(key, UndefinedValue());
+        return false;
+    }
+
+    return true;
+}
+
+/* static */ bool
+GlobalObject::defineConstructorPropertiesAndLinkPrototype(JSContext* cx,
+                                                          Handle<GlobalObject*> global,
+                                                          JSProtoKey key, const Class* clasp,
+                                                          HandleId id, HandleObject ctor,
+                                                          HandleObject proto)
+{
     // 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;
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -236,16 +236,22 @@ class GlobalObject : public NativeObject
      * manner.
      */
     static HandleObject upcast(Handle<GlobalObject*> global) {
         return HandleObject::fromMarkedLocation(
                 reinterpret_cast<JSObject * const*>(global.address()));
     }
 
   private:
+    static bool defineConstructorPropertiesAndLinkPrototype(JSContext* cx,
+                                                            Handle<GlobalObject*> global,
+                                                            JSProtoKey key, const Class* clasp,
+                                                            HandleId id, HandleObject ctor,
+                                                            HandleObject proto);
+
     bool arrayClassInitialized() const {
         return classIsInitialized(JSProto_Array);
     }
 
     bool booleanClassInitialized() const {
         return classIsInitialized(JSProto_Boolean);
     }
     bool numberClassInitialized() const {