Bug 1081379 - change BufferKind from a bit field to a dense enum (r=sfink)
authorLuke Wagner <luke@mozilla.com>
Fri, 17 Oct 2014 00:15:29 -0500
changeset 211034 c837c78af266974cd5d2b09403553f27b6d667a3
parent 211033 6e17d46ddda46d459e04478e8a840fe876cdd2da
child 211035 ec90e1a7b632ce30ab74d20a48d75e3ce0ce155d
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerssfink
bugs1081379
milestone36.0a1
Bug 1081379 - change BufferKind from a bit field to a dense enum (r=sfink)
js/src/asmjs/AsmJSModule.cpp
js/src/shell/js.cpp
js/src/vm/ArrayBufferObject.cpp
js/src/vm/ArrayBufferObject.h
js/src/vm/StructuredClone.cpp
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -779,18 +779,17 @@ AsmJSModule::staticallyLink(ExclusiveCon
     }
 
     MOZ_ASSERT(isStaticallyLinked());
 }
 
 void
 AsmJSModule::initHeap(Handle<ArrayBufferObjectMaybeShared *> heap, JSContext *cx)
 {
-    MOZ_ASSERT_IF(heap->is<ArrayBufferObject>(),
-                  heap->as<ArrayBufferObject>().isAsmJSArrayBuffer());
+    MOZ_ASSERT_IF(heap->is<ArrayBufferObject>(), heap->as<ArrayBufferObject>().isAsmJS());
     MOZ_ASSERT(IsValidAsmJSHeapLength(heap->byteLength()));
     MOZ_ASSERT(dynamicallyLinked_);
     MOZ_ASSERT(!maybeHeap_);
 
     maybeHeap_ = heap;
     heapDatum() = heap->dataPointer();
 
 #if defined(JS_CODEGEN_X86)
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1062,17 +1062,17 @@ CacheEntry_getBytecode(HandleObject cach
 }
 
 static bool
 CacheEntry_setBytecode(JSContext *cx, HandleObject cache, uint8_t *buffer, uint32_t length)
 {
     MOZ_ASSERT(CacheEntry_isCacheEntry(cache));
 
     ArrayBufferObject::BufferContents contents =
-        ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN_BUFFER>(buffer);
+        ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(buffer);
     Rooted<ArrayBufferObject*> arrayBuffer(cx, ArrayBufferObject::create(cx, length, contents));
     if (!arrayBuffer)
         return false;
 
     SetReservedSlot(cache, CacheEntry_BYTECODE, OBJECT_TO_JSVAL(arrayBuffer));
     return true;
 }
 
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -269,34 +269,34 @@ ArrayBufferObject::class_constructor(JSC
 
 static ArrayBufferObject::BufferContents
 AllocateArrayBufferContents(JSContext *cx, uint32_t nbytes)
 {
     uint8_t *p = cx->runtime()->pod_callocCanGC<uint8_t>(nbytes);
     if (!p)
         js_ReportOutOfMemory(cx);
 
-    return ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN_BUFFER>(p);
+    return ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(p);
 }
 
 void
 ArrayBufferObject::neuterView(JSContext *cx, ArrayBufferViewObject *view,
                               BufferContents newContents)
 {
     view->neuter(newContents.data());
 
     // Notify compiled jit code that the base pointer has moved.
     MarkObjectStateChange(cx, view);
 }
 
 /* static */ bool
 ArrayBufferObject::neuter(JSContext *cx, Handle<ArrayBufferObject*> buffer,
                           BufferContents newContents)
 {
-    if (buffer->isAsmJSArrayBuffer() && !OnDetachAsmJSArrayBuffer(cx, buffer))
+    if (buffer->isAsmJS() && !OnDetachAsmJSArrayBuffer(cx, buffer))
         return false;
 
     // Neuter all views on the buffer, clear out the list of views and the
     // buffer's data.
 
     if (InnerViewTable::ViewVector *views = cx->compartment()->innerViews.maybeViewsUnbarriered(buffer)) {
         for (size_t i = 0; i < views->length(); i++)
             buffer->neuterView(cx, (*views)[i], newContents);
@@ -312,18 +312,16 @@ ArrayBufferObject::neuter(JSContext *cx,
     buffer->setByteLength(0);
     buffer->setIsNeutered();
     return true;
 }
 
 void
 ArrayBufferObject::setNewOwnedData(FreeOp* fop, BufferContents newContents)
 {
-    MOZ_ASSERT(!isAsmJSArrayBuffer());
-
     if (ownsData()) {
         MOZ_ASSERT(newContents.data() != dataPointer());
         releaseData(fop);
     }
 
     setDataPointer(newContents, OwnsData);
 }
 
@@ -360,50 +358,46 @@ ArrayBufferObject::changeContents(JSCont
     }
     if (firstView())
         changeViewContents(cx, firstView(), oldDataPointer, newContents);
 }
 
 /* static */ bool
 ArrayBufferObject::prepareForAsmJSNoSignals(JSContext *cx, Handle<ArrayBufferObject*> buffer)
 {
-    if (buffer->isAsmJSArrayBuffer())
-        return true;
-
     if (!buffer->ownsData()) {
         BufferContents contents = AllocateArrayBufferContents(cx, buffer->byteLength());
         if (!contents)
             return false;
         memcpy(contents.data(), buffer->dataPointer(), buffer->byteLength());
         buffer->changeContents(cx, contents);
     }
 
-    buffer->setIsAsmJSArrayBuffer();
+    buffer->setIsAsmJSMalloced();
     return true;
 }
 
-void
-ArrayBufferObject::releaseAsmJSArrayNoSignals(FreeOp *fop)
-{
-    MOZ_ASSERT(!(bufferKind() & MAPPED_BUFFER));
-    fop->free_(dataPointer());
-}
-
 #ifdef JS_CODEGEN_X64
 /* static */ bool
 ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer,
                                    bool usesSignalHandlers)
 {
     // If we can't use signal handlers, just do it like on other platforms.
     if (!usesSignalHandlers)
         return prepareForAsmJSNoSignals(cx, buffer);
 
-    if (buffer->isAsmJSArrayBuffer())
+    if (buffer->isAsmJSMapped())
         return true;
 
+    // This can't happen except via the shell toggling signals.enabled.
+    if (buffer->isAsmJSMalloced()) {
+        JS_ReportError(cx, "can't access same buffer with and without signals enabled");
+        return false;
+    }
+
     // Get the entire reserved region (with all pages inaccessible).
     void *data;
 # ifdef XP_WIN
     data = VirtualAlloc(nullptr, AsmJSMappedSize, MEM_RESERVE, PAGE_NOACCESS);
     if (!data)
         return false;
 # else
     data = MozTaggedAnonymousMmap(nullptr, AsmJSMappedSize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0, "asm-js-reserved");
@@ -431,80 +425,58 @@ ArrayBufferObject::prepareForAsmJS(JSCon
 #   endif
 # endif
 
     // Copy over the current contents of the typed array.
     memcpy(data, buffer->dataPointer(), buffer->byteLength());
 
     // Swap the new elements into the ArrayBufferObject. Mark the
     // ArrayBufferObject so we don't do this again.
-    BufferContents newContents = BufferContents::create<BufferKind(ASMJS_BUFFER|MAPPED_BUFFER)>(data);
+    BufferContents newContents = BufferContents::create<ASMJS_MAPPED>(data);
     buffer->changeContents(cx, newContents);
     MOZ_ASSERT(data == buffer->dataPointer());
 
     return true;
 }
 
-void
-ArrayBufferObject::releaseAsmJSArray(FreeOp *fop)
+static void
+ReleaseAsmJSMappedData(void *base)
 {
-    if (!(bufferKind() & MAPPED_BUFFER)) {
-        releaseAsmJSArrayNoSignals(fop);
-        return;
-    }
-
-    void *data = dataPointer();
-
-    MOZ_ASSERT(uintptr_t(data) % AsmJSPageSize == 0);
-# ifdef XP_WIN
-    VirtualFree(data, 0, MEM_RELEASE);
-# else
-    munmap(data, AsmJSMappedSize);
-#   if defined(MOZ_VALGRIND) && defined(VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE)
+    MOZ_ASSERT(uintptr_t(base) % AsmJSPageSize == 0);
+#ifdef XP_WIN
+    VirtualFree(base, 0, MEM_RELEASE);
+#else
+    munmap(base, AsmJSMappedSize);
+# if defined(MOZ_VALGRIND) && defined(VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE)
     // Tell Valgrind/Memcheck to recommence reporting accesses in the
     // previously-inaccessible region.
     if (AsmJSMappedSize > 0) {
-        VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(data, AsmJSMappedSize);
+        VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(base, AsmJSMappedSize);
     }
-#   endif
 # endif
+#endif
 }
+
 #else // JS_CODEGEN_X64
 bool
 ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer,
                                    bool usesSignalHandlers)
 {
     // Platforms other than x64 don't use signalling for bounds checking, so
     // just use the variant with no signals.
     MOZ_ASSERT(!usesSignalHandlers);
     return prepareForAsmJSNoSignals(cx, buffer);
 }
-
-void
-ArrayBufferObject::releaseAsmJSArray(FreeOp *fop)
-{
-    // See comment above.
-    releaseAsmJSArrayNoSignals(fop);
-}
 #endif
 
 ArrayBufferObject::BufferContents
 ArrayBufferObject::createMappedContents(int fd, size_t offset, size_t length)
 {
     void *data = AllocateMappedContent(fd, offset, length, ARRAY_BUFFER_ALIGNMENT);
-    return BufferContents::create<MAPPED_BUFFER>(data);
-}
-
-void
-ArrayBufferObject::releaseMappedArray()
-{
-    if(!isMappedArrayBuffer() || isNeutered())
-        return;
-
-    DeallocateMappedContent(dataPointer(), byteLength());
+    return BufferContents::create<MAPPED>(data);
 }
 
 uint8_t *
 ArrayBufferObject::inlineDataPointer() const
 {
     return static_cast<uint8_t *>(fixedData(JSCLASS_RESERVED_SLOTS(&class_)));
 }
 
@@ -514,23 +486,28 @@ ArrayBufferObject::dataPointer() const
     return static_cast<uint8_t *>(getSlot(DATA_SLOT).toPrivate());
 }
 
 void
 ArrayBufferObject::releaseData(FreeOp *fop)
 {
     MOZ_ASSERT(ownsData());
 
-    BufferKind bufkind = bufferKind();
-    if (bufkind & ASMJS_BUFFER)
-        releaseAsmJSArray(fop);
-    else if (bufkind & MAPPED_BUFFER)
-        releaseMappedArray();
-    else
+    switch (bufferKind()) {
+      case PLAIN:
+      case ASMJS_MALLOCED:
         fop->free_(dataPointer());
+        break;
+      case MAPPED:
+        DeallocateMappedContent(dataPointer(), byteLength());
+        break;
+      case ASMJS_MAPPED:
+        ReleaseAsmJSMappedData(dataPointer());
+        break;
+    }
 }
 
 void
 ArrayBufferObject::setDataPointer(BufferContents contents, OwnsState ownsData)
 {
     setSlot(DATA_SLOT, PrivateValue(contents.data()));
     setOwnsData(ownsData);
     setFlags((flags() & ~KIND_MASK) | contents.kind());
@@ -559,30 +536,30 @@ ArrayBufferObject::setFlags(uint32_t fla
 {
     setSlot(FLAGS_SLOT, Int32Value(flags));
 }
 
 ArrayBufferObject *
 ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, BufferContents contents,
                           NewObjectKind newKind /* = GenericObject */)
 {
-    MOZ_ASSERT_IF(contents.kind() & MAPPED_BUFFER, contents);
+    MOZ_ASSERT_IF(contents.kind() == MAPPED, contents);
 
     // If we need to allocate data, try to use a larger object size class so
     // that the array buffer's data can be allocated inline with the object.
     // The extra space will be left unused by the object's fixed slots and
     // available for the buffer's data, see NewObject().
     size_t reservedSlots = JSCLASS_RESERVED_SLOTS(&class_);
 
     size_t nslots = reservedSlots;
     bool allocated = false;
     if (contents) {
         // The ABO is taking ownership, so account the bytes against the zone.
         size_t nAllocated = nbytes;
-        if (contents.kind() & MAPPED_BUFFER)
+        if (contents.kind() == MAPPED)
             nAllocated = JS_ROUNDUP(nbytes, js::gc::SystemPageSize());
         cx->zone()->updateMallocCounter(nAllocated);
     } else {
         size_t usableSlots = NativeObject::MAX_FIXED_SLOTS - reservedSlots;
         if (nbytes <= usableSlots * sizeof(Value)) {
             int newSlots = (nbytes - 1) / sizeof(Value) + 1;
             MOZ_ASSERT(int(nbytes) <= newSlots * int(sizeof(Value)));
             nslots = reservedSlots + newSlots;
@@ -716,27 +693,29 @@ ArrayBufferObject::stealContents(JSConte
 ArrayBufferObject::addSizeOfExcludingThis(JSObject *obj, mozilla::MallocSizeOf mallocSizeOf,
                                           JS::ClassInfo *info)
 {
     ArrayBufferObject &buffer = AsArrayBuffer(obj);
 
     if (!buffer.ownsData())
         return;
 
-    if (MOZ_UNLIKELY(buffer.bufferKind() & ASMJS_BUFFER)) {
-        // On x64, ArrayBufferObject::prepareForAsmJS switches the
-        // ArrayBufferObject to use mmap'd storage.
-        if (buffer.bufferKind() & MAPPED_BUFFER)
-            info->objectsNonHeapElementsAsmJS += buffer.byteLength();
-        else
-            info->objectsMallocHeapElementsAsmJS += mallocSizeOf(buffer.dataPointer());
-    } else if (MOZ_UNLIKELY(buffer.bufferKind() & MAPPED_BUFFER)) {
+    switch (buffer.bufferKind()) {
+      case PLAIN:
+        info->objectsMallocHeapElementsNonAsmJS += mallocSizeOf(buffer.dataPointer());
+        break;
+      case MAPPED:
         info->objectsNonHeapElementsMapped += buffer.byteLength();
-    } else if (buffer.dataPointer()) {
-        info->objectsMallocHeapElementsNonAsmJS += mallocSizeOf(buffer.dataPointer());
+        break;
+      case ASMJS_MALLOCED:
+        info->objectsMallocHeapElementsAsmJS += mallocSizeOf(buffer.dataPointer());
+        break;
+      case ASMJS_MAPPED:
+        info->objectsNonHeapElementsAsmJS += buffer.byteLength();
+        break;
     }
 }
 
 /* static */ void
 ArrayBufferObject::finalize(FreeOp *fop, JSObject *obj)
 {
     ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
 
@@ -1003,17 +982,17 @@ ArrayBufferViewObject::bufferObject(JSCo
 }
 
 /* JS Friend API */
 
 JS_FRIEND_API(bool)
 JS_IsArrayBufferViewObject(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
-    return obj ? obj->is<ArrayBufferViewObject>() : false;
+    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;
@@ -1065,42 +1044,40 @@ JS_NeuterArrayBuffer(JSContext *cx, Hand
 
 JS_FRIEND_API(bool)
 JS_IsNeuteredArrayBufferObject(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return false;
 
-    return obj->is<ArrayBufferObject>()
-           ? obj->as<ArrayBufferObject>().isNeutered()
-           : false;
+    return obj->is<ArrayBufferObject>() && obj->as<ArrayBufferObject>().isNeutered();
 }
 
 JS_FRIEND_API(JSObject *)
 JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes)
 {
     MOZ_ASSERT(nbytes <= INT32_MAX);
     return ArrayBufferObject::create(cx, nbytes);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewArrayBufferWithContents(JSContext *cx, size_t nbytes, void *data)
 {
     MOZ_ASSERT(data);
     ArrayBufferObject::BufferContents contents =
-        ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN_BUFFER>(data);
+        ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(data);
     return ArrayBufferObject::create(cx, nbytes, contents, TenuredObject);
 }
 
 JS_FRIEND_API(bool)
 JS_IsArrayBufferObject(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
-    return obj ? obj->is<ArrayBufferObject>() : false;
+    return obj && obj->is<ArrayBufferObject>();
 }
 
 JS_FRIEND_API(bool)
 JS_ArrayBufferHasData(JSObject *obj)
 {
     return CheckedUnwrap(obj)->as<ArrayBufferObject>().hasData();
 }
 
@@ -1129,28 +1106,27 @@ JS_StealArrayBufferContents(JSContext *c
         JS_ReportErrorNumber(cx, js_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() &&
-                                buffer->bufferKind() == ArrayBufferObject::PLAIN_BUFFER;
+    bool hasStealableContents = buffer->hasStealableContents() && buffer->isPlain();
 
     return ArrayBufferObject::stealContents(cx, buffer, hasStealableContents).data();
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewMappedArrayBufferWithContents(JSContext *cx, size_t nbytes, void *data)
 {
     MOZ_ASSERT(data);
     ArrayBufferObject::BufferContents contents =
-        ArrayBufferObject::BufferContents::create<ArrayBufferObject::MAPPED_BUFFER>(data);
+        ArrayBufferObject::BufferContents::create<ArrayBufferObject::MAPPED>(data);
     return ArrayBufferObject::create(cx, nbytes, contents, TenuredObject);
 }
 
 JS_PUBLIC_API(void *)
 JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length)
 {
     return ArrayBufferObject::createMappedContents(fd, offset, length).data();
 }
@@ -1163,19 +1139,17 @@ JS_ReleaseMappedArrayBufferContents(void
 
 JS_FRIEND_API(bool)
 JS_IsMappedArrayBufferObject(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return false;
 
-    return obj->is<ArrayBufferObject>()
-           ? obj->as<ArrayBufferObject>().isMappedArrayBuffer()
-           : false;
+    return obj->is<ArrayBufferObject>() && obj->as<ArrayBufferObject>().isMapped();
 }
 
 JS_FRIEND_API(void *)
 JS_GetArrayBufferViewData(JSObject *obj, const JS::AutoCheckCannotGC&)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -100,29 +100,31 @@ class ArrayBufferObject : public ArrayBu
 
     static const uint8_t RESERVED_SLOTS = 4;
 
     static const size_t ARRAY_BUFFER_ALIGNMENT = 8;
 
   public:
 
     enum BufferKind {
-        PLAIN_BUFFER        =   0, // malloced or inline data
-        ASMJS_BUFFER        = 0x1,
-        MAPPED_BUFFER       = 0x2,
-        KIND_MASK           = ASMJS_BUFFER | MAPPED_BUFFER
+        PLAIN               = 0, // malloced or inline data
+        ASMJS_MALLOCED      = 1,
+        ASMJS_MAPPED        = 2,
+        MAPPED              = 3,
+
+        KIND_MASK           = 0x3
     };
 
   protected:
 
     enum ArrayBufferFlags {
         // The flags also store the BufferKind
         BUFFER_KIND_MASK    = BufferKind::KIND_MASK,
 
-        NEUTERED_BUFFER     = 0x4,
+        NEUTERED            = 0x4,
 
         // The dataPointer() is owned by this buffer and should be released
         // when no longer in use. Releasing the pointer may be done by either
         // freeing or unmapping it, and how to do this is determined by the
         // buffer's other flags.
         OWNS_DATA           = 0x8,
     };
 
@@ -146,17 +148,17 @@ class ArrayBufferObject : public ArrayBu
         template<BufferKind Kind>
         static BufferContents create(void *data)
         {
             return BufferContents(static_cast<uint8_t*>(data), Kind);
         }
 
         static BufferContents createUnowned(void *data)
         {
-            return BufferContents(static_cast<uint8_t*>(data), PLAIN_BUFFER);
+            return BufferContents(static_cast<uint8_t*>(data), PLAIN);
         }
 
         uint8_t *data() const { return data_; }
         BufferKind kind() const { return kind_; }
 
         operator ConvertibleToBool() const { return data_ ? &BufferContents::nonNull : nullptr; }
     };
 
@@ -200,17 +202,17 @@ class ArrayBufferObject : public ArrayBu
 
     bool hasStealableContents() const {
         // Inline elements strictly adhere to the corresponding buffer.
         if (!ownsData())
             return false;
 
         // asm.js buffer contents are transferred by copying, just like inline
         // elements.
-        if (isAsmJSArrayBuffer())
+        if (isAsmJS())
             return false;
 
         // Neutered contents aren't transferrable because we want a neutered
         // array's contents to be backed by zeroed memory equal in length to
         // the original buffer contents.  Transferring these contents would
         // allocate new ones based on the current byteLength, which is 0 for a
         // neutered array -- not the original byteLength.
         return !isNeutered();
@@ -266,36 +268,39 @@ class ArrayBufferObject : public ArrayBu
      * Check if the arrayBuffer contains any data. This will return false for
      * ArrayBuffer.prototype and neutered ArrayBuffers.
      */
     bool hasData() const {
         return getClass() == &class_;
     }
 
     BufferKind bufferKind() const { return BufferKind(flags() & BUFFER_KIND_MASK); }
-    bool isAsmJSArrayBuffer() const { return flags() & ASMJS_BUFFER; }
-    bool isMappedArrayBuffer() const { return flags() & MAPPED_BUFFER; }
-    bool isNeutered() const { return flags() & NEUTERED_BUFFER; }
+    bool isPlain() const { return bufferKind() == PLAIN; }
+    bool isAsmJSMapped() const { return bufferKind() == ASMJS_MAPPED; }
+    bool isAsmJSMalloced() const { return bufferKind() == ASMJS_MALLOCED; }
+    bool isAsmJS() const { return isAsmJSMapped() || isAsmJSMalloced(); }
+    bool isMapped() const { return bufferKind() == MAPPED; }
+    bool isNeutered() const { return flags() & NEUTERED; }
 
     static bool prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer,
                                 bool usesSignalHandlers);
     static bool prepareForAsmJSNoSignals(JSContext *cx, Handle<ArrayBufferObject*> buffer);
 
     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);
     }
 
-    static uint32_t neuteredFlag() { return NEUTERED_BUFFER; }
+    static uint32_t neuteredFlag() { return NEUTERED; }
 
   protected:
     enum OwnsState {
         DoesntOwnData = 0,
         OwnsData = 1,
     };
 
     void setDataPointer(BufferContents contents, OwnsState ownsState);
@@ -304,30 +309,25 @@ class ArrayBufferObject : public ArrayBu
     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));
     }
 
-    void setIsAsmJSArrayBuffer() { setFlags(flags() | ASMJS_BUFFER); }
-    void setIsMappedArrayBuffer() { setFlags(flags() | MAPPED_BUFFER); }
-    void setIsNeutered() { setFlags(flags() | NEUTERED_BUFFER); }
+    void setIsAsmJSMalloced() { setFlags((flags() & ~KIND_MASK) | ASMJS_MALLOCED); }
+    void setIsNeutered() { setFlags(flags() | NEUTERED); }
 
     void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState) {
         setByteLength(byteLength);
         setFlags(0);
         setFirstView(nullptr);
         setDataPointer(contents, ownsState);
     }
-
-    void releaseAsmJSArray(FreeOp *fop);
-    void releaseAsmJSArrayNoSignals(FreeOp *fop);
-    void releaseMappedArray();
 };
 
 /*
  * ArrayBufferViewObject
  *
  * Common definitions shared by all array buffer views.
  */
 
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1171,17 +1171,17 @@ JSStructuredCloneWriter::transferOwnersh
             size_t nbytes = arrayBuffer->byteLength();
             bool hasStealableContents = arrayBuffer->hasStealableContents();
             ArrayBufferObject::BufferContents bufContents =
                 ArrayBufferObject::stealContents(context(), arrayBuffer, hasStealableContents);
             if (!bufContents)
                 return false; // Destructor will clean up the already-transferred data.
             content = bufContents.data();
             tag = SCTAG_TRANSFER_MAP_ARRAY_BUFFER;
-            if (bufContents.kind() & ArrayBufferObject::MAPPED_BUFFER)
+            if (bufContents.kind() == ArrayBufferObject::MAPPED)
                 ownership = JS::SCTAG_TMO_MAPPED_DATA;
             else
                 ownership = JS::SCTAG_TMO_ALLOC_DATA;
             extraData = nbytes;
         } else if (ObjectClassIs(obj, ESClass_SharedArrayBuffer, context())) {
             Rooted<SharedArrayBufferObject *> sharedArrayBuffer(context(), &CheckedUnwrap(obj)->as<SharedArrayBufferObject>());
             SharedArrayRawBuffer *rawbuf = sharedArrayBuffer->rawBufferObject();