Bug 1496378 part 4 - Move ArrayBufferViewObject and related APIs into vm/ArrayBufferViewObject.{h,cpp}. r=jwalden
authorJan de Mooij <jdemooij@mozilla.com>
Mon, 15 Oct 2018 11:42:12 +0000
changeset 489626 992c0bd2f327fd11fa790814162621f77080eb6b
parent 489625 e6c5e6c15848b2df293dade2084ec9a585f21c2b
child 489627 b449c4991dc4153716f7d53173a14f7a29284616
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersjwalden
bugs1496378
milestone64.0a1
Bug 1496378 part 4 - Move ArrayBufferViewObject and related APIs into vm/ArrayBufferViewObject.{h,cpp}. r=jwalden Depends on D7723 Differential Revision: https://phabricator.services.mozilla.com/D7724
js/src/builtin/DataViewObject.h
js/src/moz.build
js/src/vm/ArrayBufferObject-inl.h
js/src/vm/ArrayBufferObject.cpp
js/src/vm/ArrayBufferObject.h
js/src/vm/ArrayBufferViewObject.cpp
js/src/vm/ArrayBufferViewObject.h
js/src/vm/TypedArrayObject.h
--- a/js/src/builtin/DataViewObject.h
+++ b/js/src/builtin/DataViewObject.h
@@ -7,16 +7,17 @@
 #ifndef vm_DataViewObject_h
 #define vm_DataViewObject_h
 
 #include "mozilla/Attributes.h"
 
 #include "gc/Barrier.h"
 #include "js/Class.h"
 #include "vm/ArrayBufferObject.h"
+#include "vm/ArrayBufferViewObject.h"
 #include "vm/JSObject.h"
 #include "vm/SharedArrayObject.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
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -362,16 +362,17 @@ UNIFIED_SOURCES += [
     'util/CompleteFile.cpp',
     'util/NativeStack.cpp',
     'util/Printf.cpp',
     'util/StringBuffer.cpp',
     'util/Text.cpp',
     'util/Unicode.cpp',
     'vm/ArgumentsObject.cpp',
     'vm/ArrayBufferObject.cpp',
+    'vm/ArrayBufferViewObject.cpp',
     'vm/AsyncFunction.cpp',
     'vm/AsyncIteration.cpp',
     'vm/BytecodeUtil.cpp',
     'vm/Caches.cpp',
     'vm/CallNonGenericMethod.cpp',
     'vm/CharacterEncoding.cpp',
     'vm/CodeCoverage.cpp',
     'vm/Compartment.cpp',
--- a/js/src/vm/ArrayBufferObject-inl.h
+++ b/js/src/vm/ArrayBufferObject-inl.h
@@ -86,35 +86,11 @@ inline ArrayBufferObjectMaybeShared&
 AsAnyArrayBuffer(HandleValue val)
 {
     if (val.toObject().is<ArrayBufferObject>()) {
         return val.toObject().as<ArrayBufferObject>();
     }
     return val.toObject().as<SharedArrayBufferObject>();
 }
 
-inline SharedArrayBufferObject*
-ArrayBufferViewObject::bufferShared() const
-{
-    MOZ_ASSERT(isSharedMemory());
-    JSObject* obj = bufferObject();
-    if (!obj) {
-        return nullptr;
-    }
-    return &obj->as<SharedArrayBufferObject>();
-}
-
-inline ArrayBufferObjectMaybeShared*
-ArrayBufferViewObject::bufferEither() const
-{
-    JSObject* obj = bufferObject();
-    if (!obj) {
-        return nullptr;
-    }
-    if (isSharedMemory()) {
-        return &obj->as<SharedArrayBufferObject>();
-    }
-    return &obj->as<ArrayBufferObject>();
-}
-
 } // namespace js
 
 #endif // vm_ArrayBufferObject_inl_h
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -1653,159 +1653,23 @@ InnerViewTable::sizeOfExcludingThis(mozi
         vectorSize += e.front().value().sizeOfExcludingThis(mallocSizeOf);
     }
 
     return vectorSize
          + map.shallowSizeOfExcludingThis(mallocSizeOf)
          + nurseryKeys.sizeOfExcludingThis(mallocSizeOf);
 }
 
-/*
- * ArrayBufferViewObject
- */
-
-/*
- * This method is used to trace TypedArrayObjects and DataViewObjects. We need
- * a custom tracer to move the object's data pointer if its owner was moved and
- * stores its data inline.
- */
-/* static */ void
-ArrayBufferViewObject::trace(JSTracer* trc, JSObject* objArg)
-{
-    NativeObject* obj = &objArg->as<NativeObject>();
-    HeapSlot& bufSlot = obj->getFixedSlotRef(TypedArrayObject::BUFFER_SLOT);
-    TraceEdge(trc, &bufSlot, "typedarray.buffer");
-
-    // Update obj's data pointer if it moved.
-    if (bufSlot.isObject()) {
-        if (IsArrayBuffer(&bufSlot.toObject())) {
-            ArrayBufferObject& buf = AsArrayBuffer(MaybeForwarded(&bufSlot.toObject()));
-            uint32_t offset = uint32_t(obj->getFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT).toInt32());
-            MOZ_ASSERT(offset <= INT32_MAX);
-
-            if (buf.forInlineTypedObject()) {
-                MOZ_ASSERT(buf.dataPointer() != nullptr);
-
-                // The data is inline with an InlineTypedObject associated with the
-                // buffer. Get a new address for the typed object if it moved.
-                JSObject* view = buf.firstView();
-
-                // Mark the object to move it into the tenured space.
-                TraceManuallyBarrieredEdge(trc, &view, "typed array nursery owner");
-                MOZ_ASSERT(view->is<InlineTypedObject>());
-                MOZ_ASSERT(view != obj);
-
-                size_t nfixed = obj->numFixedSlotsMaybeForwarded();
-                void* srcData = obj->getPrivate(nfixed);
-                void* dstData = view->as<InlineTypedObject>().inlineTypedMemForGC() + offset;
-                obj->setPrivateUnbarriered(nfixed, dstData);
-
-                // We can't use a direct forwarding pointer here, as there might
-                // not be enough bytes available, and other views might have data
-                // pointers whose forwarding pointers would overlap this one.
-                if (trc->isTenuringTracer()) {
-                    Nursery& nursery = trc->runtime()->gc.nursery();
-                    nursery.maybeSetForwardingPointer(trc, srcData, dstData, /* direct = */ false);
-                }
-            } else {
-                MOZ_ASSERT_IF(buf.dataPointer() == nullptr, offset == 0);
-
-                // The data may or may not be inline with the buffer. The buffer
-                // can only move during a compacting GC, in which case its
-                // objectMoved hook has already updated the buffer's data pointer.
-                size_t nfixed = obj->numFixedSlotsMaybeForwarded();
-                obj->setPrivateUnbarriered(nfixed, buf.dataPointer() + offset);
-            }
-        }
-    }
-}
-
-template <>
-bool
-JSObject::is<js::ArrayBufferViewObject>() const
-{
-    return is<DataViewObject>() || is<TypedArrayObject>();
-}
-
 template <>
 bool
 JSObject::is<js::ArrayBufferObjectMaybeShared>() const
 {
     return is<ArrayBufferObject>() || is<SharedArrayBufferObject>();
 }
 
-void
-ArrayBufferViewObject::notifyBufferDetached(JSContext* cx, void* newData)
-{
-    if (isSharedMemory()) {
-        return;
-    }
-
-    MOZ_ASSERT(!isSharedMemory());
-    setFixedSlot(LENGTH_SLOT, Int32Value(0));
-    setFixedSlot(BYTEOFFSET_SLOT, Int32Value(0));
-
-    // If the object is in the nursery, the buffer will be freed by the next
-    // nursery GC. Free the data slot pointer if the object has no inline data.
-    if (is<TypedArrayObject>()) {
-        TypedArrayObject& tarr = as<TypedArrayObject>();
-        Nursery& nursery = cx->nursery();
-        if (isTenured() && !hasBuffer() && !tarr.hasInlineElements() &&
-            !nursery.isInside(tarr.elements()))
-        {
-            js_free(tarr.elements());
-        }
-    }
-
-    setPrivate(newData);
-}
-
-uint8_t*
-ArrayBufferViewObject::dataPointerUnshared(const JS::AutoRequireNoGC& nogc)
-{
-    return static_cast<uint8_t*>(dataPointerUnshared());
-}
-
-void
-ArrayBufferViewObject::setDataPointerUnshared(uint8_t* data)
-{
-    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)) {
-            return nullptr;
-        }
-    }
-    return thisObject->bufferEither();
-}
-
-/* JS Friend API */
-
-JS_FRIEND_API(bool)
-JS_IsArrayBufferViewObject(JSObject* obj)
-{
-    obj = CheckedUnwrap(obj);
-    return obj && obj->is<ArrayBufferViewObject>();
-}
-
-JS_FRIEND_API(JSObject*)
-js::UnwrapArrayBufferView(JSObject* obj)
-{
-    if (JSObject* unwrapped = CheckedUnwrap(obj)) {
-        return unwrapped->is<ArrayBufferViewObject>() ? unwrapped : nullptr;
-    }
-    return nullptr;
-}
-
 JS_FRIEND_API(uint32_t)
 JS_GetArrayBufferByteLength(JSObject* obj)
 {
     obj = CheckedUnwrap(obj);
     return obj ? AsArrayBuffer(obj).byteLength() : 0;
 }
 
 JS_FRIEND_API(uint8_t*)
@@ -2043,102 +1907,16 @@ JS_IsMappedArrayBufferObject(JSObject* o
     obj = CheckedUnwrap(obj);
     if (!obj) {
         return false;
     }
 
     return obj->is<ArrayBufferObject>() && obj->as<ArrayBufferObject>().isMapped();
 }
 
-JS_FRIEND_API(void*)
-JS_GetArrayBufferViewData(JSObject* obj, bool* isSharedMemory, const JS::AutoRequireNoGC&)
-{
-    obj = CheckedUnwrap(obj);
-    if (!obj) {
-        return nullptr;
-    }
-
-    ArrayBufferViewObject& view = obj->as<ArrayBufferViewObject>();
-    *isSharedMemory = view.isSharedMemory();
-    return view.dataPointerEither().unwrap(/*safe - caller sees isSharedMemory flag*/);
-}
-
-JS_FRIEND_API(JSObject*)
-JS_GetArrayBufferViewBuffer(JSContext* cx, HandleObject objArg, bool* isSharedMemory)
-{
-    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));
-    ArrayBufferObjectMaybeShared* buffer = ArrayBufferViewObject::bufferObject(cx, viewObject);
-    *isSharedMemory = buffer->is<SharedArrayBufferObject>();
-    return buffer;
-}
-
-JS_FRIEND_API(uint32_t)
-JS_GetArrayBufferViewByteLength(JSObject* obj)
-{
-    obj = CheckedUnwrap(obj);
-    if (!obj) {
-        return 0;
-    }
-    return obj->is<DataViewObject>()
-           ? obj->as<DataViewObject>().byteLength()
-           : obj->as<TypedArrayObject>().byteLength();
-}
-
-JS_FRIEND_API(uint32_t)
-JS_GetArrayBufferViewByteOffset(JSObject* obj)
-{
-    obj = CheckedUnwrap(obj);
-    if (!obj) {
-        return 0;
-    }
-    return obj->is<DataViewObject>()
-           ? obj->as<DataViewObject>().byteOffset()
-           : obj->as<TypedArrayObject>().byteOffset();
-}
-
-JS_FRIEND_API(JSObject*)
-JS_GetObjectAsArrayBufferView(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data)
-{
-    if (!(obj = CheckedUnwrap(obj))) {
-        return nullptr;
-    }
-    if (!(obj->is<ArrayBufferViewObject>())) {
-        return nullptr;
-    }
-
-    js::GetArrayBufferViewLengthAndData(obj, length, isSharedMemory, data);
-    return obj;
-}
-
-JS_FRIEND_API(void)
-js::GetArrayBufferViewLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory,
-                                    uint8_t** data)
-{
-    MOZ_ASSERT(obj->is<ArrayBufferViewObject>());
-
-    *length = obj->is<DataViewObject>()
-              ? obj->as<DataViewObject>().byteLength()
-              : obj->as<TypedArrayObject>().byteLength();
-
-    ArrayBufferViewObject& view = obj->as<ArrayBufferViewObject>();
-    *isSharedMemory = view.isSharedMemory();
-    *data = static_cast<uint8_t*>(
-            view.dataPointerEither().unwrap(/*safe - caller sees isShared flag*/));
-}
-
 JS_FRIEND_API(JSObject*)
 JS_GetObjectAsArrayBuffer(JSObject* obj, uint32_t* length, uint8_t** data)
 {
     if (!(obj = CheckedUnwrap(obj))) {
         return nullptr;
     }
     if (!IsArrayBuffer(obj)) {
         return nullptr;
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -448,138 +448,16 @@ class ArrayBufferObject : public ArrayBu
 
 typedef Rooted<ArrayBufferObject*> RootedArrayBufferObject;
 typedef Handle<ArrayBufferObject*> HandleArrayBufferObject;
 typedef MutableHandle<ArrayBufferObject*> MutableHandleArrayBufferObject;
 
 bool CreateWasmBuffer(JSContext* cx, const wasm::Limits& memory,
                       MutableHandleArrayBufferObjectMaybeShared buffer);
 
-/*
- * 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;
-
-  private:
-    void* dataPointerEither_() const {
-        // Note, do not check whether shared or not
-        // Keep synced with js::Get<Type>ArrayLengthAndData in jsfriendapi.h!
-        return static_cast<void*>(getPrivate(DATA_SLOT));
-    }
-
-  public:
-    static ArrayBufferObjectMaybeShared* bufferObject(JSContext* cx, Handle<ArrayBufferViewObject*> obj);
-
-    void notifyBufferDetached(JSContext* cx, void* newData);
-
-    // By construction we only need unshared variants here.  See
-    // comments in ArrayBufferObject.cpp.
-    uint8_t* dataPointerUnshared(const JS::AutoRequireNoGC&);
-    void setDataPointerUnshared(uint8_t* data);
-
-    void initDataPointer(SharedMem<uint8_t*> viewData) {
-        // Install a pointer to the buffer location that corresponds
-        // to offset zero within the typed array.
-        //
-        // The following unwrap is safe because the DATA_SLOT is
-        // accessed only from jitted code and from the
-        // dataPointerEither_() accessor above; in neither case does the
-        // raw pointer escape untagged into C++ code.
-        initPrivate(viewData.unwrap(/*safe - see above*/));
-    }
-
-    SharedMem<void*> dataPointerShared() const {
-        return SharedMem<void*>::shared(dataPointerEither_());
-    }
-    SharedMem<void*> dataPointerEither() const {
-        if (isSharedMemory()) {
-            return SharedMem<void*>::shared(dataPointerEither_());
-        }
-        return SharedMem<void*>::unshared(dataPointerEither_());
-    }
-    void* dataPointerUnshared() const {
-        MOZ_ASSERT(!isSharedMemory());
-        return dataPointerEither_();
-    }
-
-    static Value bufferValue(const ArrayBufferViewObject* view) {
-        return view->getFixedSlot(BUFFER_SLOT);
-    }
-    bool hasBuffer() const {
-        return bufferValue(this).isObject();
-    }
-    JSObject* bufferObject() const {
-        return bufferValue(this).toObjectOrNull();
-    }
-
-    ArrayBufferObject* bufferUnshared() const {
-        MOZ_ASSERT(!isSharedMemory());
-        JSObject* obj = bufferObject();
-        if (!obj) {
-            return nullptr;
-        }
-        return &obj->as<ArrayBufferObject>();
-    }
-
-    inline SharedArrayBufferObject* bufferShared() const;
-    inline ArrayBufferObjectMaybeShared* bufferEither() const;
-
-    bool hasDetachedBuffer() const {
-        // Shared buffers can't be detached.
-        if (isSharedMemory()) {
-            return false;
-        }
-
-        // A typed array with a null buffer has never had its buffer exposed to
-        // become detached.
-        ArrayBufferObject* buffer = bufferUnshared();
-        if (!buffer) {
-            return false;
-        }
-
-        return buffer->isDetached();
-    }
-
-    static void trace(JSTracer* trc, JSObject* obj);
-};
-
 bool
 ToClampedIndex(JSContext* cx, HandleValue v, uint32_t length, uint32_t* out);
 
 /*
  * Tests for ArrayBufferObject, like obj->is<ArrayBufferObject>().
  */
 bool IsArrayBuffer(HandleValue v);
 bool IsArrayBuffer(HandleObject obj);
