Bug 1496378 part 1 - Make ArrayBufferViewObject a base class of TypedArrayObject and DataViewObject. r=jwalden
authorJan de Mooij <jdemooij@mozilla.com>
Mon, 15 Oct 2018 11:39:08 +0000
changeset 489623 87071cf93bcc0f411b0fb267fa5872aad6abab53
parent 489622 4d2fbdbead3a58f724be4cba4c5fa00fbb4f5207
child 489624 1f8af7db9d96ee0e9fd4f9d4949efe3921f99290
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersjwalden
bugs1496378
milestone64.0a1
Bug 1496378 part 1 - Make ArrayBufferViewObject a base class of TypedArrayObject and DataViewObject. r=jwalden Differential Revision: https://phabricator.services.mozilla.com/D7721
js/src/builtin/DataViewObject.cpp
js/src/builtin/DataViewObject.h
js/src/vm/ArrayBufferObject.cpp
js/src/vm/ArrayBufferObject.h
js/src/vm/TypedArrayObject.h
--- a/js/src/builtin/DataViewObject.cpp
+++ b/js/src/builtin/DataViewObject.cpp
@@ -66,19 +66,19 @@ DataViewObject::create(JSContext* cx, ui
     // The isSharedMemory property is invariant.  Self-hosting code that sets
     // BUFFER_SLOT or the private slot (if it does) must maintain it by always
     // setting those to reference shared memory.
     bool isSharedMemory = IsSharedArrayBuffer(arrayBuffer.get());
     if (isSharedMemory) {
         obj->setIsSharedMemory();
     }
 
-    obj->setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(byteOffset));
-    obj->setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(byteLength));
-    obj->setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectValue(*arrayBuffer));
+    obj->setFixedSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset));
+    obj->setFixedSlot(LENGTH_SLOT, Int32Value(byteLength));
+    obj->setFixedSlot(BUFFER_SLOT, ObjectValue(*arrayBuffer));
 
     SharedMem<uint8_t*> ptr = arrayBuffer->dataPointerEither();
     // A pointer to raw shared memory is exposed through the private slot.  This
     // is safe so long as getPrivate() is not used willy-nilly.  It is wrapped in
     // other accessors in TypedArrayObject.h.
     obj->initPrivate(ptr.unwrap(/*safe - see above*/) + byteOffset);
 
     // Include a barrier if the data view's data pointer is in the nursery, as
@@ -93,17 +93,17 @@ DataViewObject::create(JSContext* cx, ui
             MOZ_ASSERT(arrayBuffer->byteLength() == 0 &&
                        (uintptr_t(ptr.unwrapValue()) & gc::ChunkMask) == 0);
         } else {
             cx->runtime()->gc.storeBuffer().putWholeCell(obj);
         }
     }
 
     // Verify that the private slot is at the expected place
-    MOZ_ASSERT(obj->numFixedSlots() == TypedArrayObject::DATA_SLOT);
+    MOZ_ASSERT(obj->numFixedSlots() == DATA_SLOT);
 
     if (arrayBuffer->is<ArrayBufferObject>()) {
         if (!arrayBuffer->as<ArrayBufferObject>().addView(cx, obj)) {
             return nullptr;
         }
     }
 
     return obj;
