Bug 1015791 - Retrieve the constructor for the slot, rather than looking up |proto.constructor|, for JSFUN_GENERIC_NATIVE functions. r=luke
authorBobby Holley <bobbyholley@gmail.com>
Mon, 02 Jun 2014 08:38:43 -0700
changeset 205395 54fdf394e808ed2da16823b8f3887969f1bd040c
parent 205394 1c9fed1fd66cc6d6c47d21f08a269a7fc724e04e
child 205396 4b633a2d780310493ab08aff1a2e3020131cce2a
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1015791
milestone32.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 1015791 - Retrieve the constructor for the slot, rather than looking up |proto.constructor|, for JSFUN_GENERIC_NATIVE functions. r=luke Note that the Array and TypedArray changes here are very ephemeral, because we're about to convert these things to ClassSpec (which does this right automatically) in the upcoming patches.
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsstr.cpp
js/src/vm/TypedArrayObject.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4200,18 +4200,16 @@ js_generic_native_method_dispatcher(JSCo
 JS_PUBLIC_API(bool)
 JS_DefineFunctions(JSContext *cx, HandleObject obj, const JSFunctionSpec *fs)
 {
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
 
-    RootedObject ctor(cx);
-
     for (; fs->name; fs++) {
         RootedAtom atom(cx);
         // If the name starts with "@@", it must be a well-known symbol.
         if (fs->name[0] != '@' || fs->name[1] != '@')
             atom = Atomize(cx, fs->name, strlen(fs->name));
         else if (strcmp(fs->name, "@@iterator") == 0)
             // FIXME: This atom should be a symbol: bug 918828.
             atom = cx->names().std_iterator;
@@ -4223,21 +4221,22 @@ JS_DefineFunctions(JSContext *cx, Handle
         Rooted<jsid> id(cx, AtomToId(atom));
 
         /*
          * Define a generic arity N+1 static method for the arity N prototype
          * method if flags contains JSFUN_GENERIC_NATIVE.
          */
         unsigned flags = fs->flags;
         if (flags & JSFUN_GENERIC_NATIVE) {
-            if (!ctor) {
-                ctor = JS_GetConstructor(cx, obj);
-                if (!ctor)
-                    return false;
-            }
+            // We require that any consumers using JSFUN_GENERIC_NATIVE stash
+            // the prototype and constructor in the global slots before invoking
+            // JS_DefineFunctions on the proto.
+            JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
+            JS_ASSERT(obj == &obj->global().getPrototype(key).toObject());
+            RootedObject ctor(cx, &obj->global().getConstructor(key).toObject());
 
             flags &= ~JSFUN_GENERIC_NATIVE;
             JSFunction *fun = DefineFunction(cx, ctor, id,
                                              js_generic_native_method_dispatcher,
                                              fs->nargs + 1, flags,
                                              JSFunction::ExtendedFinalizeKind);
             if (!fun)
                 return false;
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3099,16 +3099,19 @@ js_InitArrayClass(JSContext *cx, HandleO
     if (!arrayProto || !JSObject::setSingletonType(cx, arrayProto) || !AddLengthProperty(cx, arrayProto))
         return nullptr;
 
     RootedFunction ctor(cx);
     ctor = global->createConstructor(cx, js_Array, cx->names().Array, 1);
     if (!ctor)
         return nullptr;
 
+    if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_Array, ctor, arrayProto))
+        return nullptr;
+
     /*
      * The default 'new' type of Array.prototype is required by type inference
      * to have unknown properties, to simplify handling of e.g. heterogenous
      * arrays in JSON and script literals and allows setDenseArrayElement to
      * be used without updating the indexed type set for such default arrays.
      */
     if (!JSObject::setNewTypeUnknown(cx, &ArrayObject::class_, arrayProto))
         return nullptr;
@@ -3117,19 +3120,16 @@ js_InitArrayClass(JSContext *cx, HandleO
         return nullptr;
 
     if (!DefinePropertiesAndBrand(cx, arrayProto, nullptr, array_methods) ||
         !DefinePropertiesAndBrand(cx, ctor, nullptr, array_static_methods))
     {
         return nullptr;
     }
 
-    if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_Array, ctor, arrayProto))
-        return nullptr;
-
     return arrayProto;
 }
 
 /*
  * Array allocation functions.
  */
 
 static inline bool
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -3939,28 +3939,28 @@ js_InitStringClass(JSContext *cx, Handle
         return nullptr;
 
     /* Now create the String function. */
     RootedFunction ctor(cx);
     ctor = global->createConstructor(cx, js_String, cx->names().String, 1);
     if (!ctor)
         return nullptr;
 
+    if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_String, ctor, proto))
+        return nullptr;
+
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return nullptr;
 
     if (!DefinePropertiesAndBrand(cx, proto, nullptr, string_methods) ||
         !DefinePropertiesAndBrand(cx, ctor, nullptr, string_static_methods))
     {
         return nullptr;
     }
 
-    if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_String, ctor, proto))
-        return nullptr;
-
     /*
      * Define escape/unescape, the URI encode/decode functions, and maybe
      * uneval on the global object.
      */
     if (!JS_DefineFunctions(cx, global, string_functions))
         return nullptr;
 
     return proto;
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -2182,16 +2182,19 @@ InitTypedArrayClass(JSContext *cx)
         return false;
 
     RootedFunction ctor(cx);
     ctor = global->createConstructor(cx, ArrayType::class_constructor,
                                      ClassName(ArrayType::key, cx), 3);
     if (!ctor)
         return false;
 