@@ -764,15 +642,11 @@ class MutableWrappedPtrOperations<InnerV
         return table().sizeOfExcludingThis(mallocSizeOf);
     }
 };
 
 } // namespace js
 
 template <>
 bool
-JSObject::is<js::ArrayBufferViewObject>() const;
-
-template <>
-bool
 JSObject::is<js::ArrayBufferObjectMaybeShared>() const;
 
 #endif // vm_ArrayBufferObject_h
copy from js/src/vm/ArrayBufferObject.cpp
copy to js/src/vm/ArrayBufferViewObject.cpp
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferViewObject.cpp
@@ -1,1673 +1,27 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "vm/ArrayBufferObject-inl.h"
-#include "vm/ArrayBufferObject.h"
-
-#include "mozilla/Alignment.h"
-#include "mozilla/CheckedInt.h"
-#include "mozilla/FloatingPoint.h"
-#include "mozilla/Maybe.h"
-#include "mozilla/PodOperations.h"
-#include "mozilla/TaggedAnonymousMemory.h"
+#include "vm/ArrayBufferViewObject.h"
 
-#include <string.h>
-#ifndef XP_WIN
-# include <sys/mman.h>
-#endif
-#ifdef MOZ_VALGRIND
-# include <valgrind/memcheck.h>
-#endif
-
-#include "jsapi.h"
-#include "jsfriendapi.h"
-#include "jsnum.h"
-#include "jstypes.h"
-#include "jsutil.h"
-
-#include "builtin/Array.h"
 #include "builtin/DataViewObject.h"
-#include "gc/Barrier.h"
-#include "gc/FreeOp.h"
-#include "gc/Memory.h"
-#include "js/Conversions.h"
-#include "js/MemoryMetrics.h"
-#include "js/Wrapper.h"
-#include "util/Windows.h"
-#include "vm/GlobalObject.h"
-#include "vm/Interpreter.h"
+#include "gc/Nursery.h"
 #include "vm/JSContext.h"
-#include "vm/JSObject.h"
-#include "vm/SharedArrayObject.h"
-#include "vm/WrapperObject.h"
-#include "wasm/WasmSignalHandlers.h"
-#include "wasm/WasmTypes.h"
+#include "vm/TypedArrayObject.h"
 
-#include "gc/Marking-inl.h"
 #include "gc/Nursery-inl.h"
-#include "vm/JSAtom-inl.h"
 #include "vm/NativeObject-inl.h"
