Bug 1393089 - Part 2: Avoid "prototype" lookup for ArrayBuffer when copying typed arrays. r=jandem
authorAndré Bargull <andre.bargull@gmail.com>
Fri, 25 Aug 2017 17:00:39 +0200
changeset 663385 0ac55815c6bc3403b942b7adf4c5ef6b9e76a634
parent 663384 daaddc22f93fc7d435c8816626790587f4c59ae4
child 663386 d5a9cdfcffa6953ee0d7827a569ab95f6be18475
push id79424
push userbmo:tchiovoloni@mozilla.com
push dateTue, 12 Sep 2017 23:17:54 +0000
reviewersjandem
bugs1393089
milestone57.0a1
Bug 1393089 - Part 2: Avoid "prototype" lookup for ArrayBuffer when copying typed arrays. r=jandem
js/src/vm/GlobalObject.h
js/src/vm/TypedArrayObject.cpp
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -360,16 +360,23 @@ class GlobalObject : public NativeObject
 
     static NativeObject*
     getOrCreateSavedFramePrototype(JSContext* cx, Handle<GlobalObject*> global) {
         if (!ensureConstructor(cx, global, JSProto_SavedFrame))
             return nullptr;
         return &global->getPrototype(JSProto_SavedFrame).toObject().as<NativeObject>();
     }
 
+    static JSFunction*
+    getOrCreateArrayBufferConstructor(JSContext* cx, Handle<GlobalObject*> global) {
+        if (!ensureConstructor(cx, global, JSProto_ArrayBuffer))
+            return nullptr;
+        return &global->getConstructor(JSProto_ArrayBuffer).toObject().as<JSFunction>();
+    }
+
     static JSObject*
     getOrCreateArrayBufferPrototype(JSContext* cx, Handle<GlobalObject*> global) {
         if (!ensureConstructor(cx, global, JSProto_ArrayBuffer))
             return nullptr;
         return &global->getPrototype(JSProto_ArrayBuffer).toObject();
     }
 
     static JSObject*
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -1033,55 +1033,67 @@ js::TypedArrayCreateWithTemplate(JSConte
         return TypedArrayObjectTemplate<T>::makeTypedArrayWithTemplate(cx, tobj, len);
 JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPED_ARRAY)
 #undef CREATE_TYPED_ARRAY
       default:
         MOZ_CRASH("Unsupported TypedArray type");
     }
 }
 
-// ES 2016 draft Mar 25, 2016 24.1.1.1.
+// ES2018 draft rev 2aea8f3e617b49df06414eb062ab44fad87661d3
+// 24.1.1.1 AllocateArrayBuffer ( constructor, byteLength )
 // byteLength = count * unit
 template<typename T>
 /* static */ bool
 TypedArrayObjectTemplate<T>::AllocateArrayBuffer(JSContext* cx, HandleObject ctor,
                                                  uint32_t count, uint32_t unit,
                                                  MutableHandle<ArrayBufferObject*> buffer)
 {
-    // ES 2016 draft Mar 25, 2016 24.1.1.1 step 1 (partially).
-    // ES 2016 draft Mar 25, 2016 9.1.14 steps 1-2.
+    // 24.1.1.1 step 1 (partially).
     RootedObject proto(cx);
-    if (!GetPrototypeFromConstructor(cx, ctor, &proto))
+
+    JSFunction* arrayBufferCtor = GlobalObject::getOrCreateArrayBufferConstructor(cx, cx->global());
+    if (!arrayBufferCtor)
         return false;
-    JSObject* arrayBufferProto = GlobalObject::getOrCreateArrayBufferPrototype(cx, cx->global());
-    if (!arrayBufferProto)
-        return false;
-    if (proto == arrayBufferProto)
-        proto = nullptr;
+
+    // As an optimization, skip the "prototype" lookup for %ArrayBuffer%.
+    if (ctor != arrayBufferCtor) {
+        // 9.1.13 OrdinaryCreateFromConstructor, steps 1-2.
+        if (!GetPrototypeFromConstructor(cx, ctor, &proto))
+            return false;
 
-    // ES 2016 draft Mar 25, 2016 24.1.1.1 steps 1 (remaining part), 2-6.
+        JSObject* arrayBufferProto = GlobalObject::getOrCreateArrayBufferPrototype(cx, cx->global());
+        if (!arrayBufferProto)
+            return false;
+
+        // Reset |proto| if it's the default %ArrayBufferPrototype%.
+        if (proto == arrayBufferProto)
+            proto = nullptr;
+    }
+
+    // 24.1.1.1 steps 1 (remaining part), 2-6.
     if (!maybeCreateArrayBuffer(cx, count, unit, proto, buffer))
         return false;
 
     return true;
 }
 
 static bool
 IsArrayBufferSpecies(JSContext* cx, JSFunction* species)
 {
     return IsSelfHostedFunctionWithName(species, cx->names().ArrayBufferSpecies);
 }
 
 static JSObject*
 GetSpeciesConstructor(JSContext* cx, HandleObject obj, bool isWrapped,
                       SpeciesConstructorOverride override)
 {
-    if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_ArrayBuffer))
+    RootedObject defaultCtor(cx, GlobalObject::getOrCreateArrayBufferConstructor(cx, cx->global()));
+    if (!defaultCtor)
         return nullptr;
-    RootedObject defaultCtor(cx, &cx->global()->getConstructor(JSProto_ArrayBuffer).toObject());
 
     // Use the current global's ArrayBuffer if the override is set.
     if (override == SpeciesConstructorOverride::ArrayBuffer)
         return defaultCtor;
 
     RootedObject wrappedObj(cx, obj);
     if (isWrapped && !cx->compartment()->wrap(cx, &wrappedObj))
         return nullptr;