+    if (!GlobalObject::initBuiltinConstructor(cx, global, ArrayType::key, ctor, proto))
+        return false;
+
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return false;
 
     RootedValue bytesValue(cx, Int32Value(ArrayType::BYTES_PER_ELEMENT));
 
     if (!JSObject::defineProperty(cx, ctor,
                                   cx->names().BYTES_PER_ELEMENT, bytesValue,
                                   JS_PropertyStub, JS_StrictPropertyStub,
@@ -2213,19 +2216,16 @@ InitTypedArrayClass(JSContext *cx)
     RootedFunction fun(cx);
     fun =
         NewFunction(cx, NullPtr(),
                     ArrayBufferObject::createTypedArrayFromBuffer<typename ArrayType::ThisType>,
                     0, JSFunction::NATIVE_FUN, global, NullPtr());
     if (!fun)
         return false;
 
-    if (!GlobalObject::initBuiltinConstructor(cx, global, ArrayType::key, ctor, proto))
-        return false;
-
     global->setCreateArrayFromBuffer<typename ArrayType::ThisType>(fun);
 
     return true;
 }
 
 IMPL_TYPED_ARRAY_STATICS(Int8Array);
 IMPL_TYPED_ARRAY_STATICS(Uint8Array);
 IMPL_TYPED_ARRAY_STATICS(Int16Array);
@@ -2288,16 +2288,22 @@ InitArrayBufferClass(JSContext *cx)
     if (!arrayBufferProto)
         return nullptr;
 
     RootedFunction ctor(cx, global->createConstructor(cx, ArrayBufferObject::class_constructor,
                                                       cx->names().ArrayBuffer, 1));
     if (!ctor)
         return nullptr;
 
+    if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_ArrayBuffer,
+                                              ctor, arrayBufferProto))
+    {
+        return nullptr;
+    }
+
     if (!LinkConstructorAndPrototype(cx, ctor, arrayBufferProto))
         return nullptr;
 
     RootedId byteLengthId(cx, NameToId(cx->names().byteLength));
     unsigned attrs = JSPROP_SHARED | JSPROP_GETTER | JSPROP_PERMANENT;
     JSObject *getter = NewFunction(cx, NullPtr(), ArrayBufferObject::byteLengthGetter, 0,
                                    JSFunction::NATIVE_FUN, global, NullPtr());
     if (!getter)
@@ -2308,22 +2314,16 @@ InitArrayBufferClass(JSContext *cx)
         return nullptr;
 
     if (!JS_DefineFunctions(cx, ctor, ArrayBufferObject::jsstaticfuncs))
         return nullptr;
 
     if (!JS_DefineFunctions(cx, arrayBufferProto, ArrayBufferObject::jsfuncs))
         return nullptr;
 
-    if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_ArrayBuffer,
-                                              ctor, arrayBufferProto))
-    {
-        return nullptr;
-    }
-
     return arrayBufferProto;
 }
 
 const Class DataViewObject::protoClass = {
     "DataViewPrototype",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(DataViewObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),