Bug 1496378 part 6 - Remove TypedObject to ArrayBufferViewObject static_cast hackery. r=jwalden
authorJan de Mooij <jdemooij@mozilla.com>
Mon, 15 Oct 2018 11:43:36 +0000
changeset 489628 8886fad423dc0f7de57b96512b5680eecc2733ba
parent 489627 b449c4991dc4153716f7d53173a14f7a29284616
child 489629 942ccac42c5e7e0ef48f5ef3f1b3d18f1cf47750
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersjwalden
bugs1496378
milestone64.0a1
Bug 1496378 part 6 - Remove TypedObject to ArrayBufferViewObject static_cast hackery. r=jwalden Depends on D7727 Differential Revision: https://phabricator.services.mozilla.com/D7728
js/src/vm/ArrayBufferObject.cpp
js/src/vm/ArrayBufferObject.h
js/src/vm/ArrayBufferViewObject.cpp
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -504,33 +504,32 @@ ArrayBufferObject::detach(JSContext* cx,
             oomUnsafe.crash("ArrayBufferObject::detach");
         }
         MarkObjectGroupFlags(cx, cx->global(), OBJECT_FLAG_TYPED_OBJECT_HAS_DETACHED_BUFFER);
         cx->zone()->detachedTypedObjects = 1;
     }
 
     // Update all views of the buffer to account for the buffer having been
     // detached, and clear the buffer's data and list of views.
+    //
+    // Typed object buffers are not exposed and cannot be detached.
 
     auto& innerViews = ObjectRealm::get(buffer).innerViews.get();
     if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(buffer)) {
         for (size_t i = 0; i < views->length(); i++) {
-            NoteViewBufferWasDetached((*views)[i], newContents, cx);
+            JSObject* view = (*views)[i];
+            NoteViewBufferWasDetached(&view->as<ArrayBufferViewObject>(), newContents, cx);
         }
         innerViews.removeViews(buffer);
     }
