Bug 975589, part 2 - Avoid recursing in TypedArray initialization. r=jwalden.
authorJason Orendorff <jorendorff@mozilla.com>
Mon, 10 Mar 2014 16:29:58 -0500
changeset 190048 a4be3456ea82fdac258cd53c00a89a09b7232745
parent 190047 6635d1edc7497a5fa346d0921013d0fde248c0bb
child 190049 bb4060b72c3882c43b3a2e779c625a7935863eda
push id3503
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:51:11 +0000
treeherdermozilla-beta@c95ac01e332e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs975589
milestone30.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 975589, part 2 - Avoid recursing in TypedArray initialization. r=jwalden.
js/src/jsobj.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/TypedArrayObject.cpp
js/src/vm/TypedArrayObject.h
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3239,18 +3239,18 @@ MaybeResolveConstructor(ExclusiveContext
         return true;
     if (!cxArg->shouldBeJSContext())
         return false;
 
     JSContext *cx = cxArg->asJSContext();
     RootedId name(cx, NameToId(ClassName(key, cx)));
     AutoResolving resolving(cx, global, name);
     if (resolving.alreadyStarted())
-       return true;
-    return GlobalObject::ensureConstructor(cx, global, key);
+        return true;
+    return GlobalObject::resolveConstructor(cx, global, key);
 }
 
 bool
 js_GetClassObject(ExclusiveContext *cx, JSProtoKey key, MutableHandleObject objp)
 {
     MOZ_ASSERT(key != JSProto_Null);
     Rooted<GlobalObject*> global(cx, cx->global());
     if (!MaybeResolveConstructor(cx, global, key))
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -441,25 +441,25 @@ GlobalObject::initFunctionAndObjectClass
     RootedScript functionProtoScript(cx, functionProto->nonLazyScript());
     CallNewScriptHook(cx, functionProtoScript, functionProto);
     return functionProto;
 }
 
 /* static */ bool
 GlobalObject::ensureConstructor(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey key)
 {
-    if (global->getConstructor(key).isObject())
+    if (global->isStandardClassResolved(key))
         return true;
     return resolveConstructor(cx, global, key);
 }
 
 /* static*/ bool
 GlobalObject::resolveConstructor(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey key)
 {
-    MOZ_ASSERT(global->getConstructor(key).isUndefined());
+    MOZ_ASSERT(!global->isStandardClassResolved(key));
 
     // There are two different kinds of initialization hooks. One of them is
     // the class js_InitFoo hook, defined in a JSProtoKey-keyed table at the
     // top of this file. The other lives in the ClassSpec for classes that
     // define it. Classes may use one or the other, but not both.
     ClassInitializerOp init = protoTable[key].init;
     if (init == js_InitViaClassSpec)
         init = nullptr;
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -2135,67 +2135,70 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Flo
     nullptr,                 /* finalize */                                    \
     nullptr,                 /* call        */                                 \
     nullptr,                 /* hasInstance */                                 \
     nullptr,                 /* construct   */                                 \
     ArrayBufferViewObject::trace, /* trace  */                                 \
 }
 
 template<class ArrayType>
-static inline JSObject *
+static inline bool
 InitTypedArrayClass(JSContext *cx)
 {
     Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
+    if (global->isStandardClassResolved(ArrayType::key))
+        return true;
+
     RootedObject proto(cx, global->createBlankPrototype(cx, ArrayType::protoClass()));
     if (!proto)
-        return nullptr;
+        return false;
 
     RootedFunction ctor(cx);
     ctor = global->createConstructor(cx, ArrayType::class_constructor,
                                      ClassName(ArrayType::key, cx), 3);
     if (!ctor)
-        return nullptr;
+        return false;
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
-        return nullptr;
+        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,
                                   JSPROP_PERMANENT | JSPROP_READONLY) ||
         !JSObject::defineProperty(cx, proto,
                                   cx->names().BYTES_PER_ELEMENT, bytesValue,
                                   JS_PropertyStub, JS_StrictPropertyStub,
                                   JSPROP_PERMANENT | JSPROP_READONLY))
     {
-        return nullptr;
+        return false;
     }
 
     if (!ArrayType::defineGetters(cx, proto))
-        return nullptr;
+        return false;
 
     if (!JS_DefineFunctions(cx, proto, ArrayType::jsfuncs))
-        return nullptr;
+        return false;
 
     RootedFunction fun(cx);
     fun =
         NewFunction(cx, NullPtr(),
                     ArrayBufferObject::createTypedArrayFromBuffer<typename ArrayType::ThisType>,
                     0, JSFunction::NATIVE_FUN, global, NullPtr());
     if (!fun)
-        return nullptr;
+        return false;
 
     if (!GlobalObject::initBuiltinConstructor(cx, global, ArrayType::key, ctor, proto))
-        return nullptr;
+        return false;
 
     global->setCreateArrayFromBuffer<typename ArrayType::ThisType>(fun);
 
-    return proto;
+    return true;
 }
 
 IMPL_TYPED_ARRAY_STATICS(Int8Array);
 IMPL_TYPED_ARRAY_STATICS(Uint8Array);
 IMPL_TYPED_ARRAY_STATICS(Int16Array);
 IMPL_TYPED_ARRAY_STATICS(Uint16Array);
 IMPL_TYPED_ARRAY_STATICS(Int32Array);
 IMPL_TYPED_ARRAY_STATICS(Uint32Array);