-#include "vm/Shape-inl.h"
-
-using JS::ToInt32;
-
-using mozilla::Atomic;
-using mozilla::CheckedInt;
-using mozilla::Some;
-using mozilla::Maybe;
-using mozilla::Nothing;
-using mozilla::Unused;
 
 using namespace js;
 
 /*
- * Convert |v| to an array index for an array of length |length| per
- * the Typed Array Specification section 7.0, |subarray|. If successful,
- * the output value is in the range [0, length].
- */
-bool
-js::ToClampedIndex(JSContext* cx, HandleValue v, uint32_t length, uint32_t* out)
-{
-    int32_t result;
-    if (!ToInt32(cx, v, &result)) {
-        return false;
-    }
-    if (result < 0) {
-        result += length;
-        if (result < 0) {
-            result = 0;
-        }
-    } else if (uint32_t(result) > length) {
-        result = length;
-    }
-    *out = uint32_t(result);
-    return true;
-}
-
-// If there are too many 4GB buffers live we run up against system resource
-// exhaustion (address space or number of memory map descriptors), see
-// bug 1068684, bug 1073934 for details.  The limiting case seems to be
-// Windows Vista Home 64-bit, where the per-process address space is limited
-// to 8TB.  Thus we track the number of live objects, and set a limit of
-// 1000 live objects per process and we throw an OOM error if the per-process
-// limit is exceeded.
-//
-// Since the MaximumLiveMappedBuffers limit is not generally accounted for by
-// any existing GC-trigger heuristics, we need an extra heuristic for triggering
-// GCs when the caller is allocating memories rapidly without other garbage.
-// Thus, once the live buffer count crosses a certain threshold, we start
-// triggering GCs every N allocations. As we get close to the limit, perform
-// expensive non-incremental full GCs as a last-ditch effort to avoid
-// unnecessary failure. The *Sans use a ton of vmem for bookkeeping leaving a
-// lot less for the program so use a lower limit.
-
-#if defined(MOZ_TSAN) || defined(MOZ_ASAN)
-static const int32_t MaximumLiveMappedBuffers = 500;
-#else
-static const int32_t MaximumLiveMappedBuffers = 1000;
-#endif
-static const int32_t StartTriggeringAtLiveBufferCount = 100;
-static const int32_t StartSyncFullGCAtLiveBufferCount = MaximumLiveMappedBuffers - 100;
-static const int32_t AllocatedBuffersPerTrigger = 100;
-
-static Atomic<int32_t, mozilla::ReleaseAcquire> liveBufferCount(0);
-static Atomic<int32_t, mozilla::ReleaseAcquire> allocatedSinceLastTrigger(0);
-
-int32_t
-js::LiveMappedBufferCount()
-{
-    return liveBufferCount;
-}
-
-void*
-js::MapBufferMemory(size_t mappedSize, size_t initialCommittedSize)
-{
-    MOZ_ASSERT(mappedSize % gc::SystemPageSize() == 0);
-    MOZ_ASSERT(initialCommittedSize % gc::SystemPageSize() == 0);
-    MOZ_ASSERT(initialCommittedSize <= mappedSize);
-
-    // Test >= to guard against the case where multiple extant runtimes
-    // race to allocate.
-    if (++liveBufferCount >= MaximumLiveMappedBuffers) {
-        if (OnLargeAllocationFailure) {
-            OnLargeAllocationFailure();
-        }
-        if (liveBufferCount >= MaximumLiveMappedBuffers) {
-            liveBufferCount--;
-            return nullptr;
-        }
-    }
-
-#ifdef XP_WIN
-    void* data = VirtualAlloc(nullptr, mappedSize, MEM_RESERVE, PAGE_NOACCESS);
-    if (!data) {
-        liveBufferCount--;
-        return nullptr;
-    }
-
-    if (!VirtualAlloc(data, initialCommittedSize, MEM_COMMIT, PAGE_READWRITE)) {
-        VirtualFree(data, 0, MEM_RELEASE);
-        liveBufferCount--;
-        return nullptr;
-    }
-#else  // XP_WIN
-    void* data = MozTaggedAnonymousMmap(nullptr, mappedSize, PROT_NONE,
-                                        MAP_PRIVATE | MAP_ANON, -1, 0, "wasm-reserved");
-    if (data == MAP_FAILED) {
-        liveBufferCount--;
-        return nullptr;
-    }
-
-    // Note we will waste a page on zero-sized memories here
-    if (mprotect(data, initialCommittedSize, PROT_READ | PROT_WRITE)) {
-        munmap(data, mappedSize);
-        liveBufferCount--;
-        return nullptr;
-    }
-#endif  // !XP_WIN
-
-#if defined(MOZ_VALGRIND) && defined(VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE)
-    VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE((unsigned char*)data + initialCommittedSize,
-                                                   mappedSize - initialCommittedSize);
-#endif
-
-    return data;
-}
-
-bool
-js::CommitBufferMemory(void* dataEnd, uint32_t delta)
-{
-    MOZ_ASSERT(delta);
-    MOZ_ASSERT(delta % gc::SystemPageSize() == 0);
-
-#ifdef XP_WIN
-    if (!VirtualAlloc(dataEnd, delta, MEM_COMMIT, PAGE_READWRITE)) {
-        return false;
-    }
-#else  // XP_WIN
-    if (mprotect(dataEnd, delta, PROT_READ | PROT_WRITE)) {
-        return false;
-    }
-#endif  // !XP_WIN
-
-#if defined(MOZ_VALGRIND) && defined(VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE)
-    VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE((unsigned char*)dataEnd, delta);
-#endif
-
-    return true;
-}
-
-#ifndef WASM_HUGE_MEMORY
-bool
-js::ExtendBufferMapping(void* dataPointer, size_t mappedSize, size_t newMappedSize)
-{
-    MOZ_ASSERT(mappedSize % gc::SystemPageSize() == 0);
-    MOZ_ASSERT(newMappedSize % gc::SystemPageSize() == 0);
-    MOZ_ASSERT(newMappedSize >= mappedSize);
-
-#ifdef XP_WIN
-    void* mappedEnd = (char*)dataPointer + mappedSize;
-    uint32_t delta = newMappedSize - mappedSize;
-    if (!VirtualAlloc(mappedEnd, delta, MEM_RESERVE, PAGE_NOACCESS)) {
-        return false;
-    }
-    return true;
-#elif defined(XP_LINUX)
-    // Note this will not move memory (no MREMAP_MAYMOVE specified)
-    if (MAP_FAILED == mremap(dataPointer, mappedSize, newMappedSize, 0)) {
-        return false;
-    }
-    return true;
-#else
-    // No mechanism for remapping on MacOS and other Unices. Luckily
-    // shouldn't need it here as most of these are 64-bit.
-    return false;
-#endif
-}
-#endif
-
-void
-js::UnmapBufferMemory(void* base, size_t mappedSize)
-{
-    MOZ_ASSERT(mappedSize % gc::SystemPageSize() == 0);
-
-#ifdef XP_WIN
-    VirtualFree(base, 0, MEM_RELEASE);
-#else  // XP_WIN
-    munmap(base, mappedSize);
-#endif  // !XP_WIN
-
-#if defined(MOZ_VALGRIND) && defined(VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE)
-    VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE((unsigned char*)base, mappedSize);
-#endif
-
-    // Decrement the buffer counter at the end -- otherwise, a race condition
-    // could enable the creation of unlimited buffers.
-    liveBufferCount--;
-}
-
-/*
- * ArrayBufferObject
- *
- * This class holds the underlying raw buffer that the TypedArrayObject classes
- * access.  It can be created explicitly and passed to a TypedArrayObject, or
- * can be created implicitly by constructing a TypedArrayObject with a size.
- */
-
-/*
- * ArrayBufferObject (base)
- */
-
-static const ClassOps ArrayBufferObjectClassOps = {
-    nullptr,        /* addProperty */
-    nullptr,        /* delProperty */
-    nullptr,        /* enumerate */
-    nullptr,        /* newEnumerate */
-    nullptr,        /* resolve */
-    nullptr,        /* mayResolve */
-    ArrayBufferObject::finalize,
-    nullptr,        /* call        */
-    nullptr,        /* hasInstance */
-    nullptr,        /* construct   */
-    ArrayBufferObject::trace,
-};
-
-static const JSFunctionSpec arraybuffer_functions[] = {
-    JS_FN("isView", ArrayBufferObject::fun_isView, 1, 0),
-    JS_FS_END
-};
-
-static const JSPropertySpec arraybuffer_properties[] = {
-    JS_SELF_HOSTED_SYM_GET(species, "ArrayBufferSpecies", 0),
-    JS_PS_END
-};
-
-
-static const JSFunctionSpec arraybuffer_proto_functions[] = {
-    JS_SELF_HOSTED_FN("slice", "ArrayBufferSlice", 2, 0),
-    JS_FS_END
-};
-
-static const JSPropertySpec arraybuffer_proto_properties[] = {
-    JS_PSG("byteLength", ArrayBufferObject::byteLengthGetter, 0),
-    JS_STRING_SYM_PS(toStringTag, "ArrayBuffer", JSPROP_READONLY),
-    JS_PS_END
-};
-
-static const ClassSpec ArrayBufferObjectClassSpec = {
-    GenericCreateConstructor<ArrayBufferObject::class_constructor, 1, gc::AllocKind::FUNCTION>,
-    GenericCreatePrototype<ArrayBufferObject>,
-    arraybuffer_functions,
-    arraybuffer_properties,
-    arraybuffer_proto_functions,
-    arraybuffer_proto_properties
-};
-
-static const ClassExtension ArrayBufferObjectClassExtension = {
-    nullptr,    /* weakmapKeyDelegateOp */
-    ArrayBufferObject::objectMoved
-};
-
-const Class ArrayBufferObject::class_ = {
-    "ArrayBuffer",
-    JSCLASS_DELAY_METADATA_BUILDER |
-    JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer) |
-    JSCLASS_BACKGROUND_FINALIZE,
-    &ArrayBufferObjectClassOps,
-    &ArrayBufferObjectClassSpec,
-    &ArrayBufferObjectClassExtension
-};
-
-const Class ArrayBufferObject::protoClass_ = {
-    "ArrayBufferPrototype",
-    JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
-    JS_NULL_CLASS_OPS,
-    &ArrayBufferObjectClassSpec
-};
-
-bool
-js::IsArrayBuffer(HandleValue v)
-{
-    return v.isObject() && v.toObject().is<ArrayBufferObject>();
-}
-
-bool
-js::IsArrayBuffer(HandleObject obj)
-{
-    return obj->is<ArrayBufferObject>();
-}
-
-bool
-js::IsArrayBuffer(JSObject* obj)
-{
-    return obj->is<ArrayBufferObject>();
-}
-
-ArrayBufferObject&
-js::AsArrayBuffer(HandleObject obj)
-{
-    MOZ_ASSERT(IsArrayBuffer(obj));
-    return obj->as<ArrayBufferObject>();
-}
-
-ArrayBufferObject&
-js::AsArrayBuffer(JSObject* obj)
-{
-    MOZ_ASSERT(IsArrayBuffer(obj));
-    return obj->as<ArrayBufferObject>();
-}
-
-bool
-js::IsArrayBufferMaybeShared(HandleValue v)
-{
-    return v.isObject() && v.toObject().is<ArrayBufferObjectMaybeShared>();
-}
-
-bool
-js::IsArrayBufferMaybeShared(HandleObject obj)
-{
-    return obj->is<ArrayBufferObjectMaybeShared>();
-}
-
-bool
-js::IsArrayBufferMaybeShared(JSObject* obj)
-{
-    return obj->is<ArrayBufferObjectMaybeShared>();
-}
-
-ArrayBufferObjectMaybeShared&
-js::AsArrayBufferMaybeShared(HandleObject obj)
-{
-    MOZ_ASSERT(IsArrayBufferMaybeShared(obj));
-    return obj->as<ArrayBufferObjectMaybeShared>();
-}
-
-ArrayBufferObjectMaybeShared&
-js::AsArrayBufferMaybeShared(JSObject* obj)
-{
-    MOZ_ASSERT(IsArrayBufferMaybeShared(obj));
-    return obj->as<ArrayBufferObjectMaybeShared>();
-}
-
-MOZ_ALWAYS_INLINE bool
-ArrayBufferObject::byteLengthGetterImpl(JSContext* cx, const CallArgs& args)
-{
-    MOZ_ASSERT(IsArrayBuffer(args.thisv()));
-    args.rval().setInt32(args.thisv().toObject().as<ArrayBufferObject>().byteLength());
-    return true;
-}
-
-bool
-ArrayBufferObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsArrayBuffer, byteLengthGetterImpl>(cx, args);
-}
-
-/*
- * ArrayBuffer.isView(obj); ES6 (Dec 2013 draft) 24.1.3.1
- */
-bool
-ArrayBufferObject::fun_isView(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    args.rval().setBoolean(args.get(0).isObject() &&
-                           JS_IsArrayBufferViewObject(&args.get(0).toObject()));
-    return true;
-}
-
-// ES2017 draft 24.1.2.1
-bool
-ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    // Step 1.
-    if (!ThrowIfNotConstructing(cx, args, "ArrayBuffer")) {
-        return false;
-    }
-
-    // Step 2.
-    uint64_t byteLength;
-    if (!ToIndex(cx, args.get(0), &byteLength)) {
-        return false;
-    }
-
-    // Step 3 (Inlined 24.1.1.1 AllocateArrayBuffer).
-    // 24.1.1.1, step 1 (Inlined 9.1.14 OrdinaryCreateFromConstructor).
-    RootedObject proto(cx);
-    if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
-        return false;
-    }
-
-    // 24.1.1.1, step 3 (Inlined 6.2.6.1 CreateByteDataBlock, step 2).
-    // Refuse to allocate too large buffers, currently limited to ~2 GiB.
-    if (byteLength > INT32_MAX) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
-        return false;
-    }
-
-    // 24.1.1.1, steps 1 and 4-6.
-    JSObject* bufobj = create(cx, uint32_t(byteLength), proto);
-    if (!bufobj) {
-        return false;
-    }
-    args.rval().setObject(*bufobj);
-    return true;
-}
-
-static ArrayBufferObject::BufferContents
-AllocateArrayBufferContents(JSContext* cx, uint32_t nbytes)
-{
-    uint8_t* p = cx->pod_callocCanGC<uint8_t>(nbytes,
-                                                      js::ArrayBufferContentsArena);
-    return ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(p);
-}
-
-static void
-NoteViewBufferWasDetached(ArrayBufferViewObject* view,
-                          ArrayBufferObject::BufferContents newContents,
-                          JSContext* cx)
-{
-    view->notifyBufferDetached(cx, newContents.data());
-
-    // Notify compiled jit code that the base pointer has moved.
-    MarkObjectStateChange(cx, view);
-}
-
-/* static */ void
-ArrayBufferObject::detach(JSContext* cx, Handle<ArrayBufferObject*> buffer,
-                          BufferContents newContents)
-{
-    cx->check(buffer);
-    MOZ_ASSERT(!buffer->isPreparedForAsmJS());
-
-    // When detaching buffers where we don't know all views, the new data must
-    // match the old data. All missing views are typed objects, which do not
-    // expect their data to ever change.
-    MOZ_ASSERT_IF(buffer->forInlineTypedObject(),
-                  newContents.data() == buffer->dataPointer());
-
-    // When detaching a buffer with typed object views, any jitcode accessing
-    // such views must be deoptimized so that detachment checks are performed.
-    // This is done by setting a zone-wide flag indicating that buffers with
-    // typed object views have been detached.
-    if (buffer->hasTypedObjectViews()) {
-        // Make sure the global object's group has been instantiated, so the
-        // flag change will be observed.
-        AutoEnterOOMUnsafeRegion oomUnsafe;
-        if (!JSObject::getGroup(cx, cx->global())) {
-            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.
-
-    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);
-        }
-        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 (newContents.data() != buffer->dataPointer()) {
-        buffer->setNewData(cx->runtime()->defaultFreeOp(), newContents, OwnsData);
-    }
-
-    buffer->setByteLength(0);
-    buffer->setIsDetached();
-}
-
-void
-ArrayBufferObject::setNewData(FreeOp* fop, BufferContents newContents, OwnsState ownsState)
-{
-    if (ownsData()) {
-        MOZ_ASSERT(newContents.data() != dataPointer());
-        releaseData(fop);
-    }
-
-    setDataPointer(newContents, ownsState);
-}
-
-// This is called *only* from changeContents(), below.
-// By construction, every view parameter will be mapping unshared memory (an ArrayBuffer).
-// Hence no reason to worry about shared memory here.
-
-void
-ArrayBufferObject::changeViewContents(JSContext* cx, ArrayBufferViewObject* view,
-                                      uint8_t* oldDataPointer, BufferContents newContents)
-{
-    MOZ_ASSERT(!view->isSharedMemory());
-
-    // Watch out for NULL data pointers in views. This means that the view
-    // is not fully initialized (in which case it'll be initialized later
-    // with the correct pointer).
-    JS::AutoCheckCannotGC nogc;
-    uint8_t* viewDataPointer = view->dataPointerUnshared(nogc);
-    if (viewDataPointer) {
-        MOZ_ASSERT(newContents);
-        ptrdiff_t offset = viewDataPointer - oldDataPointer;
-        viewDataPointer = static_cast<uint8_t*>(newContents.data()) + offset;
-        view->setDataPointerUnshared(viewDataPointer);
-    }
-
-    // Notify compiled jit code that the base pointer has moved.
-    MarkObjectStateChange(cx, view);
-}
-
-// BufferContents is specific to ArrayBuffer, hence it will not represent shared memory.
-
-void
-ArrayBufferObject::changeContents(JSContext* cx, BufferContents newContents,
-                                  OwnsState ownsState)
-{
-    MOZ_RELEASE_ASSERT(!isWasm());
-    MOZ_ASSERT(!forInlineTypedObject());
-
-    // 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);
-        }
-    }
-    if (firstView()) {
-        changeViewContents(cx, firstView(), oldDataPointer, newContents);
-    }
-}
-
-/*
- * [SMDOC] WASM Linear Memory structure
- *
- * Wasm Raw Buf Linear Memory Structure
- *
- * The linear heap in Wasm is an mmaped array buffer. Several
- * constants manage its lifetime:
- *
- *  - length - the wasm-visible current length of the buffer. Accesses in the
- *    range [0, length] succeed. May only increase.
- *
- *  - boundsCheckLimit - the size against which we perform bounds checks. It is
- *    always a constant offset smaller than mappedSize. Currently that constant
- *    offset is 64k (wasm::GuardSize).
- *
- *  - maxSize - the optional declared limit on how much length can grow.
- *
- *  - mappedSize - the actual mmaped size. Access in the range
- *    [0, mappedSize] will either succeed, or be handled by the wasm signal
- *    handlers.
- *
- * The below diagram shows the layout of the wasm heap. The wasm-visible
- * portion of the heap starts at 0. There is one extra page prior to the
- * start of the wasm heap which contains the WasmArrayRawBuffer struct at
- * its end (i.e. right before the start of the WASM heap).
- *
- *  WasmArrayRawBuffer
- *      \    ArrayBufferObject::dataPointer()
- *       \  /
- *        \ |
- *  ______|_|____________________________________________________________
- * |______|_|______________|___________________|____________|____________|
- *          0          length              maxSize  boundsCheckLimit  mappedSize
- *
- * \_______________________/
- *          COMMITED
- *                          \____________________________________________/
- *                                           SLOP
- * \_____________________________________________________________________/
- *                         MAPPED
- *
- * Invariants:
- *  - length only increases
- *  - 0 <= length <= maxSize (if present) <= boundsCheckLimit <= mappedSize
- *  - on ARM boundsCheckLimit must be a valid ARM immediate.
- *  - if maxSize is not specified, boundsCheckLimit/mappedSize may grow. They are
- *    otherwise constant.
- *
- * NOTE: For asm.js on non-x64 we guarantee that
- *
- * length == maxSize == boundsCheckLimit == mappedSize
- *
- * That is, signal handlers will not be invoked, since they cannot emulate
- * asm.js accesses on non-x64 architectures.
- *
- * The region between length and mappedSize is the SLOP - an area where we use
- * signal handlers to catch things that slip by bounds checks. Logically it has
- * two parts:
- *
- *  - from length to boundsCheckLimit - this part of the SLOP serves to catch
- *  accesses to memory we have reserved but not yet grown into. This allows us
- *  to grow memory up to max (when present) without having to patch/update the
- *  bounds checks.
- *
- *  - from boundsCheckLimit to mappedSize - this part of the SLOP allows us to
- *  bounds check against base pointers and fold some constant offsets inside
- *  loads. This enables better Bounds Check Elimination.
- *
- */
-
-class js::WasmArrayRawBuffer
-{
-    Maybe<uint32_t> maxSize_;
-    size_t mappedSize_;         // Not including the header page
-
-  protected:
-    WasmArrayRawBuffer(uint8_t* buffer, const Maybe<uint32_t>& maxSize, size_t mappedSize)
-      : maxSize_(maxSize), mappedSize_(mappedSize)
-    {
-        MOZ_ASSERT(buffer == dataPointer());
-    }
-
-  public:
-    static WasmArrayRawBuffer* Allocate(uint32_t numBytes, const Maybe<uint32_t>& maxSize);
-    static void Release(void* mem);
-
-    uint8_t* dataPointer() {
-        uint8_t* ptr = reinterpret_cast<uint8_t*>(this);
-        return ptr + sizeof(WasmArrayRawBuffer);
-    }
-
-    uint8_t* basePointer() {
-        return dataPointer() - gc::SystemPageSize();
-    }
-
-    size_t mappedSize() const {
-        return mappedSize_;
-    }
-
-    Maybe<uint32_t> maxSize() const {
-        return maxSize_;
-    }
-
-#ifndef WASM_HUGE_MEMORY
-    uint32_t boundsCheckLimit() const {
-        MOZ_ASSERT(mappedSize_ <= UINT32_MAX);
-        MOZ_ASSERT(mappedSize_ >= wasm::GuardSize);
-        MOZ_ASSERT(wasm::IsValidBoundsCheckImmediate(mappedSize_ - wasm::GuardSize));
-        return mappedSize_ - wasm::GuardSize;
-    }
-#endif
-
-    MOZ_MUST_USE bool growToSizeInPlace(uint32_t oldSize, uint32_t newSize) {
-        MOZ_ASSERT(newSize >= oldSize);
-        MOZ_ASSERT_IF(maxSize(), newSize <= maxSize().value());
-        MOZ_ASSERT(newSize <= mappedSize());
-
-        uint32_t delta = newSize - oldSize;
-        MOZ_ASSERT(delta % wasm::PageSize == 0);
-
-        uint8_t* dataEnd = dataPointer() + oldSize;
-        MOZ_ASSERT(uintptr_t(dataEnd) % gc::SystemPageSize() == 0);
-
-        if (delta && !CommitBufferMemory(dataEnd, delta)) {
-            return false;
-        }
-
-        return true;
-    }
-
-#ifndef WASM_HUGE_MEMORY
-    bool extendMappedSize(uint32_t maxSize) {
-        size_t newMappedSize = wasm::ComputeMappedSize(maxSize);
-        MOZ_ASSERT(mappedSize_ <= newMappedSize);
-        if (mappedSize_ == newMappedSize) {
-            return true;
-        }
-
-        if (!ExtendBufferMapping(dataPointer(), mappedSize_, newMappedSize)) {
-            return false;
-        }
-
-        mappedSize_ = newMappedSize;
-        return true;
-    }
-
-    // Try and grow the mapped region of memory. Does not change current size.
-    // Does not move memory if no space to grow.
-    void tryGrowMaxSizeInPlace(uint32_t deltaMaxSize) {
-        CheckedInt<uint32_t> newMaxSize = maxSize_.value();
-        newMaxSize += deltaMaxSize;
-        MOZ_ASSERT(newMaxSize.isValid());
-        MOZ_ASSERT(newMaxSize.value() % wasm::PageSize == 0);
-
-        if (!extendMappedSize(newMaxSize.value())) {
-            return;
-        }
-
-        maxSize_ = Some(newMaxSize.value());
-    }
-#endif // WASM_HUGE_MEMORY
-};
-
-/* static */ WasmArrayRawBuffer*
-WasmArrayRawBuffer::Allocate(uint32_t numBytes, const Maybe<uint32_t>& maxSize)
-{
-    MOZ_RELEASE_ASSERT(numBytes <= ArrayBufferObject::MaxBufferByteLength);
-
-    size_t mappedSize;
-#ifdef WASM_HUGE_MEMORY
-    mappedSize = wasm::HugeMappedSize;
-#else
-    mappedSize = wasm::ComputeMappedSize(maxSize.valueOr(numBytes));
-#endif
-
-    MOZ_RELEASE_ASSERT(mappedSize <= SIZE_MAX - gc::SystemPageSize());
-    MOZ_RELEASE_ASSERT(numBytes <= maxSize.valueOr(UINT32_MAX));
-    MOZ_ASSERT(numBytes % gc::SystemPageSize() == 0);
-    MOZ_ASSERT(mappedSize % gc::SystemPageSize() == 0);
-
-    uint64_t mappedSizeWithHeader = mappedSize + gc::SystemPageSize();
-    uint64_t numBytesWithHeader = numBytes + gc::SystemPageSize();
-
-    void* data = MapBufferMemory((size_t) mappedSizeWithHeader, (size_t) numBytesWithHeader);
-    if (!data) {
-        return nullptr;
-    }
-
-    uint8_t* base = reinterpret_cast<uint8_t*>(data) + gc::SystemPageSize();
-    uint8_t* header = base - sizeof(WasmArrayRawBuffer);
-
-    auto rawBuf = new (header) WasmArrayRawBuffer(base, maxSize, mappedSize);
-    return rawBuf;
-}
-
-/* static */ void
-WasmArrayRawBuffer::Release(void* mem)
-{
-    WasmArrayRawBuffer* header = (WasmArrayRawBuffer*)((uint8_t*)mem - sizeof(WasmArrayRawBuffer));
-
-    MOZ_RELEASE_ASSERT(header->mappedSize() <= SIZE_MAX - gc::SystemPageSize());
-    size_t mappedSizeWithHeader = header->mappedSize() + gc::SystemPageSize();
-
-    UnmapBufferMemory(header->basePointer(), mappedSizeWithHeader);
-}
-
-WasmArrayRawBuffer*
-ArrayBufferObject::BufferContents::wasmBuffer() const
-{
-    MOZ_RELEASE_ASSERT(kind_ == WASM);
-    return (WasmArrayRawBuffer*)(data_ - sizeof(WasmArrayRawBuffer));
-}
-
-template<typename ObjT, typename RawbufT>
-static bool
-CreateBuffer(JSContext* cx, uint32_t initialSize, const Maybe<uint32_t>& maxSize,
-             MutableHandleArrayBufferObjectMaybeShared maybeSharedObject)
-{
-#define ROUND_UP(v, a) ((v) % (a) == 0 ? (v) : v + a - ((v) % (a)))
-
-    RawbufT* buffer = RawbufT::Allocate(initialSize, maxSize);
-    if (!buffer) {
-#ifdef  WASM_HUGE_MEMORY
-        ReportOutOfMemory(cx);
-        return false;
-#else
-        // If we fail, and have a maxSize, try to reserve the biggest chunk in
-        // the range [initialSize, maxSize) using log backoff.
-        if (!maxSize) {
-            ReportOutOfMemory(cx);
-            return false;
-        }
-
-        uint32_t cur = maxSize.value() / 2;
-
-        for (; cur > initialSize; cur /= 2) {
-            buffer = RawbufT::Allocate(initialSize, mozilla::Some(ROUND_UP(cur, wasm::PageSize)));
-            if (buffer) {
-                break;
-            }
-        }
-
-        if (!buffer) {
-            ReportOutOfMemory(cx);
-            return false;
-        }
-
-        // Try to grow our chunk as much as possible.
-        for (size_t d = cur / 2; d >= wasm::PageSize; d /= 2) {
-            buffer->tryGrowMaxSizeInPlace(ROUND_UP(d, wasm::PageSize));
-        }
-#endif
-    }
-
-#undef ROUND_UP
-
-    // ObjT::createFromNewRawBuffer assumes ownership of |buffer| even in case
-    // of failure.
-    ObjT* object = ObjT::createFromNewRawBuffer(cx, buffer, initialSize);
-    if (!object) {
-        return false;
-    }
-
-    maybeSharedObject.set(object);
-
-    // See MaximumLiveMappedBuffers comment above.
-    if (liveBufferCount > StartSyncFullGCAtLiveBufferCount) {
-        JS::PrepareForFullGC(cx);
-        JS::NonIncrementalGC(cx, GC_NORMAL, JS::gcreason::TOO_MUCH_WASM_MEMORY);
-        allocatedSinceLastTrigger = 0;
-    } else if (liveBufferCount > StartTriggeringAtLiveBufferCount) {
-        allocatedSinceLastTrigger++;
-        if (allocatedSinceLastTrigger > AllocatedBuffersPerTrigger) {
-            Unused << cx->runtime()->gc.triggerGC(JS::gcreason::TOO_MUCH_WASM_MEMORY);
-            allocatedSinceLastTrigger = 0;
-        }
-    } else {
-        allocatedSinceLastTrigger = 0;
-    }
-
-    return true;
-}
-
-bool
-js::CreateWasmBuffer(JSContext* cx, const wasm::Limits& memory,
-                     MutableHandleArrayBufferObjectMaybeShared buffer)
-{
-    MOZ_ASSERT(memory.initial % wasm::PageSize == 0);
-    MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
-    MOZ_RELEASE_ASSERT((memory.initial / wasm::PageSize) <= wasm::MaxMemoryInitialPages);
-
-    // Prevent applications specifying a large max (like UINT32_MAX) from
-    // unintentially OOMing the browser on 32-bit: they just want "a lot of
-    // memory". Maintain the invariant that initialSize <= maxSize.
-
-    Maybe<uint32_t> maxSize = memory.maximum;
-    if (sizeof(void*) == 4 && maxSize) {
-        static const uint32_t OneGiB = 1 << 30;
-        uint32_t clamp = Max(OneGiB, memory.initial);
-        maxSize = Some(Min(clamp, *maxSize));
-    }
-
-#ifndef WASM_HUGE_MEMORY
-    if (sizeof(void*) == 8 && maxSize && maxSize.value() >= (UINT32_MAX - wasm::PageSize)) {
-        // On 64-bit platforms that don't define WASM_HUGE_MEMORY
-        // clamp maxSize to smaller value that satisfies the 32-bit invariants
-        // maxSize + wasm::PageSize < UINT32_MAX and maxSize % wasm::PageSize == 0
-        uint32_t clamp = (wasm::MaxMemoryMaximumPages - 2) * wasm::PageSize;
-        MOZ_ASSERT(clamp < UINT32_MAX);
-        MOZ_ASSERT(memory.initial <= clamp);
-        maxSize = Some(clamp);
-    }
-#endif
-
-    if (memory.shared == wasm::Shareable::True) {
-        if (!cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled()) {
-            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_NO_SHMEM_LINK);
-            return false;
-        }
-        return CreateBuffer<SharedArrayBufferObject, SharedArrayRawBuffer>(cx, memory.initial,
-                                                                           maxSize, buffer);
-    }
-    return CreateBuffer<ArrayBufferObject, WasmArrayRawBuffer>(cx, memory.initial, maxSize,
-                                                               buffer);
-}
-
-// Note this function can return false with or without an exception pending. The
-// asm.js caller checks cx->isExceptionPending before propagating failure.
-// Returning false without throwing means that asm.js linking will fail which
-// will recompile as non-asm.js.
-/* static */ bool
-ArrayBufferObject::prepareForAsmJS(JSContext* cx, Handle<ArrayBufferObject*> buffer)
-{
-    MOZ_ASSERT(buffer->byteLength() % wasm::PageSize == 0);
-    MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
-
-    if (buffer->forInlineTypedObject()) {
-        return false;
-    }
-
-    if (!buffer->isWasm() && buffer->isPreparedForAsmJS()) {
-        return true;
-    }
-
-    // Non-prepared-for-asm.js wasm buffers can be detached at any time.
-    if (buffer->isWasm()) {
-        return false;
-    }
-
-    if (!buffer->ownsData()) {
-        BufferContents contents = AllocateArrayBufferContents(cx, buffer->byteLength());
-        if (!contents) {
-            return false;
-        }
-        memcpy(contents.data(), buffer->dataPointer(), buffer->byteLength());
-        buffer->changeContents(cx, contents, OwnsData);
-    }
-
-    buffer->setIsPreparedForAsmJS();
-    return true;
-}
-
-ArrayBufferObject::BufferContents
-ArrayBufferObject::createMappedContents(int fd, size_t offset, size_t length)
-{
-    void* data = gc::AllocateMappedContent(fd, offset, length, ARRAY_BUFFER_ALIGNMENT);
-    return BufferContents::create<MAPPED>(data);
-}
-
-uint8_t*
-ArrayBufferObject::inlineDataPointer() const
-{
-    return static_cast<uint8_t*>(fixedData(JSCLASS_RESERVED_SLOTS(&class_)));
-}
-
-uint8_t*
-ArrayBufferObject::dataPointer() const
-{
-    return static_cast<uint8_t*>(getFixedSlot(DATA_SLOT).toPrivate());
-}
-
-SharedMem<uint8_t*>
-ArrayBufferObject::dataPointerShared() const
-{
-    return SharedMem<uint8_t*>::unshared(getFixedSlot(DATA_SLOT).toPrivate());
-}
-
-ArrayBufferObject::FreeInfo*
-ArrayBufferObject::freeInfo() const
-{
-    MOZ_ASSERT(isExternal());
-    return reinterpret_cast<FreeInfo*>(inlineDataPointer());
-}
-
-void
-ArrayBufferObject::releaseData(FreeOp* fop)
-{
-    MOZ_ASSERT(ownsData());
-
-    switch (bufferKind()) {
-      case PLAIN:
-        fop->free_(dataPointer());
-        break;
-      case MAPPED:
-        gc::DeallocateMappedContent(dataPointer(), byteLength());
-        break;
-      case WASM:
-        WasmArrayRawBuffer::Release(dataPointer());
-        break;
-      case EXTERNAL:
-        if (freeInfo()->freeFunc) {
-            // The analyzer can't know for sure whether the embedder-supplied
-            // free function will GC. We give the analyzer a hint here.
-            // (Doing a GC in the free function is considered a programmer
-            // error.)
-            JS::AutoSuppressGCAnalysis nogc;
-            freeInfo()->freeFunc(dataPointer(), freeInfo()->freeUserData);
-        }
-        break;
-    }
-}
-
-void
-ArrayBufferObject::setDataPointer(BufferContents contents, OwnsState ownsData)
-{
-    setFixedSlot(DATA_SLOT, PrivateValue(contents.data()));
-    setOwnsData(ownsData);
-    setFlags((flags() & ~KIND_MASK) | contents.kind());
-
-    if (isExternal()) {
-        auto info = freeInfo();
-        info->freeFunc = contents.freeFunc();
-        info->freeUserData = contents.freeUserData();
-    }
-}
-
-uint32_t
-ArrayBufferObject::byteLength() const
-{
-    return getFixedSlot(BYTE_LENGTH_SLOT).toInt32();
-}
-
-void
-ArrayBufferObject::setByteLength(uint32_t length)
-{
-    MOZ_ASSERT(length <= INT32_MAX);
-    setFixedSlot(BYTE_LENGTH_SLOT, Int32Value(length));
-}
-
-size_t
-ArrayBufferObject::wasmMappedSize() const
-{
-    if (isWasm()) {
-        return contents().wasmBuffer()->mappedSize();
-    }
-    return byteLength();
-}
-
-size_t
-js::WasmArrayBufferMappedSize(const ArrayBufferObjectMaybeShared* buf)
-{
-    if (buf->is<ArrayBufferObject>()) {
-        return buf->as<ArrayBufferObject>().wasmMappedSize();
-    }
-    return buf->as<SharedArrayBufferObject>().wasmMappedSize();
-}
-
-Maybe<uint32_t>
-ArrayBufferObject::wasmMaxSize() const
-{
-    if (isWasm()) {
-        return contents().wasmBuffer()->maxSize();
-    } else {
-        return Some<uint32_t>(byteLength());
-    }
-}
-
-Maybe<uint32_t>
-js::WasmArrayBufferMaxSize(const ArrayBufferObjectMaybeShared* buf)
-{
-    if (buf->is<ArrayBufferObject>()) {
-        return buf->as<ArrayBufferObject>().wasmMaxSize();
-    }
-    return buf->as<SharedArrayBufferObject>().wasmMaxSize();
-}
-
-/* static */ bool
-ArrayBufferObject::wasmGrowToSizeInPlace(uint32_t newSize,
-                                         HandleArrayBufferObject oldBuf,
-                                         MutableHandleArrayBufferObject newBuf,
-                                         JSContext* cx)
-{
-    // On failure, do not throw and ensure that the original buffer is
-    // unmodified and valid. After WasmArrayRawBuffer::growToSizeInPlace(), the
-    // wasm-visible length of the buffer has been increased so it must be the
-    // last fallible operation.
-
-    if (newSize > ArrayBufferObject::MaxBufferByteLength) {
-        return false;
-    }
-
-    newBuf.set(ArrayBufferObject::createEmpty(cx));
-    if (!newBuf) {
-        cx->clearPendingException();
-        return false;
-    }
-
-    if (!oldBuf->contents().wasmBuffer()->growToSizeInPlace(oldBuf->byteLength(), newSize)) {
-        return false;
-    }
-
-    bool hasStealableContents = true;
-    BufferContents contents = ArrayBufferObject::stealContents(cx, oldBuf, hasStealableContents);
-    MOZ_ASSERT(contents);
-    newBuf->initialize(newSize, contents, OwnsData);
-    return true;
-}
-
-#ifndef WASM_HUGE_MEMORY
-/* static */ bool
-ArrayBufferObject::wasmMovingGrowToSize(uint32_t newSize,
-                                        HandleArrayBufferObject oldBuf,
-                                        MutableHandleArrayBufferObject newBuf,
-                                        JSContext* cx)
-{
-    // On failure, do not throw and ensure that the original buffer is
-    // unmodified and valid.
-
-    if (newSize > ArrayBufferObject::MaxBufferByteLength) {
-        return false;
-    }
-
-    if (newSize <= oldBuf->wasmBoundsCheckLimit() ||
-        oldBuf->contents().wasmBuffer()->extendMappedSize(newSize))
-    {
-        return wasmGrowToSizeInPlace(newSize, oldBuf, newBuf, cx);
-    }
-
-    newBuf.set(ArrayBufferObject::createEmpty(cx));
-    if (!newBuf) {
-        cx->clearPendingException();
-        return false;
-    }
-
-    WasmArrayRawBuffer* newRawBuf = WasmArrayRawBuffer::Allocate(newSize, Nothing());
-    if (!newRawBuf) {
-        return false;
-    }
-    BufferContents contents = BufferContents::create<WASM>(newRawBuf->dataPointer());
-    newBuf->initialize(newSize, contents, OwnsData);
-
-    memcpy(newBuf->dataPointer(), oldBuf->dataPointer(), oldBuf->byteLength());
-    ArrayBufferObject::detach(cx, oldBuf, BufferContents::createPlain(nullptr));
-    return true;
-}
-
-uint32_t
-ArrayBufferObject::wasmBoundsCheckLimit() const
-{
-    if (isWasm()) {
-        return contents().wasmBuffer()->boundsCheckLimit();
-    }
-    return byteLength();
-}
-
-uint32_t
-ArrayBufferObjectMaybeShared::wasmBoundsCheckLimit() const
-{
-    if (is<ArrayBufferObject>()) {
-        return as<ArrayBufferObject>().wasmBoundsCheckLimit();
-    }
-    return as<SharedArrayBufferObject>().wasmBoundsCheckLimit();
-}
-#else
-uint32_t
-ArrayBufferObject::wasmBoundsCheckLimit() const
-{
-    return byteLength();
-}
-
-uint32_t
-ArrayBufferObjectMaybeShared::wasmBoundsCheckLimit() const
-{
-    return byteLength();
-}
-#endif
-
-uint32_t
-ArrayBufferObject::flags() const
-{
-    return uint32_t(getFixedSlot(FLAGS_SLOT).toInt32());
-}
-
-void
-ArrayBufferObject::setFlags(uint32_t flags)
-{
-    setFixedSlot(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);
-
-    // 24.1.1.1, step 3 (Inlined 6.2.6.1 CreateByteDataBlock, step 2).
-    // Refuse to allocate too large buffers, currently limited to ~2 GiB.
-    if (nbytes > INT32_MAX) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
-        return nullptr;
-    }
-
-    // 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().
-    size_t reservedSlots = JSCLASS_RESERVED_SLOTS(&class_);
-
-    size_t nslots = reservedSlots;
-    bool allocated = false;
-    if (contents) {
-        if (ownsState == OwnsData) {
-            if (contents.kind() == EXTERNAL) {
-                // Store the FreeInfo in the inline data slots so that we
-                // don't use up slots for it in non-refcounted array buffers.
-                size_t freeInfoSlots = JS_HOWMANY(sizeof(FreeInfo), sizeof(Value));
-                MOZ_ASSERT(reservedSlots + freeInfoSlots <= NativeObject::MAX_FIXED_SLOTS,
-                           "FreeInfo must fit in inline slots");
-                nslots += freeInfoSlots;
-            } else {
-                // The ABO is taking ownership, so account the bytes against
-                // the zone.
-                size_t nAllocated = nbytes;
-                if (contents.kind() == MAPPED) {
-                    nAllocated = JS_ROUNDUP(nbytes, js::gc::SystemPageSize());
-                }
-                cx->updateMallocCounter(nAllocated);
-            }
-        }
-    } else {
-        MOZ_ASSERT(ownsState == OwnsData);
-        size_t usableSlots = NativeObject::MAX_FIXED_SLOTS - reservedSlots;
-        if (nbytes <= usableSlots * sizeof(Value)) {
-            int newSlots = JS_HOWMANY(nbytes, sizeof(Value));
-            MOZ_ASSERT(int(nbytes) <= newSlots * int(sizeof(Value)));
-            nslots = reservedSlots + newSlots;
-            contents = BufferContents::createPlain(nullptr);
-        } else {
-            contents = AllocateArrayBufferContents(cx, nbytes);
-            if (!contents) {
-                return nullptr;
-            }
-            allocated = true;
-        }
-    }
-
-    MOZ_ASSERT(!(class_.flags & JSCLASS_HAS_PRIVATE));
-    gc::AllocKind allocKind = gc::GetGCObjectKind(nslots);
-
-    AutoSetNewObjectMetadata metadata(cx);
-    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));
-
-    if (!contents) {
-        void* data = obj->inlineDataPointer();
-        memset(data, 0, nbytes);
-        obj->initialize(nbytes, BufferContents::createPlain(data), DoesntOwnData);
-    } else {
-        obj->initialize(nbytes, contents, ownsState);
-    }
-
-    return obj;
-}
-
-ArrayBufferObject*
-ArrayBufferObject::create(JSContext* cx, uint32_t nbytes,
-                          HandleObject proto /* = nullptr */)
-{
-    return create(cx, nbytes, BufferContents::createPlain(nullptr),
-                  OwnsState::OwnsData, proto);
-}
-
-ArrayBufferObject*
-ArrayBufferObject::createEmpty(JSContext* cx)
-{
-    AutoSetNewObjectMetadata metadata(cx);
-    ArrayBufferObject* obj = NewBuiltinClassInstance<ArrayBufferObject>(cx);
-    if (!obj) {
-        return nullptr;
-    }
-
-    obj->setByteLength(0);
-    obj->setFlags(0);
-    obj->setFirstView(nullptr);
-    obj->setDataPointer(BufferContents::createPlain(nullptr), DoesntOwnData);
-
-    return obj;
-}
-
-ArrayBufferObject*
-ArrayBufferObject::createFromNewRawBuffer(JSContext* cx, WasmArrayRawBuffer* buffer,
-                                          uint32_t initialSize)
-{
-    AutoSetNewObjectMetadata metadata(cx);
-    ArrayBufferObject* obj = NewBuiltinClassInstance<ArrayBufferObject>(cx);
-    if (!obj) {
-        WasmArrayRawBuffer::Release(buffer->dataPointer());
-        return nullptr;
-    }
-
-    obj->setByteLength(initialSize);
-    obj->setFlags(0);
-    obj->setFirstView(nullptr);
-
-    auto contents = BufferContents::create<WASM>(buffer->dataPointer());
-    obj->setDataPointer(contents, OwnsData);
-
-    cx->updateMallocCounter(initialSize);
-
-    return obj;
-}
-
-/* static */ ArrayBufferObject::BufferContents
-ArrayBufferObject::externalizeContents(JSContext* cx, Handle<ArrayBufferObject*> buffer,
-                                       bool hasStealableContents)
-{
-    MOZ_ASSERT(buffer->isPlain(), "Only support doing this on plain ABOs");
-    MOZ_ASSERT(!buffer->isDetached(), "must have contents to externalize");
-    MOZ_ASSERT_IF(hasStealableContents, buffer->hasStealableContents());
-
-    BufferContents contents = buffer->contents();
-
-    if (hasStealableContents) {
-        buffer->setOwnsData(DoesntOwnData);
-        return contents;
-    }
-
-    // Create a new chunk of memory to return since we cannot steal the
-    // existing contents away from the buffer.
-    BufferContents newContents = AllocateArrayBufferContents(cx, buffer->byteLength());
-    if (!newContents) {
-        return BufferContents::createPlain(nullptr);
-    }
-    memcpy(newContents.data(), contents.data(), buffer->byteLength());
-    buffer->changeContents(cx, newContents, DoesntOwnData);
-
-    return newContents;
-}
-
-/* static */ ArrayBufferObject::BufferContents
-ArrayBufferObject::stealContents(JSContext* cx, Handle<ArrayBufferObject*> buffer,
-                                 bool hasStealableContents)
-{
-    // While wasm buffers cannot generally be transferred by content, the
-    // stealContents() is used internally by the impl of memory growth.
-    MOZ_ASSERT_IF(hasStealableContents, buffer->hasStealableContents() ||
-                                        (buffer->isWasm() && !buffer->isPreparedForAsmJS()));
-    cx->check(buffer);
-
-    BufferContents oldContents = buffer->contents();
-
-    if (hasStealableContents) {
-        // Return the old contents and reset the detached buffer's data
-        // pointer. This pointer should never be accessed.
-        auto newContents = BufferContents::createPlain(nullptr);
-        buffer->setOwnsData(DoesntOwnData); // Do not free the stolen data.
-        ArrayBufferObject::detach(cx, buffer, newContents);
-        buffer->setOwnsData(DoesntOwnData); // Do not free the nullptr.
-        return oldContents;
-    }
-
-    // Create a new chunk of memory to return since we cannot steal the
-    // existing contents away from the buffer.
-    BufferContents contentsCopy = AllocateArrayBufferContents(cx, buffer->byteLength());
-    if (!contentsCopy) {
-        return BufferContents::createPlain(nullptr);
-    }
-
-    if (buffer->byteLength() > 0) {
-        memcpy(contentsCopy.data(), oldContents.data(), buffer->byteLength());
-    }
-    ArrayBufferObject::detach(cx, buffer, oldContents);
-    return contentsCopy;
-}
-
-/* static */ void
-ArrayBufferObject::addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf mallocSizeOf,
-                                          JS::ClassInfo* info)
-{
-    ArrayBufferObject& buffer = AsArrayBuffer(obj);
-
-    if (!buffer.ownsData()) {
-        return;
-    }
-
-    switch (buffer.bufferKind()) {
-      case PLAIN:
-        if (buffer.isPreparedForAsmJS()) {
-            info->objectsMallocHeapElementsAsmJS += mallocSizeOf(buffer.dataPointer());
-        } else {
-            info->objectsMallocHeapElementsNormal += mallocSizeOf(buffer.dataPointer());
-        }
-        break;
-      case MAPPED:
-        info->objectsNonHeapElementsNormal += buffer.byteLength();
-        break;
-      case WASM:
-        info->objectsNonHeapElementsWasm += buffer.byteLength();
-        MOZ_ASSERT(buffer.wasmMappedSize() >= buffer.byteLength());
-        info->wasmGuardPages += buffer.wasmMappedSize() - buffer.byteLength();
-        break;
-      case KIND_MASK:
-        MOZ_CRASH("bad bufferKind()");
-    }
-}
-
-/* static */ void
-ArrayBufferObject::finalize(FreeOp* fop, JSObject* obj)
-{
-    ArrayBufferObject& buffer = obj->as<ArrayBufferObject>();
-
-    if (buffer.ownsData()) {
-        buffer.releaseData(fop);
-    }
-}
-
-/* static */ void
-ArrayBufferObject::copyData(Handle<ArrayBufferObject*> toBuffer, uint32_t toIndex,
-                            Handle<ArrayBufferObject*> fromBuffer, uint32_t fromIndex,
-                            uint32_t count)
-{
-    MOZ_ASSERT(toBuffer->byteLength() >= count);
-    MOZ_ASSERT(toBuffer->byteLength() >= toIndex + count);
-    MOZ_ASSERT(fromBuffer->byteLength() >= fromIndex);
-    MOZ_ASSERT(fromBuffer->byteLength() >= fromIndex + count);
-
-    memcpy(toBuffer->dataPointer() + toIndex, fromBuffer->dataPointer() + fromIndex, count);
-}
-
-/* static */ void
-ArrayBufferObject::trace(JSTracer* trc, JSObject* obj)
-{
-    // If this buffer is associated with an inline typed object,
-    // fix up the data pointer if the typed object was moved.
-    ArrayBufferObject& buf = obj->as<ArrayBufferObject>();
-
-    if (!buf.forInlineTypedObject()) {
-        return;
-    }
-
-    JSObject* view = MaybeForwarded(buf.firstView());
-    MOZ_ASSERT(view && view->is<InlineTransparentTypedObject>());
-
-    TraceManuallyBarrieredEdge(trc, &view, "array buffer inline typed object owner");
-    buf.setFixedSlot(DATA_SLOT,
-                     PrivateValue(view->as<InlineTransparentTypedObject>().inlineTypedMem()));
-}
-
-/* static */ size_t
-ArrayBufferObject::objectMoved(JSObject* obj, JSObject* old)
-{
-    ArrayBufferObject& dst = obj->as<ArrayBufferObject>();
-    const ArrayBufferObject& src = old->as<ArrayBufferObject>();
-
-    // Fix up possible inline data pointer.
-    if (src.hasInlineData()) {
-        dst.setFixedSlot(DATA_SLOT, PrivateValue(dst.inlineDataPointer()));
-    }
-
-    return 0;
-}
-
-ArrayBufferViewObject*
-ArrayBufferObject::firstView()
-{
-    return getFixedSlot(FIRST_VIEW_SLOT).isObject()
-        ? static_cast<ArrayBufferViewObject*>(&getFixedSlot(FIRST_VIEW_SLOT).toObject())
-        : nullptr;
-}
-
-void
-ArrayBufferObject::setFirstView(ArrayBufferViewObject* view)
-{
-    setFixedSlot(FIRST_VIEW_SLOT, ObjectOrNullValue(view));
-}
-
-bool
-ArrayBufferObject::addView(JSContext* cx, JSObject* viewArg)
-{
-    // 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);
-
-    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)
-{
-    // 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);
-
-    if (p) {
-        ViewVector& views = p->value();
-        MOZ_ASSERT(!views.empty());
-
-        if (addToNursery) {
-            // Only add the entry to |nurseryKeys| if it isn't already there.
-            if (views.length() >= VIEW_LIST_MAX_LENGTH) {
-                // To avoid quadratic blowup, skip the loop below if we end up
-                // adding enormous numbers of views for the same object.
-                nurseryKeysValid = false;
-            } else {
-                for (size_t i = 0; i < views.length(); i++) {
-                    if (gc::IsInsideNursery(views[i])) {
-                        addToNursery = false;
-                        break;
-                    }
-                }
-            }
-        }
-
-        if (!views.append(view)) {
-            ReportOutOfMemory(cx);
-            return false;
-        }
-    } else {
-        if (!map.add(p, buffer, ViewVector())) {
-            ReportOutOfMemory(cx);
-            return false;
-        }
-        // ViewVector has one inline element, so the first insertion is
-        // guaranteed to succeed.
-        MOZ_ALWAYS_TRUE(p->value().append(view));
-    }
-
-    if (addToNursery && !nurseryKeys.append(buffer)) {
-        nurseryKeysValid = false;
-    }
-
-    return true;
-}
-
-InnerViewTable::ViewVector*
-InnerViewTable::maybeViewsUnbarriered(ArrayBufferObject* buffer)
-{
-    Map::Ptr p = map.lookup(buffer);
-    if (p) {
-        return &p->value();
-    }
-    return nullptr;
-}
-
-void
-InnerViewTable::removeViews(ArrayBufferObject* buffer)
-{
-    Map::Ptr p = map.lookup(buffer);
-    MOZ_ASSERT(p);
-
-    map.remove(p);
-}
-
-/* static */ bool
-InnerViewTable::sweepEntry(JSObject** pkey, ViewVector& views)
-{
-    if (IsAboutToBeFinalizedUnbarriered(pkey)) {
-        return true;
-    }
-
-    MOZ_ASSERT(!views.empty());
-    size_t i = 0;
-    while (i < views.length()) {
-        if (IsAboutToBeFinalizedUnbarriered(&views[i])) {
-            // If the current element is garbage then remove it from the
-            // vector by moving the last one into its place.
-            views[i] = views.back();
-            views.popBack();
-        } else {
-            i++;
-        }
-    }
-
-    return views.empty();
-}
-
-void
-InnerViewTable::sweep()
-{
-    MOZ_ASSERT(nurseryKeys.empty());
-    map.sweep();
-}
-
-void
-InnerViewTable::sweepAfterMinorGC()
-{
-    MOZ_ASSERT(needsSweepAfterMinorGC());
-
-    if (nurseryKeysValid) {
-        for (size_t i = 0; i < nurseryKeys.length(); i++) {
-            JSObject* buffer = MaybeForwarded(nurseryKeys[i]);
-            Map::Ptr p = map.lookup(buffer);
-            if (!p) {
-                continue;
-            }
-
-            if (sweepEntry(&p->mutableKey(), p->value())) {
-                map.remove(buffer);
-            }
-        }
-        nurseryKeys.clear();
-    } else {
-        // Do the required sweeping by looking at every map entry.
-        nurseryKeys.clear();
-        sweep();
-
-        nurseryKeysValid = true;
-    }
-}
-
-size_t
-InnerViewTable::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
-{
-    size_t vectorSize = 0;
-    for (Map::Enum e(map); !e.empty(); e.popFront()) {
-        vectorSize += e.front().value().sizeOfExcludingThis(mallocSizeOf);
-    }
-
-    return vectorSize
-         + map.shallowSizeOfExcludingThis(mallocSizeOf)
-         + nurseryKeys.sizeOfExcludingThis(mallocSizeOf);
-}
-
-/*
- * ArrayBufferViewObject
- */
-
-/*
  * This method is used to trace TypedArrayObjects and DataViewObjects. We need
  * a custom tracer to move the object's data pointer if its owner was moved and
  * stores its data inline.
  */
 /* static */ void
 ArrayBufferViewObject::trace(JSTracer* trc, JSObject* objArg)
 {
     NativeObject* obj = &objArg->as<NativeObject>();
@@ -1720,23 +74,16 @@ ArrayBufferViewObject::trace(JSTracer* t
 
 template <>
 bool
 JSObject::is<js::ArrayBufferViewObject>() const
 {
     return is<DataViewObject>() || is<TypedArrayObject>();
 }
 
-template <>
-bool
-JSObject::is<js::ArrayBufferObjectMaybeShared>() const
-{
-    return is<ArrayBufferObject>() || is<SharedArrayBufferObject>();
-}
-
 void
 ArrayBufferViewObject::notifyBufferDetached(JSContext* cx, void* newData)
 {
     if (isSharedMemory()) {
         return;
     }
 
     MOZ_ASSERT(!isSharedMemory());
@@ -1796,263 +143,16 @@ JS_FRIEND_API(JSObject*)
 js::UnwrapArrayBufferView(JSObject* obj)
 {
     if (JSObject* unwrapped = CheckedUnwrap(obj)) {
         return unwrapped->is<ArrayBufferViewObject>() ? unwrapped : nullptr;
     }
     return nullptr;
 }
 
-JS_FRIEND_API(uint32_t)
-JS_GetArrayBufferByteLength(JSObject* obj)
-{
-    obj = CheckedUnwrap(obj);
-    return obj ? AsArrayBuffer(obj).byteLength() : 0;
-}
-
-JS_FRIEND_API(uint8_t*)
-JS_GetArrayBufferData(JSObject* obj, bool* isSharedMemory, const JS::AutoRequireNoGC&)
-{
-    obj = CheckedUnwrap(obj);
-    if (!obj) {
-        return nullptr;
-    }
-    if (!IsArrayBuffer(obj)) {
-        return nullptr;
-    }
-    *isSharedMemory = false;
-    return AsArrayBuffer(obj).dataPointer();
-}
-
-JS_FRIEND_API(bool)
-JS_DetachArrayBuffer(JSContext* cx, HandleObject obj)
-{
-    AssertHeapIsIdle();
-    CHECK_THREAD(cx);
-    cx->check(obj);
-
-    if (!obj->is<ArrayBufferObject>()) {
-        JS_ReportErrorASCII(cx, "ArrayBuffer object required");
-        return false;
-    }
-
-    Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
-
-    if (buffer->isWasm() || buffer->isPreparedForAsmJS()) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_NO_TRANSFER);
-        return false;
-    }
-
-    ArrayBufferObject::BufferContents newContents =
-        buffer->hasStealableContents() ? ArrayBufferObject::BufferContents::createPlain(nullptr)
-                                       : buffer->contents();
-
-    ArrayBufferObject::detach(cx, buffer, newContents);
-
-    return true;
-}
-
-JS_FRIEND_API(bool)
-JS_IsDetachedArrayBufferObject(JSObject* obj)
-{
-    obj = CheckedUnwrap(obj);
-    if (!obj) {
-        return false;
-    }
-
-    return obj->is<ArrayBufferObject>() && obj->as<ArrayBufferObject>().isDetached();
-}
-
-JS_FRIEND_API(JSObject*)
-JS_NewArrayBuffer(JSContext* cx, uint32_t nbytes)
-{
-    AssertHeapIsIdle();
-    CHECK_THREAD(cx);
-    MOZ_ASSERT(nbytes <= INT32_MAX);
-    return ArrayBufferObject::create(cx, nbytes);
-}
-
-JS_PUBLIC_API(JSObject*)
-JS_NewArrayBufferWithContents(JSContext* cx, size_t nbytes, void* data)
-{
-    AssertHeapIsIdle();
-    CHECK_THREAD(cx);
-    MOZ_ASSERT_IF(!data, nbytes == 0);
-
-    ArrayBufferObject::BufferContents contents =
-        ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(data);
-    return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData,
-                                     /* proto = */ nullptr, TenuredObject);
-}
-
-JS_PUBLIC_API(JSObject*)
-JS_NewExternalArrayBuffer(JSContext* cx, size_t nbytes, void* data,
-                          JS::BufferContentsFreeFunc freeFunc, void* freeUserData)
-{
-    AssertHeapIsIdle();
-    CHECK_THREAD(cx);
-
-    MOZ_ASSERT(data);
-    MOZ_ASSERT(nbytes > 0);
-
-    ArrayBufferObject::BufferContents contents =
-        ArrayBufferObject::BufferContents::createExternal(data, freeFunc, freeUserData);
-    return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData,
-                                     /* proto = */ nullptr, TenuredObject);
-}
-
-JS_PUBLIC_API(JSObject*)
-JS_NewArrayBufferWithExternalContents(JSContext* cx, size_t nbytes, void* data)
-{
-    AssertHeapIsIdle();
-    CHECK_THREAD(cx);
-    MOZ_ASSERT_IF(!data, nbytes == 0);
-    ArrayBufferObject::BufferContents contents =
-        ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(data);
-    return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::DoesntOwnData,
-                                     /* proto = */ nullptr, TenuredObject);
-}
-
-JS_FRIEND_API(bool)
-JS_IsArrayBufferObject(JSObject* obj)
-{
-    obj = CheckedUnwrap(obj);
-    return obj && obj->is<ArrayBufferObject>();
-}
-
-JS_FRIEND_API(bool)
-JS_ArrayBufferHasData(JSObject* obj)
-{
-    return CheckedUnwrap(obj)->as<ArrayBufferObject>().hasData();
-}
-
-JS_FRIEND_API(JSObject*)
-js::UnwrapArrayBuffer(JSObject* obj)
-{
-    if (JSObject* unwrapped = CheckedUnwrap(obj)) {
-        return unwrapped->is<ArrayBufferObject>() ? unwrapped : nullptr;
-    }
-    return nullptr;
-}
-
-JS_FRIEND_API(JSObject*)
-js::UnwrapSharedArrayBuffer(JSObject* obj)
-{
-    if (JSObject* unwrapped = CheckedUnwrap(obj)) {
-        return unwrapped->is<SharedArrayBufferObject>() ? unwrapped : nullptr;
-    }
-    return nullptr;
-}
-
-JS_PUBLIC_API(void*)
-JS_ExternalizeArrayBufferContents(JSContext* cx, HandleObject obj)
-{
-    AssertHeapIsIdle();
-    CHECK_THREAD(cx);
-    cx->check(obj);
-
-    if (!obj->is<ArrayBufferObject>()) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
-        return nullptr;
-    }
-
-    Handle<ArrayBufferObject*> buffer = obj.as<ArrayBufferObject>();
-    if (!buffer->isPlain()) {
-        // This operation isn't supported on mapped or wsm ArrayBufferObjects.
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
-        return nullptr;
-    }
-    if (buffer->isDetached()) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
-        return nullptr;
-    }
-
-    // The caller assumes that a plain malloc'd buffer is returned.
-    // hasStealableContents is true for mapped buffers, so we must additionally
-    // require that the buffer is plain. In the future, we could consider
-    // returning something that handles releasing the memory.
-    bool hasStealableContents = buffer->hasStealableContents();
-
-    return ArrayBufferObject::externalizeContents(cx, buffer, hasStealableContents).data();
-}
-
-JS_PUBLIC_API(void*)
-JS_StealArrayBufferContents(JSContext* cx, HandleObject objArg)
-{
-    AssertHeapIsIdle();
-    CHECK_THREAD(cx);
-    cx->check(objArg);
-
-    JSObject* obj = CheckedUnwrap(objArg);
-    if (!obj) {
-        return nullptr;
-    }
-
-    if (!obj->is<ArrayBufferObject>()) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
-        return nullptr;
-    }
-
-    Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
-    if (buffer->isDetached()) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
-        return nullptr;
-    }
-
-    if (buffer->isWasm() || buffer->isPreparedForAsmJS()) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_NO_TRANSFER);
-        return nullptr;
-    }
-
-    // The caller assumes that a plain malloc'd buffer is returned.
-    // hasStealableContents is true for mapped buffers, so we must additionally
-    // require that the buffer is plain. In the future, we could consider
-    // returning something that handles releasing the memory.
-    bool hasStealableContents = buffer->hasStealableContents() && buffer->isPlain();
-
-    AutoRealm ar(cx, buffer);
-    return ArrayBufferObject::stealContents(cx, buffer, hasStealableContents).data();
-}
-
-JS_PUBLIC_API(JSObject*)
-JS_NewMappedArrayBufferWithContents(JSContext* cx, size_t nbytes, void* data)
-{
-    AssertHeapIsIdle();
-    CHECK_THREAD(cx);
-
-    MOZ_ASSERT(data);
-    ArrayBufferObject::BufferContents contents =
-        ArrayBufferObject::BufferContents::create<ArrayBufferObject::MAPPED>(data);
-    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();
-}
-
-JS_PUBLIC_API(void)
-JS_ReleaseMappedArrayBufferContents(void* contents, size_t length)
-{
-    gc::DeallocateMappedContent(contents, length);
-}
-
-JS_FRIEND_API(bool)
-JS_IsMappedArrayBufferObject(JSObject* obj)
-{
-    obj = CheckedUnwrap(obj);
-    if (!obj) {
-        return false;
-    }
-
-    return obj->is<ArrayBufferObject>() && obj->as<ArrayBufferObject>().isMapped();
-}
-
 JS_FRIEND_API(void*)
 JS_GetArrayBufferViewData(JSObject* obj, bool* isSharedMemory, const JS::AutoRequireNoGC&)
 {
     obj = CheckedUnwrap(obj);
     if (!obj) {
         return nullptr;
     }
 
@@ -2128,33 +228,8 @@ js::GetArrayBufferViewLengthAndData(JSOb
               ? obj->as<DataViewObject>().byteLength()
               : obj->as<TypedArrayObject>().byteLength();
 
     ArrayBufferViewObject& view = obj->as<ArrayBufferViewObject>();
     *isSharedMemory = view.isSharedMemory();
     *data = static_cast<uint8_t*>(
             view.dataPointerEither().unwrap(/*safe - caller sees isShared flag*/));
 }
-
-JS_FRIEND_API(JSObject*)
-JS_GetObjectAsArrayBuffer(JSObject* obj, uint32_t* length, uint8_t** data)
-{
-    if (!(obj = CheckedUnwrap(obj))) {
-        return nullptr;
-    }
-    if (!IsArrayBuffer(obj)) {
-        return nullptr;
-    }
-
-    *length = AsArrayBuffer(obj).byteLength();
-    *data = AsArrayBuffer(obj).dataPointer();
-
-    return obj;
-}
-
-JS_FRIEND_API(void)
-js::GetArrayBufferLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data)
-{
-    MOZ_ASSERT(IsArrayBuffer(obj));
-    *length = AsArrayBuffer(obj).byteLength();
-    *data = AsArrayBuffer(obj).dataPointer();
-    *isSharedMemory = false;
-}
copy from js/src/vm/ArrayBufferObject.h
copy to js/src/vm/ArrayBufferViewObject.h
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferViewObject.h
@@ -1,467 +1,30 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef vm_ArrayBufferObject_h
-#define vm_ArrayBufferObject_h
-
-#include "mozilla/Maybe.h"
+#ifndef vm_ArrayBufferViewObject_h
+#define vm_ArrayBufferViewObject_h
 
 #include "builtin/TypedObjectConstants.h"