-    if (buffer->firstView()) {
-        if (buffer->forInlineTypedObject()) {
-            // The buffer points to inline data in its first view, so to keep
-            // this pointer alive we don't clear out the first view.
-            MOZ_ASSERT(buffer->firstView()->is<InlineTransparentTypedObject>());
-        } else {
-            NoteViewBufferWasDetached(buffer->firstView(), newContents, cx);
-            buffer->setFirstView(nullptr);
-        }
+    if (JSObject* view = buffer->firstView()) {
+        MOZ_ASSERT(!buffer->forInlineTypedObject(),
+                   "Typed object buffers cannot be detached");
+        NoteViewBufferWasDetached(&view->as<ArrayBufferViewObject>(), newContents, cx);
+        buffer->setFirstView(nullptr);
     }
 
     if (newContents.data() != buffer->dataPointer()) {
         buffer->setNewData(cx->runtime()->defaultFreeOp(), newContents, OwnsData);
     }
 
     buffer->setByteLength(0);
     buffer->setIsDetached();
@@ -585,21 +584,23 @@ ArrayBufferObject::changeContents(JSCont
     // Change buffer contents.
     uint8_t* oldDataPointer = dataPointer();
     setNewData(cx->runtime()->defaultFreeOp(), newContents, ownsState);
 
     // Update all views.
     auto& innerViews = ObjectRealm::get(this).innerViews.get();
     if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(this)) {
         for (size_t i = 0; i < views->length(); i++) {
-            changeViewContents(cx, (*views)[i], oldDataPointer, newContents);
+            JSObject* view = (*views)[i];
+            changeViewContents(cx, &view->as<ArrayBufferViewObject>(), oldDataPointer,
+                               newContents);
         }
     }
-    if (firstView()) {
-        changeViewContents(cx, firstView(), oldDataPointer, newContents);
+    if (JSObject* view = firstView()) {
+        changeViewContents(cx, &view->as<ArrayBufferViewObject>(), oldDataPointer, newContents);
     }
 }
 
 /*
  * [SMDOC] WASM Linear Memory structure
  *
  * Wasm Raw Buf Linear Memory Structure
  *
@@ -1476,54 +1477,53 @@ ArrayBufferObject::objectMoved(JSObject*
     // Fix up possible inline data pointer.
     if (src.hasInlineData()) {
         dst.setFixedSlot(DATA_SLOT, PrivateValue(dst.inlineDataPointer()));
     }
 
     return 0;
 }
 
-ArrayBufferViewObject*
+JSObject*
 ArrayBufferObject::firstView()
 {
     return getFixedSlot(FIRST_VIEW_SLOT).isObject()
-        ? static_cast<ArrayBufferViewObject*>(&getFixedSlot(FIRST_VIEW_SLOT).toObject())
+        ? &getFixedSlot(FIRST_VIEW_SLOT).toObject()
         : nullptr;
 }
 
 void
-ArrayBufferObject::setFirstView(ArrayBufferViewObject* view)
+ArrayBufferObject::setFirstView(JSObject* view)
 {
+    MOZ_ASSERT_IF(view,
+                  view->is<ArrayBufferViewObject>() || view->is<TypedObject>());
     setFixedSlot(FIRST_VIEW_SLOT, ObjectOrNullValue(view));
 }
 
 bool
-ArrayBufferObject::addView(JSContext* cx, JSObject* viewArg)
+ArrayBufferObject::addView(JSContext* cx, JSObject* view)
 {
-    // Note: we don't pass in an ArrayBufferViewObject as the argument due to
-    // tricky inheritance in the various view classes. View classes do not
-    // inherit from ArrayBufferViewObject so won't be upcast automatically.
-    MOZ_ASSERT(viewArg->is<ArrayBufferViewObject>() || viewArg->is<TypedObject>());
-    ArrayBufferViewObject* view = static_cast<ArrayBufferViewObject*>(viewArg);
+    MOZ_ASSERT(view->is<ArrayBufferViewObject>() || view->is<TypedObject>());
 
     if (!firstView()) {
         setFirstView(view);
         return true;
     }
+
     return ObjectRealm::get(this).innerViews.get().addView(cx, this, view);
 }
 
 /*
  * InnerViewTable
  */
 
 constexpr size_t VIEW_LIST_MAX_LENGTH = 500;
 
 bool
-InnerViewTable::addView(JSContext* cx, ArrayBufferObject* buffer, ArrayBufferViewObject* view)
+InnerViewTable::addView(JSContext* cx, ArrayBufferObject* buffer, JSObject* view)
 {
     // ArrayBufferObject entries are only added when there are multiple views.
     MOZ_ASSERT(buffer->firstView());
 
     Map::AddPtr p = map.lookupForAdd(buffer);
 
     MOZ_ASSERT(!gc::IsInsideNursery(buffer));
     bool addToNursery = nurseryKeysValid && gc::IsInsideNursery(view);
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -321,32 +321,32 @@ class ArrayBufferObject : public ArrayBu
     static void addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf mallocSizeOf,
                                        JS::ClassInfo* info);
 
     // ArrayBufferObjects (strongly) store the first view added to them, while
     // later views are (weakly) stored in the compartment's InnerViewTable
     // below. Buffers usually only have one view, so this slot optimizes for
     // the common case. Avoiding entries in the InnerViewTable saves memory and
     // non-incrementalized sweep time.
-    ArrayBufferViewObject* firstView();
+    JSObject* firstView();
 
     bool addView(JSContext* cx, JSObject* view);
 
     void setNewData(FreeOp* fop, BufferContents newContents, OwnsState ownsState);
     void changeContents(JSContext* cx, BufferContents newContents, OwnsState ownsState);
 
     // Detach this buffer from its original memory.  (This necessarily makes
     // views of this buffer unusable for modifying that original memory.)
     static void
     detach(JSContext* cx, Handle<ArrayBufferObject*> buffer, BufferContents newContents);
 
   private:
     void changeViewContents(JSContext* cx, ArrayBufferViewObject* view,
                             uint8_t* oldDataPointer, BufferContents newContents);
-    void setFirstView(ArrayBufferViewObject* view);
+    void setFirstView(JSObject* view);
 
     uint8_t* inlineDataPointer() const;
 
     struct FreeInfo {
         JS::BufferContentsFreeFunc freeFunc;
         void* freeUserData;
     };
     FreeInfo* freeInfo() const;
@@ -557,17 +557,17 @@ template<> inline bool TypeIsUnsigned<ui
 template<> inline bool TypeIsUnsigned<uint16_t>() { return true; }
 template<> inline bool TypeIsUnsigned<uint32_t>() { return true; }
 
 // Per-compartment table that manages the relationship between array buffers
 // and the views that use their storage.
 class InnerViewTable
 {
   public:
-    typedef Vector<ArrayBufferViewObject*, 1, SystemAllocPolicy> ViewVector;
+    typedef Vector<JSObject*, 1, SystemAllocPolicy> ViewVector;
 
     friend class ArrayBufferObject;
 
   private:
     struct MapGCPolicy {
         static bool needsSweep(JSObject** key, ViewVector* value) {
             return InnerViewTable::sweepEntry(key, *value);
         }
@@ -599,17 +599,17 @@ class InnerViewTable
     Vector<JSObject*, 0, SystemAllocPolicy> nurseryKeys;
 
     // Whether nurseryKeys is a complete list.
     bool nurseryKeysValid;
 
     // Sweep an entry during GC, returning whether the entry should be removed.
     static bool sweepEntry(JSObject** pkey, ViewVector& views);
 
-    bool addView(JSContext* cx, ArrayBufferObject* obj, ArrayBufferViewObject* view);
+    bool addView(JSContext* cx, ArrayBufferObject* buffer, JSObject* view);
     ViewVector* maybeViewsUnbarriered(ArrayBufferObject* obj);
     void removeViews(ArrayBufferObject* obj);
 
   public:
     InnerViewTable()
       : nurseryKeysValid(true)
     {}
 
--- a/js/src/vm/ArrayBufferViewObject.cpp
+++ b/js/src/vm/ArrayBufferViewObject.cpp
@@ -147,19 +147,17 @@ JS_GetArrayBufferViewBuffer(JSContext* c
     AssertHeapIsIdle();
     CHECK_THREAD(cx);
     cx->check(objArg);
 
     JSObject* obj = CheckedUnwrap(objArg);
     if (!obj) {
         return nullptr;
     }
-    MOZ_ASSERT(obj->is<ArrayBufferViewObject>());
-
-    Rooted<ArrayBufferViewObject*> viewObject(cx, static_cast<ArrayBufferViewObject*>(obj));
+    Rooted<ArrayBufferViewObject*> viewObject(cx, &obj->as<ArrayBufferViewObject>());
     ArrayBufferObjectMaybeShared* buffer = ArrayBufferViewObject::bufferObject(cx, viewObject);
     *isSharedMemory = buffer->is<SharedArrayBufferObject>();
     return buffer;
 }
 
 JS_FRIEND_API(uint32_t)
 JS_GetArrayBufferViewByteLength(JSObject* obj)
 {