@@ -2243,16 +2246,19 @@ js::IsTypedArrayThisCheck(JS::IsAcceptab
     return false;
 }
 #undef CHECK
 
 static JSObject *
 InitArrayBufferClass(JSContext *cx)
 {
     Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
+    if (global->isStandardClassResolved(JSProto_ArrayBuffer))
+        return &global->getPrototype(JSProto_ArrayBuffer).toObject();
+
     RootedObject arrayBufferProto(cx, global->createBlankPrototype(cx, &ArrayBufferObject::protoClass));
     if (!arrayBufferProto)
         return nullptr;
 
     RootedFunction ctor(cx, global->createConstructor(cx, ArrayBufferObject::class_constructor,
                                                       cx->names().ArrayBuffer, 1));
     if (!ctor)
         return nullptr;
@@ -2369,84 +2375,76 @@ DataViewObject::defineGetter(JSContext *
     if (!getter)
         return false;
 
     return DefineNativeProperty(cx, proto, id, UndefinedHandleValue,
                                 JS_DATA_TO_FUNC_PTR(PropertyOp, getter), nullptr,
                                 flags, 0, 0);
 }
 
-/* static */ JSObject *
+/* static */ bool
 DataViewObject::initClass(JSContext *cx)
 {
     Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
+    if (global->isStandardClassResolved(JSProto_DataView))
+        return true;
+
     RootedObject proto(cx, global->createBlankPrototype(cx, &DataViewObject::protoClass));
     if (!proto)
-        return nullptr;
+        return false;
 
     RootedFunction ctor(cx, global->createConstructor(cx, DataViewObject::class_constructor,
                                                       cx->names().DataView, 3));
     if (!ctor)
-        return nullptr;
+        return false;
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
-        return nullptr;
+        return false;
 
     if (!defineGetter<bufferValue>(cx, cx->names().buffer, proto))
-        return nullptr;
+        return false;
 
     if (!defineGetter<byteLengthValue>(cx, cx->names().byteLength, proto))
-        return nullptr;
+        return false;
 
     if (!defineGetter<byteOffsetValue>(cx, cx->names().byteOffset, proto))
-        return nullptr;
+        return false;
 
     if (!JS_DefineFunctions(cx, proto, DataViewObject::jsfuncs))
-        return nullptr;
+        return false;
 
     /*
      * Create a helper function to implement the craziness of
      * |new DataView(new otherWindow.ArrayBuffer())|, and install it in the
      * global for use by the DataViewObject constructor.
      */
     RootedFunction fun(cx, NewFunction(cx, NullPtr(), ArrayBufferObject::createDataViewForThis,
                                        0, JSFunction::NATIVE_FUN, global, NullPtr()));
     if (!fun)
-        return nullptr;
+        return false;
 
     if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_DataView, ctor, proto))
-        return nullptr;
+        return false;
 
     global->setCreateDataViewForThis(fun);
 
-    return proto;
+    return true;
 }
 
 void
 DataViewObject::neuter()
 {
     setSlot(BYTELENGTH_SLOT, Int32Value(0));
     setSlot(BYTEOFFSET_SLOT, Int32Value(0));
     setPrivate(nullptr);
 }
 
 JSObject *
 js_InitTypedArrayClasses(JSContext *cx, HandleObject obj)
 {
-    JS_ASSERT(obj->isNative());
-    assertSameCompartment(cx, obj);
-    Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
-
-    /* Idempotency required: we initialize several things, possibly lazily. */
-    RootedObject stop(cx);
-    if (!js_GetClassObject(cx, JSProto_ArrayBuffer, &stop))
-        return nullptr;
-    if (stop)
-        return stop;
-
     if (!InitTypedArrayClass<Int8ArrayObject>(cx) ||
         !InitTypedArrayClass<Uint8ArrayObject>(cx) ||
         !InitTypedArrayClass<Int16ArrayObject>(cx) ||
         !InitTypedArrayClass<Uint16ArrayObject>(cx) ||
         !InitTypedArrayClass<Int32ArrayObject>(cx) ||
         !InitTypedArrayClass<Uint32ArrayObject>(cx) ||
         !InitTypedArrayClass<Float32ArrayObject>(cx) ||
         !InitTypedArrayClass<Float64ArrayObject>(cx) ||
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -305,17 +305,17 @@ class DataViewObject : public ArrayBuffe
     static bool fun_setUint32(JSContext *cx, unsigned argc, Value *vp);
 
     static bool setFloat32Impl(JSContext *cx, CallArgs args);
     static bool fun_setFloat32(JSContext *cx, unsigned argc, Value *vp);
 
     static bool setFloat64Impl(JSContext *cx, CallArgs args);
     static bool fun_setFloat64(JSContext *cx, unsigned argc, Value *vp);
 
-    static JSObject *initClass(JSContext *cx);
+    static bool initClass(JSContext *cx);
     static void neuter(JSObject *view);
     static bool getDataPointer(JSContext *cx, Handle<DataViewObject*> obj,
                                CallArgs args, size_t typeSize, uint8_t **data);
     template<typename NativeType>
     static bool read(JSContext *cx, Handle<DataViewObject*> obj,
                      CallArgs &args, NativeType *val, const char *method);
     template<typename NativeType>
     static bool write(JSContext *cx, Handle<DataViewObject*> obj,