-#include "js/GCHashTable.h"
-#include "vm/JSObject.h"
-#include "vm/Runtime.h"
+#include "vm/ArrayBufferObject.h"
+#include "vm/NativeObject.h"
+#include "vm/SharedArrayObject.h"
 #include "vm/SharedMem.h"
-#include "wasm/WasmTypes.h"
 
 namespace js {
 
-class ArrayBufferViewObject;
-class WasmArrayRawBuffer;
-
-// Create a new mapping of size `mappedSize` with an initially committed prefix
-// of size `initialCommittedSize`.  Both arguments denote bytes and must be
-// multiples of the page size, with `initialCommittedSize` <= `mappedSize`.
-// Returns nullptr on failure.
-void* MapBufferMemory(size_t mappedSize, size_t initialCommittedSize);
-
-// Commit additional memory in an existing mapping.  `dataEnd` must be the
-// correct value for the end of the existing committed area, and `delta` must be
-// a byte amount to grow the mapping by, and must be a multiple of the page
-// size.  Returns false on failure.
-bool CommitBufferMemory(void* dataEnd, uint32_t delta);
-
-#ifndef WASM_HUGE_MEMORY
-// Extend an existing mapping by adding uncommited pages to it.  `dataStart`
-// must be the pointer to the start of the existing mapping, `mappedSize` the
-// size of the existing mapping, and `newMappedSize` the size of the extended
-// mapping (sizes in bytes), with `mappedSize` <= `newMappedSize`.  Both sizes
-// must be divisible by the page size.  Returns false on failure.
-bool ExtendBufferMapping(void* dataStart, size_t mappedSize, size_t newMappedSize);
-#endif
-
-// Remove an existing mapping.  `dataStart` must be the pointer to the start of
-// the mapping, and `mappedSize` the size of that mapping.
-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.
-//
-//
-// - JSObject
-//   - 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
-// separated completely.
-//
-// Most APIs will only accept ArrayBufferObject.  ArrayBufferObjectMaybeShared
-// exists as a join point to allow APIs that can take or use either, notably AsmJS.
-//
-// In contrast with the separation of ArrayBufferObject and
-// SharedArrayBufferObject, the TypedArray types can map either.
-//
-// The possible data ownership and reference relationships with ArrayBuffers
-// and related classes are enumerated below. These are the possible locations
-// for typed data:
-//
-// (1) malloc'ed or mmap'ed data owned by an ArrayBufferObject.
-// (2) Data allocated inline with an ArrayBufferObject.
-// (3) Data allocated inline with a TypedArrayObject.
-// (4) Data allocated inline with an InlineTypedObject.
-//
-// An ArrayBufferObject may point to any of these sources of data, except (3).
-// All array buffer views may point to any of these sources of data, except
-// that (3) may only be pointed to by the typed array the data is inline with.
-//
-// During a minor GC, (3) and (4) may move. During a compacting GC, (2), (3),
-// and (4) may move.
-
-class ArrayBufferObjectMaybeShared;
-
-mozilla::Maybe<uint32_t> WasmArrayBufferMaxSize(const ArrayBufferObjectMaybeShared* buf);
-size_t WasmArrayBufferMappedSize(const ArrayBufferObjectMaybeShared* buf);
-
-class ArrayBufferObjectMaybeShared : public NativeObject
-{
-  public:
-    inline uint32_t byteLength() const;
-    inline bool isDetached() const;
-    inline SharedMem<uint8_t*> dataPointerEither();
-
-    // WebAssembly support:
-    // Note: the eventual goal is to remove this from ArrayBuffer and have
-    // (Shared)ArrayBuffers alias memory owned by some wasm::Memory object.
-
-    mozilla::Maybe<uint32_t> wasmMaxSize() const {
-        return WasmArrayBufferMaxSize(this);
-    }
-    size_t wasmMappedSize() const {
-        return WasmArrayBufferMappedSize(this);
-    }
-    uint32_t wasmBoundsCheckLimit() const;
-
-    inline bool isPreparedForAsmJS() const;
-    inline bool isWasm() const;
-};
-
-typedef Rooted<ArrayBufferObjectMaybeShared*> RootedArrayBufferObjectMaybeShared;
-typedef Handle<ArrayBufferObjectMaybeShared*> HandleArrayBufferObjectMaybeShared;
-typedef MutableHandle<ArrayBufferObjectMaybeShared*> MutableHandleArrayBufferObjectMaybeShared;
-
-/*
- * ArrayBufferObject
- *
- * This class holds the underlying raw buffer that the various ArrayBufferViews
- * (eg DataViewObject, the TypedArrays, TypedObjects) access. It can be created
- * explicitly and used to construct an ArrayBufferView, or can be created
- * lazily when it is first accessed for a TypedArrayObject or TypedObject that
- * doesn't have an explicit buffer.
- *
- * ArrayBufferObject (or really the underlying memory) /is not racy/: the
- * memory is private to a single worker.
- */
-class ArrayBufferObject : public ArrayBufferObjectMaybeShared
-{
-    static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
-    static bool fun_slice_impl(JSContext* cx, const CallArgs& args);
-
-  public:
-    static const uint8_t DATA_SLOT = 0;
-    static const uint8_t BYTE_LENGTH_SLOT = 1;
-    static const uint8_t FIRST_VIEW_SLOT = 2;
-    static const uint8_t FLAGS_SLOT = 3;
-
-    static const uint8_t RESERVED_SLOTS = 4;
-
-    static const size_t ARRAY_BUFFER_ALIGNMENT = 8;
-
-    static_assert(FLAGS_SLOT == JS_ARRAYBUFFER_FLAGS_SLOT,
-                  "self-hosted code with burned-in constants must get the "
-                  "right flags slot");
-
-    // The length of an ArrayBuffer or SharedArrayBuffer can be at most
-    // INT32_MAX, and much code must change if this changes.
-
-    static const size_t MaxBufferByteLength = INT32_MAX;
-
-  public:
-
-    enum OwnsState {
-        DoesntOwnData = 0,
-        OwnsData = 1,
-    };
-
-    enum BufferKind {
-        PLAIN               = 0, // malloced or inline data
-        WASM                = 1,
-        MAPPED              = 2,
-        EXTERNAL            = 3,
-
-        KIND_MASK           = 0x3
-    };
-
-  protected:
-
-    enum ArrayBufferFlags {
-        // The flags also store the BufferKind
-        BUFFER_KIND_MASK    = BufferKind::KIND_MASK,
-
-        DETACHED            = 0x4,
-
-        // The dataPointer() is owned by this buffer and should be released
-        // when no longer in use. Releasing the pointer may be done by freeing,
-        // invoking a free callback function, or unmapping, as determined by the
-        // buffer's other flags.
-        //
-        // Array buffers which do not own their data include buffers that
-        // allocate their data inline, and buffers that are created lazily for
-        // typed objects with inline storage, in which case the buffer points
-        // directly to the typed object's storage.
-        OWNS_DATA           = 0x8,
-
-        // This array buffer was created lazily for a typed object with inline
-        // data. This implies both that the typed object owns the buffer's data
-        // and that the list of views sharing this buffer's data might be
-        // incomplete. Any missing views will be typed objects.
-        FOR_INLINE_TYPED_OBJECT = 0x10,
-
-        // Views of this buffer might include typed objects.
-        TYPED_OBJECT_VIEWS  = 0x20,
-
-        // This PLAIN or WASM buffer has been prepared for asm.js and cannot
-        // henceforth be transferred/detached.
-        FOR_ASMJS           = 0x40
-    };
-
-    static_assert(JS_ARRAYBUFFER_DETACHED_FLAG == DETACHED,
-                  "self-hosted code with burned-in constants must use the "
-                  "correct DETACHED bit value");
-  public:
-
-    class BufferContents {
-        uint8_t* data_;
-        BufferKind kind_;
-        JS::BufferContentsFreeFunc free_;
-        void* freeUserData_;
-
-        friend class ArrayBufferObject;
-
-        BufferContents(uint8_t* data, BufferKind kind,
-                       JS::BufferContentsFreeFunc freeFunc = nullptr,
-                       void* freeUserData = nullptr)
-        : data_(data), kind_(kind), free_(freeFunc), freeUserData_(freeUserData)
-        {
-            MOZ_ASSERT((kind_ & ~KIND_MASK) == 0);
-            MOZ_ASSERT_IF(free_ || freeUserData_, kind_ == EXTERNAL);
-
-            // It is the caller's responsibility to ensure that the
-            // BufferContents does not outlive the data.
-        }
-
-      public:
-
-        template<BufferKind Kind>
-        static BufferContents create(void* data)
-        {
-            return BufferContents(static_cast<uint8_t*>(data), Kind);
-        }
-
-        static BufferContents createPlain(void* data)
-        {
-            return BufferContents(static_cast<uint8_t*>(data), PLAIN);
-        }
-
-        static BufferContents createExternal(void* data, JS::BufferContentsFreeFunc freeFunc,
-                                             void* freeUserData = nullptr)
-        {
-            return BufferContents(static_cast<uint8_t*>(data), EXTERNAL, freeFunc, freeUserData);
-        }
-
-        uint8_t* data() const { return data_; }
-        BufferKind kind() const { return kind_; }
-        JS::BufferContentsFreeFunc freeFunc() const { return free_; }
-        void* freeUserData() const { return freeUserData_; }
-
-        explicit operator bool() const { return data_ != nullptr; }
-        WasmArrayRawBuffer* wasmBuffer() const;
-    };
-
-    static const Class class_;
-    static const Class protoClass_;
-
-    static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
-
-    static bool fun_slice(JSContext* cx, unsigned argc, Value* vp);
-
-    static bool fun_isView(JSContext* cx, unsigned argc, Value* vp);
-
-    static bool fun_species(JSContext* cx, unsigned argc, Value* vp);
-
-    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);
-
-    // Create an ArrayBufferObject that is safely finalizable and can later be
-    // initialize()d to become a real, content-visible ArrayBufferObject.
-    static ArrayBufferObject* createEmpty(JSContext* cx);
-
-    // Create an ArrayBufferObject using the provided buffer and size.  Assumes
-    // ownership of |buffer| even in case of failure, i.e. on failure |buffer|
-    // is deallocated.
-    static ArrayBufferObject*
-    createFromNewRawBuffer(JSContext* cx, WasmArrayRawBuffer* buffer, uint32_t initialSize);
-
-    static void copyData(Handle<ArrayBufferObject*> toBuffer, uint32_t toIndex,
-                         Handle<ArrayBufferObject*> fromBuffer, uint32_t fromIndex,
-                         uint32_t count);
-
-    static void trace(JSTracer* trc, JSObject* obj);
-    static size_t objectMoved(JSObject* obj, JSObject* old);
-
-    static BufferContents externalizeContents(JSContext* cx,
-                                              Handle<ArrayBufferObject*> buffer,
-                                              bool hasStealableContents);
-    static BufferContents stealContents(JSContext* cx,
-                                        Handle<ArrayBufferObject*> buffer,
-                                        bool hasStealableContents);
-
-    bool hasStealableContents() const {
-        // Inline elements strictly adhere to the corresponding buffer.
-        return ownsData() && !isPreparedForAsmJS() && !isWasm();
-    }
-
-    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();
-
-    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);
-
-    uint8_t* inlineDataPointer() const;
-
-    struct FreeInfo {
-        JS::BufferContentsFreeFunc freeFunc;
-        void* freeUserData;
-    };
-    FreeInfo* freeInfo() const;
-
-  public:
-    uint8_t* dataPointer() const;
-    SharedMem<uint8_t*> dataPointerShared() const;
-    uint32_t byteLength() const;
-
-    BufferContents contents() const {
-        if (isExternal()) {
-            return BufferContents(dataPointer(), EXTERNAL, freeInfo()->freeFunc,
-                                  freeInfo()->freeUserData);
-        }
-        return BufferContents(dataPointer(), bufferKind());
-    }
-    bool hasInlineData() const {
-        return dataPointer() == inlineDataPointer();
-    }
-
-    void releaseData(FreeOp* fop);
-
-    /*
-     * Check if the arrayBuffer contains any data. This will return false for
-     * ArrayBuffer.prototype and detached ArrayBuffers.
-     */
-    bool hasData() const {
-        return getClass() == &class_;
-    }
-
-    BufferKind bufferKind() const { return BufferKind(flags() & BUFFER_KIND_MASK); }
-    bool isPlain() const { return bufferKind() == PLAIN; }
-    bool isWasm() const { return bufferKind() == WASM; }
-    bool isMapped() const { return bufferKind() == MAPPED; }
-    bool isExternal() const { return bufferKind() == EXTERNAL; }
-    bool isDetached() const { return flags() & DETACHED; }
-    bool isPreparedForAsmJS() const { return flags() & FOR_ASMJS; }
-
-    // WebAssembly support:
-    static MOZ_MUST_USE bool prepareForAsmJS(JSContext* cx, Handle<ArrayBufferObject*> buffer);
-    size_t wasmMappedSize() const;
-    mozilla::Maybe<uint32_t> wasmMaxSize() const;
-    static MOZ_MUST_USE bool wasmGrowToSizeInPlace(uint32_t newSize,
-                                                   Handle<ArrayBufferObject*> oldBuf,
-                                                   MutableHandle<ArrayBufferObject*> newBuf,
-                                                   JSContext* cx);
-#ifndef WASM_HUGE_MEMORY
-    static MOZ_MUST_USE bool wasmMovingGrowToSize(uint32_t newSize,
-                                                  Handle<ArrayBufferObject*> oldBuf,
-                                                  MutableHandle<ArrayBufferObject*> newBuf,
-                                                  JSContext* cx);
-#endif
-    uint32_t wasmBoundsCheckLimit() const;
-
-    static void finalize(FreeOp* fop, JSObject* obj);
-
-    static BufferContents createMappedContents(int fd, size_t offset, size_t length);
-
-    static size_t offsetOfFlagsSlot() {
-        return getFixedSlotOffset(FLAGS_SLOT);
-    }
-    static size_t offsetOfDataSlot() {
-        return getFixedSlotOffset(DATA_SLOT);
-    }
-
-    void setForInlineTypedObject() {
-        setFlags(flags() | FOR_INLINE_TYPED_OBJECT);
-    }
-    void setHasTypedObjectViews() {
-        setFlags(flags() | TYPED_OBJECT_VIEWS);
-    }
-
-    bool forInlineTypedObject() const { return flags() & FOR_INLINE_TYPED_OBJECT; }
-
-  protected:
-    void setDataPointer(BufferContents contents, OwnsState ownsState);
-    void setByteLength(uint32_t length);
-
-    uint32_t flags() const;
-    void setFlags(uint32_t flags);
-
-    bool ownsData() const { return flags() & OWNS_DATA; }
-    void setOwnsData(OwnsState owns) {
-        setFlags(owns ? (flags() | OWNS_DATA) : (flags() & ~OWNS_DATA));
-    }
-
-    bool hasTypedObjectViews() const { return flags() & TYPED_OBJECT_VIEWS; }
-
-    void setIsDetached() { setFlags(flags() | DETACHED); }
-    void setIsPreparedForAsmJS() { setFlags(flags() | FOR_ASMJS); }
-
-    void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState) {
-        setByteLength(byteLength);
-        setFlags(0);
-        setFirstView(nullptr);
-        setDataPointer(contents, ownsState);
-    }
-};
-
-typedef Rooted<ArrayBufferObject*> RootedArrayBufferObject;
-typedef Handle<ArrayBufferObject*> HandleArrayBufferObject;
-typedef MutableHandle<ArrayBufferObject*> MutableHandleArrayBufferObject;
-
-bool CreateWasmBuffer(JSContext* cx, const wasm::Limits& memory,
-                      MutableHandleArrayBufferObjectMaybeShared buffer);
-
 /*
  * ArrayBufferViewObject
  *
- * Common definitions shared by all array buffer views.
+ * Common base class for all array buffer views (DataViewObject and
+ * TypedArrayObject).
  */
 
 class ArrayBufferViewObject : public NativeObject
 {
   public:
     // Underlying (Shared)ArrayBufferObject.
     static constexpr size_t BUFFER_SLOT = 0;
     static_assert(BUFFER_SLOT == JS_TYPEDARRAYLAYOUT_BUFFER_SLOT,
@@ -547,19 +110,34 @@ class ArrayBufferViewObject : public Nat
     ArrayBufferObject* bufferUnshared() const {
         MOZ_ASSERT(!isSharedMemory());
         JSObject* obj = bufferObject();
         if (!obj) {
             return nullptr;
         }
         return &obj->as<ArrayBufferObject>();
     }
-
-    inline SharedArrayBufferObject* bufferShared() const;
-    inline ArrayBufferObjectMaybeShared* bufferEither() const;
+    SharedArrayBufferObject* bufferShared() const {
+        MOZ_ASSERT(isSharedMemory());
+        JSObject* obj = bufferObject();
+        if (!obj) {
+            return nullptr;
+        }
+        return &obj->as<SharedArrayBufferObject>();
+    }
+    ArrayBufferObjectMaybeShared* bufferEither() const {
+        JSObject* obj = bufferObject();
+        if (!obj) {
+            return nullptr;
+        }
+        if (isSharedMemory()) {
+            return &obj->as<SharedArrayBufferObject>();
+        }
+        return &obj->as<ArrayBufferObject>();
+    }
 
     bool hasDetachedBuffer() const {
         // Shared buffers can't be detached.
         if (isSharedMemory()) {
             return false;
         }
 
         // A typed array with a null buffer has never had its buffer exposed to
@@ -570,209 +148,15 @@ class ArrayBufferViewObject : public Nat
         }
 
         return buffer->isDetached();
     }
 
     static void trace(JSTracer* trc, JSObject* obj);
 };
 