@@ -962,17 +962,17 @@ const ClassSpec DataViewObject::classSpe
     nullptr,
     DataViewObject::methods,
     DataViewObject::properties,
 };
 
 const Class DataViewObject::class_ = {
     "DataView",
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) |
+    JSCLASS_HAS_RESERVED_SLOTS(DataViewObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
     &DataViewObjectClassOps,
     &DataViewObject::classSpec_
 };
 
 const Class DataViewObject::protoClass_ = {
     js_Object_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
@@ -1008,18 +1008,18 @@ const JSPropertySpec DataViewObject::pro
     JS_PSG("byteOffset", DataViewObject::byteOffsetGetter, 0),
     JS_STRING_SYM_PS(toStringTag, "DataView", JSPROP_READONLY),
     JS_PS_END
 };
 
 void
 DataViewObject::notifyBufferDetached(void* newData)
 {
-    setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(0));
-    setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(0));
+    setFixedSlot(LENGTH_SLOT, Int32Value(0));
+    setFixedSlot(BYTEOFFSET_SLOT, Int32Value(0));
     setPrivate(newData);
 }
 
 JS_FRIEND_API(bool)
 JS_IsDataViewObject(JSObject* obj)
 {
     obj = CheckedUnwrap(obj);
     return obj ? obj->is<DataViewObject>() : false;
--- a/js/src/builtin/DataViewObject.h
+++ b/js/src/builtin/DataViewObject.h
@@ -9,26 +9,25 @@
 
 #include "mozilla/Attributes.h"
 
 #include "gc/Barrier.h"
 #include "js/Class.h"
 #include "vm/ArrayBufferObject.h"
 #include "vm/JSObject.h"
 #include "vm/SharedArrayObject.h"
-#include "vm/TypedArrayObject.h"
 
 namespace js {
 
 // In the DataViewObject, the private slot contains a raw pointer into
 // the buffer.  The buffer may be shared memory and the raw pointer
 // should not be exposed without sharedness information accompanying
 // it.
 
-class DataViewObject : public NativeObject
+class DataViewObject : public ArrayBufferViewObject
 {
   private:
     static const ClassSpec classSpec_;
 
     static JSObject* CreatePrototype(JSContext* cx, JSProtoKey key);
 
     static bool is(HandleValue v) {
         return v.isObject() && v.toObject().hasClass(&class_);
@@ -57,29 +56,29 @@ class DataViewObject : public NativeObje
     create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
            Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, HandleObject proto);
 
   public:
     static const Class class_;
     static const Class protoClass_;
 
     static Value byteOffsetValue(const DataViewObject* view) {
-        Value v = view->getFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT);
+        Value v = view->getFixedSlot(BYTEOFFSET_SLOT);
         MOZ_ASSERT(v.toInt32() >= 0);
         return v;
     }
 
     static Value byteLengthValue(const DataViewObject* view) {
-        Value v = view->getFixedSlot(TypedArrayObject::LENGTH_SLOT);
+        Value v = view->getFixedSlot(LENGTH_SLOT);
         MOZ_ASSERT(v.toInt32() >= 0);
         return v;
     }
 
     static Value bufferValue(const DataViewObject* view) {
-        return view->getFixedSlot(TypedArrayObject::BUFFER_SLOT);
+        return view->getFixedSlot(BUFFER_SLOT);
     }
 
     uint32_t byteOffset() const {
         return byteOffsetValue(this).toInt32();
     }
 
     uint32_t byteLength() const {
         return byteLengthValue(this).toInt32();
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -1756,44 +1756,24 @@ ArrayBufferViewObject::dataPointerUnshar
     if (is<DataViewObject>()) {
         MOZ_ASSERT(!as<DataViewObject>().isSharedMemory());
         return static_cast<uint8_t*>(as<DataViewObject>().dataPointerUnshared());
     }
     if (is<TypedArrayObject>()) {
         MOZ_ASSERT(!as<TypedArrayObject>().isSharedMemory());
         return static_cast<uint8_t*>(as<TypedArrayObject>().viewDataUnshared());
     }
-    return as<TypedObject>().typedMem(nogc);
+    MOZ_CRASH("Unknown ArrayBufferViewObject");
 }
 
-#ifdef DEBUG
-bool
-ArrayBufferViewObject::isSharedMemory()
-{
-    if (is<TypedArrayObject>()) {
-        return as<TypedArrayObject>().isSharedMemory();
-    }
-    return false;
-}
-#endif
-
 void
 ArrayBufferViewObject::setDataPointerUnshared(uint8_t* data)
 {
-    if (is<DataViewObject>()) {
-        MOZ_ASSERT(!as<DataViewObject>().isSharedMemory());
-        as<DataViewObject>().setPrivate(data);
-    } else if (is<TypedArrayObject>()) {
-        MOZ_ASSERT(!as<TypedArrayObject>().isSharedMemory());
-        as<TypedArrayObject>().setPrivate(data);
-    } else if (is<OutlineTypedObject>()) {
-        as<OutlineTypedObject>().setData(data);
-    } else {
-        MOZ_CRASH();
-    }
+    MOZ_ASSERT(!isSharedMemory());
+    setPrivate(data);
 }
 
 /* static */ ArrayBufferObjectMaybeShared*
 ArrayBufferViewObject::bufferObject(JSContext* cx, Handle<ArrayBufferViewObject*> thisObject)
 {
     if (thisObject->is<TypedArrayObject>()) {
         Rooted<TypedArrayObject*> typedArray(cx, &thisObject->as<TypedArrayObject>());
         if (!TypedArrayObject::ensureHasBuffer(cx, typedArray)) {
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -47,29 +47,30 @@ bool ExtendBufferMapping(void* dataStart
 void UnmapBufferMemory(void* dataStart, size_t mappedSize);
 
 // Return the number of currently live mapped buffers.
 int32_t LiveMappedBufferCount();
 
 // The inheritance hierarchy for the various classes relating to typed arrays
 // is as follows.
 //
-// - NativeObject
-//   - ArrayBufferObjectMaybeShared
-//     - ArrayBufferObject
-//     - SharedArrayBufferObject
-//   - DataViewObject
-//   - TypedArrayObject (declared in vm/TypedArrayObject.h)
-//     - TypedArrayObjectTemplate
-//       - Int8ArrayObject
-//       - Uint8ArrayObject
-//       - ...
+//
 // - JSObject
-//   - ArrayBufferViewObject
 //   - TypedObject (declared in builtin/TypedObject.h)
+//   - NativeObject
+//     - ArrayBufferObjectMaybeShared
+//       - ArrayBufferObject
+//       - SharedArrayBufferObject
+//     - ArrayBufferViewObject
+//       - DataViewObject
+//       - TypedArrayObject (declared in vm/TypedArrayObject.h)
+//         - TypedArrayObjectTemplate
+//           - Int8ArrayObject
+//           - Uint8ArrayObject
+//           - ...
 //
 // Note that |TypedArrayObjectTemplate| is just an implementation
 // detail that makes implementing its various subclasses easier.
 //
 // ArrayBufferObject and SharedArrayBufferObject are unrelated data types:
 // the racy memory of the latter cannot substitute for the non-racy memory of
 // the former; the non-racy memory of the former cannot be used with the atomics;
 // the former can be detached and the latter not.  Hence they have been
@@ -456,24 +457,50 @@ bool CreateWasmBuffer(JSContext* cx, con
  * ArrayBufferViewObject
  *
  * Common definitions shared by all array buffer views.
  */
 
 class ArrayBufferViewObject : public NativeObject
 {
   public:
+    // Underlying (Shared)ArrayBufferObject.
+    static constexpr size_t BUFFER_SLOT = 0;
+    static_assert(BUFFER_SLOT == JS_TYPEDARRAYLAYOUT_BUFFER_SLOT,
+                  "self-hosted code with burned-in constants must get the "
+                  "right buffer slot");
+
+    // Slot containing length of the view in number of typed elements.
+    static constexpr size_t LENGTH_SLOT = 1;
+    static_assert(LENGTH_SLOT == JS_TYPEDARRAYLAYOUT_LENGTH_SLOT,
+                  "self-hosted code with burned-in constants must get the "
+                  "right length slot");
+
+    // Offset of view within underlying (Shared)ArrayBufferObject.
+    static constexpr size_t BYTEOFFSET_SLOT = 2;
+    static_assert(BYTEOFFSET_SLOT == JS_TYPEDARRAYLAYOUT_BYTEOFFSET_SLOT,
+                  "self-hosted code with burned-in constants must get the "
+                  "right byteOffset slot");
+
+    static constexpr size_t RESERVED_SLOTS = 3;
+
+#ifdef DEBUG
+    static const uint8_t ZeroLengthArrayData = 0x4A;
+#endif
+
+    // The raw pointer to the buffer memory, the "private" value.
+    //
+    // This offset is exposed for performance reasons - so that it
+    // need not be looked up on accesses.
+    static constexpr size_t DATA_SLOT = 3;
+
     static ArrayBufferObjectMaybeShared* bufferObject(JSContext* cx, Handle<ArrayBufferViewObject*> obj);
 
     void notifyBufferDetached(JSContext* cx, void* newData);
 
-#ifdef DEBUG
-    bool isSharedMemory();
-#endif
-
     // By construction we only need unshared variants here.  See
     // comments in ArrayBufferObject.cpp.
     uint8_t* dataPointerUnshared(const JS::AutoRequireNoGC&);
     void setDataPointerUnshared(uint8_t* data);
 
     static void trace(JSTracer* trc, JSObject* obj);
 };
 
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -32,52 +32,22 @@ namespace js {
 /*
  * TypedArrayObject
  *
  * The non-templated base class for the specific typed implementations.
  * This class holds all the member variables that are used by
  * the subclasses.
  */
 
-class TypedArrayObject : public NativeObject
+class TypedArrayObject : public ArrayBufferViewObject
 {
   public:
-    // Underlying (Shared)ArrayBufferObject.
-    static const size_t BUFFER_SLOT = 0;
-    static_assert(BUFFER_SLOT == JS_TYPEDARRAYLAYOUT_BUFFER_SLOT,
-                  "self-hosted code with burned-in constants must get the "
-                  "right buffer slot");
-
-    // Slot containing length of the view in number of typed elements.
-    static const size_t LENGTH_SLOT = 1;
-    static_assert(LENGTH_SLOT == JS_TYPEDARRAYLAYOUT_LENGTH_SLOT,
-                  "self-hosted code with burned-in constants must get the "
-                  "right length slot");
-
-    // Offset of view within underlying (Shared)ArrayBufferObject.
-    static const size_t BYTEOFFSET_SLOT = 2;
-    static_assert(BYTEOFFSET_SLOT == JS_TYPEDARRAYLAYOUT_BYTEOFFSET_SLOT,
-                  "self-hosted code with burned-in constants must get the "
-                  "right byteOffset slot");
-
-    static const size_t RESERVED_SLOTS = 3;
-
-#ifdef DEBUG
-    static const uint8_t ZeroLengthArrayData = 0x4A;
-#endif
-
     static int lengthOffset();
     static int dataOffset();
 
-    // The raw pointer to the buffer memory, the "private" value.
-    //
-    // This offset is exposed for performance reasons - so that it
-    // need not be looked up on accesses.
-    static const size_t DATA_SLOT = 3;
-
     static_assert(js::detail::TypedArrayLengthSlot == LENGTH_SLOT,
                   "bad inlined constant in jsfriendapi.h");
 
     static bool sameBuffer(Handle<TypedArrayObject*> a, Handle<TypedArrayObject*> b) {
         // Inline buffers.
         if (!a->hasBuffer() || !b->hasBuffer()) {
             return a.get() == b.get();
         }