Bug 1055472 - Part 13: Make the ArrayBuffer constructor properly subclassable. (r=Waldo)
authorEric Faust <efaustbmo@gmail.com>
Fri, 13 Nov 2015 18:22:22 -0800
changeset 309842 dfa71e4ddef2fbda2e09657fa3d0782bbf69e418
parent 309841 579411961394179050dd1678e8a4f8d08dfc94f7
child 309843 1e0c29a6d05886f9001513753aa0875654c13393
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1055472
milestone45.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 1055472 - Part 13: Make the ArrayBuffer constructor properly subclassable. (r=Waldo)
js/src/jsobjinlines.h
js/src/tests/ecma_6/Class/extendBuiltinConstructors.js
js/src/vm/ArrayBufferObject.cpp
js/src/vm/ArrayBufferObject.h
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -691,16 +691,25 @@ template<class T>
 inline T*
 NewObjectWithClassProto(ExclusiveContext* cx, HandleObject proto,
                         NewObjectKind newKind = GenericObject)
 {
     JSObject* obj = NewObjectWithClassProto(cx, &T::class_, proto, newKind);
     return obj ? &obj->as<T>() : nullptr;
 }
 
+template <class T>
+inline T*
+NewObjectWithClassProto(ExclusiveContext* cx, HandleObject proto, gc::AllocKind allocKind,
+                        NewObjectKind newKind = GenericObject)
+{
+    JSObject* obj = NewObjectWithClassProto(cx, &T::class_, proto, allocKind, newKind);
+    return obj ? &obj->as<T>() : nullptr;
+}
+
 /*
  * Create a native instance of the given class with parent and proto set
  * according to the context's active global.
  */
 inline JSObject*
 NewBuiltinClassInstance(ExclusiveContext* cx, const Class* clasp, gc::AllocKind allocKind,
                         NewObjectKind newKind = GenericObject)
 {
--- a/js/src/tests/ecma_6/Class/extendBuiltinConstructors.js
+++ b/js/src/tests/ecma_6/Class/extendBuiltinConstructors.js
@@ -31,16 +31,17 @@ testBuiltin(Date, 5);
 testBuiltin(Date, 5, 10);
 testBuiltin(RegExp);
 testBuiltin(RegExp, /Regexp Argument/);
 testBuiltin(RegExp, "String Argument");
 testBuiltin(Map);
 testBuiltin(Set);
 testBuiltin(WeakMap);
 testBuiltin(WeakSet);
+testBuiltin(ArrayBuffer);
 
 `;
 
 if (classesEnabled())
     eval(test);
 
 if (typeof reportCompare === 'function')
     reportCompare(0,0,"OK");
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -471,17 +471,22 @@ ArrayBufferObject::class_constructor(JSC
          * We're just not going to support arrays that are bigger than what will fit
          * as an integer value; if someone actually ever complains (validly), then we
          * can fix.
          */
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
         return false;
     }
 
-    JSObject* bufobj = create(cx, uint32_t(nbytes));
+    RootedObject proto(cx);
+    RootedObject newTarget(cx, &args.newTarget().toObject());
+    if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
+        return false;
+
+    JSObject* bufobj = create(cx, uint32_t(nbytes), proto);
     if (!bufobj)
         return false;
     args.rval().setObject(*bufobj);
     return true;
 }
 
 static ArrayBufferObject::BufferContents
 AllocateArrayBufferContents(JSContext* cx, uint32_t nbytes)
@@ -788,16 +793,17 @@ void
 ArrayBufferObject::setFlags(uint32_t flags)
 {
     setSlot(FLAGS_SLOT, Int32Value(flags));
 }
 
 ArrayBufferObject*
 ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents contents,
                           OwnsState ownsState /* = OwnsData */,
+                          HandleObject proto /* = nullptr */,
                           NewObjectKind newKind /* = GenericObject */)
 {
     MOZ_ASSERT_IF(contents.kind() == MAPPED, contents);
 
     // If we need to allocate data, try to use a larger object size class so
     // that the array buffer's data can be allocated inline with the object.
     // The extra space will be left unused by the object's fixed slots and
     // available for the buffer's data, see NewObject().
@@ -828,17 +834,18 @@ ArrayBufferObject::create(JSContext* cx,
             allocated = true;
         }
     }
 
     MOZ_ASSERT(!(class_.flags & JSCLASS_HAS_PRIVATE));
     gc::AllocKind allocKind = GetGCObjectKind(nslots);
 
     AutoSetNewObjectMetadata metadata(cx);
-    Rooted<ArrayBufferObject*> obj(cx, NewBuiltinClassInstance<ArrayBufferObject>(cx, allocKind, newKind));
+    Rooted<ArrayBufferObject*> obj(cx,
+        NewObjectWithClassProto<ArrayBufferObject>(cx, proto, allocKind, newKind));
     if (!obj) {
         if (allocated)
             js_free(contents.data());
         return nullptr;
     }
 
     MOZ_ASSERT(obj->getClass() == &class_);
     MOZ_ASSERT(!gc::IsInsideNursery(obj));
@@ -851,19 +858,21 @@ ArrayBufferObject::create(JSContext* cx,
         obj->initialize(nbytes, contents, ownsState);
     }
 
     return obj;
 }
 
 ArrayBufferObject*
 ArrayBufferObject::create(JSContext* cx, uint32_t nbytes,
+                          HandleObject proto /* = nullptr */,
                           NewObjectKind newKind /* = GenericObject */)
 {
-    return create(cx, nbytes, BufferContents::createPlain(nullptr));
+    return create(cx, nbytes, BufferContents::createPlain(nullptr),
+                  OwnsState::OwnsData, proto);
 }
 
 JSObject*
 ArrayBufferObject::createSlice(JSContext* cx, Handle<ArrayBufferObject*> arrayBuffer,
                                uint32_t begin, uint32_t end)
 {
     uint32_t bufLength = arrayBuffer->byteLength();
     if (begin > bufLength || end > bufLength || begin > end) {
@@ -1399,17 +1408,18 @@ JS_NewArrayBuffer(JSContext* cx, uint32_
 }
 
 JS_PUBLIC_API(JSObject*)
 JS_NewArrayBufferWithContents(JSContext* cx, size_t nbytes, void* data)
 {
     MOZ_ASSERT_IF(!data, nbytes == 0);
     ArrayBufferObject::BufferContents contents =
         ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(data);
-    return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData, TenuredObject);
+    return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData,
+                                     /* proto = */ nullptr, TenuredObject);
 }
 
 JS_FRIEND_API(bool)
 JS_IsArrayBufferObject(JSObject* obj)
 {
     obj = CheckedUnwrap(obj);
     return obj && obj->is<ArrayBufferObject>();
 }
@@ -1464,17 +1474,18 @@ JS_StealArrayBufferContents(JSContext* c
 }
 
 JS_PUBLIC_API(JSObject*)
 JS_NewMappedArrayBufferWithContents(JSContext* cx, size_t nbytes, void* data)
 {
     MOZ_ASSERT(data);
     ArrayBufferObject::BufferContents contents =
         ArrayBufferObject::BufferContents::create<ArrayBufferObject::MAPPED>(data);
-    return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData, TenuredObject);
+    return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData,
+                                     /* proto = */ nullptr, TenuredObject);
 }
 
 JS_PUBLIC_API(void*)
 JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length)
 {
     return ArrayBufferObject::createMappedContents(fd, offset, length).data();
 }
 
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -208,18 +208,20 @@ class ArrayBufferObject : public ArrayBu
     static bool fun_transfer(JSContext* cx, unsigned argc, Value* vp);
 #endif
 
     static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
 
     static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes,
                                      BufferContents contents,
                                      OwnsState ownsState = OwnsData,
+                                     HandleObject proto = nullptr,
                                      NewObjectKind newKind = GenericObject);
     static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes,
+                                     HandleObject proto = nullptr,
                                      NewObjectKind newKind = GenericObject);
 
     static JSObject* createSlice(JSContext* cx, Handle<ArrayBufferObject*> arrayBuffer,
                                  uint32_t begin, uint32_t end);
 
     static bool createDataViewForThisImpl(JSContext* cx, const CallArgs& args);
     static bool createDataViewForThis(JSContext* cx, unsigned argc, Value* vp);