-bool
-ToClampedIndex(JSContext* cx, HandleValue v, uint32_t length, uint32_t* out);
-
-/*
- * Tests for ArrayBufferObject, like obj->is<ArrayBufferObject>().
- */
-bool IsArrayBuffer(HandleValue v);
-bool IsArrayBuffer(HandleObject obj);
-bool IsArrayBuffer(JSObject* obj);
-ArrayBufferObject& AsArrayBuffer(HandleObject obj);
-ArrayBufferObject& AsArrayBuffer(JSObject* obj);
-
-/*
- * Ditto for ArrayBufferObjectMaybeShared.
- */
-bool IsArrayBufferMaybeShared(HandleValue v);
-bool IsArrayBufferMaybeShared(HandleObject obj);
-bool IsArrayBufferMaybeShared(JSObject* obj);
-ArrayBufferObjectMaybeShared& AsArrayBufferMaybeShared(HandleObject obj);
-ArrayBufferObjectMaybeShared& AsArrayBufferMaybeShared(JSObject* obj);
-
-extern uint32_t JS_FASTCALL
-ClampDoubleToUint8(const double x);
-
-struct uint8_clamped {
-    uint8_t val;
-
-    uint8_clamped() = default;
-    uint8_clamped(const uint8_clamped& other) = default;
-
-    // invoke our assignment helpers for constructor conversion
-    explicit uint8_clamped(uint8_t x)    { *this = x; }
-    explicit uint8_clamped(uint16_t x)   { *this = x; }
-    explicit uint8_clamped(uint32_t x)   { *this = x; }
-    explicit uint8_clamped(int8_t x)     { *this = x; }
-    explicit uint8_clamped(int16_t x)    { *this = x; }
-    explicit uint8_clamped(int32_t x)    { *this = x; }
-    explicit uint8_clamped(double x)     { *this = x; }
-
-    uint8_clamped& operator=(const uint8_clamped& x) = default;
-
-    uint8_clamped& operator=(uint8_t x) {
-        val = x;
-        return *this;
-    }
-
-    uint8_clamped& operator=(uint16_t x) {
-        val = (x > 255) ? 255 : uint8_t(x);
-        return *this;
-    }
-
-    uint8_clamped& operator=(uint32_t x) {
-        val = (x > 255) ? 255 : uint8_t(x);
-        return *this;
-    }
-
-    uint8_clamped& operator=(int8_t x) {
-        val = (x >= 0) ? uint8_t(x) : 0;
-        return *this;
-    }
-
-    uint8_clamped& operator=(int16_t x) {
-        val = (x >= 0)
-              ? ((x < 255)
-                 ? uint8_t(x)
-                 : 255)
-              : 0;
-        return *this;
-    }
-
-    uint8_clamped& operator=(int32_t x) {
-        val = (x >= 0)
-              ? ((x < 255)
-                 ? uint8_t(x)
-                 : 255)
-              : 0;
-        return *this;
-    }
-
-    uint8_clamped& operator=(const double x) {
-        val = uint8_t(ClampDoubleToUint8(x));
-        return *this;
-    }
-
-    operator uint8_t() const {
-        return val;
-    }
-
-    void staticAsserts() {
-        static_assert(sizeof(uint8_clamped) == 1,
-                      "uint8_clamped must be layout-compatible with uint8_t");
-    }
-};
-
-/* Note that we can't use std::numeric_limits here due to uint8_clamped. */
-template<typename T> inline bool TypeIsFloatingPoint() { return false; }
-template<> inline bool TypeIsFloatingPoint<float>() { return true; }
-template<> inline bool TypeIsFloatingPoint<double>() { return true; }
-
-template<typename T> inline bool TypeIsUnsigned() { return false; }
-template<> inline bool TypeIsUnsigned<uint8_t>() { return true; }
-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;
-
-    friend class ArrayBufferObject;
-
-  private:
-    struct MapGCPolicy {
-        static bool needsSweep(JSObject** key, ViewVector* value) {
-            return InnerViewTable::sweepEntry(key, *value);
-        }
-    };
-
-    // This key is a raw pointer and not a ReadBarriered because the post-
-    // barrier would hold nursery-allocated entries live unconditionally. It is
-    // a very common pattern in low-level and performance-oriented JavaScript
-    // to create hundreds or thousands of very short lived temporary views on a
-    // larger buffer; having to tenured all of these would be a catastrophic
-    // performance regression. Thus, it is vital that nursery pointers in this
-    // map not be held live. Special support is required in the minor GC,
-    // implemented in sweepAfterMinorGC.
-    typedef GCHashMap<JSObject*,
-                      ViewVector,
-                      MovableCellHasher<JSObject*>,
-                      SystemAllocPolicy,
-                      MapGCPolicy> Map;
-
-    // For all objects sharing their storage with some other view, this maps
-    // the object to the list of such views. All entries in this map are weak.
-    Map map;
-
-    // List of keys from innerViews where either the source or at least one
-    // target is in the nursery. The raw pointer to a JSObject is allowed here
-    // because this vector is cleared after every minor collection. Users in
-    // sweepAfterMinorCollection must be careful to use MaybeForwarded before
-    // touching these pointers.
-    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);
-    ViewVector* maybeViewsUnbarriered(ArrayBufferObject* obj);
-    void removeViews(ArrayBufferObject* obj);
-
-  public:
-    InnerViewTable()
-      : nurseryKeysValid(true)
-    {}
-
-    // Remove references to dead objects in the table and update table entries
-    // to reflect moved objects.
-    void sweep();
-    void sweepAfterMinorGC();
-
-    bool needsSweep() const {
-        return map.needsSweep();
-    }
-
-    bool needsSweepAfterMinorGC() const {
-        return !nurseryKeys.empty() || !nurseryKeysValid;
-    }
-
-    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
-};
-
-template <typename Wrapper>
-class MutableWrappedPtrOperations<InnerViewTable, Wrapper>
-    : public WrappedPtrOperations<InnerViewTable, Wrapper>
-{
-    InnerViewTable& table() {
-        return static_cast<Wrapper*>(this)->get();
-    }
-
-  public:
-    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
-        return table().sizeOfExcludingThis(mallocSizeOf);
-    }
-};
-
 } // namespace js
 
 template <>
 bool
 JSObject::is<js::ArrayBufferViewObject>() const;
 
-template <>
-bool
-JSObject::is<js::ArrayBufferObjectMaybeShared>() const;
-
-#endif // vm_ArrayBufferObject_h
+#endif // vm_ArrayBufferViewObject_h
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -8,16 +8,17 @@
 #define vm_TypedArrayObject_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/TextUtils.h"
 
 #include "gc/Barrier.h"
 #include "js/Class.h"
 #include "vm/ArrayBufferObject.h"
+#include "vm/ArrayBufferViewObject.h"
 #include "vm/JSObject.h"
 #include "vm/SharedArrayObject.h"
 
 #define JS_FOR_EACH_TYPED_ARRAY(macro) \
     macro(int8_t, Int8) \
     macro(uint8_t, Uint8) \
     macro(int16_t, Int16) \
     macro(uint16_t, Uint16) \