diff options
Diffstat (limited to 'js/src/vm/ArrayBufferViewObject.h')
-rw-r--r-- | js/src/vm/ArrayBufferViewObject.h | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/js/src/vm/ArrayBufferViewObject.h b/js/src/vm/ArrayBufferViewObject.h new file mode 100644 index 0000000000..7d6a4b70bd --- /dev/null +++ b/js/src/vm/ArrayBufferViewObject.h @@ -0,0 +1,166 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * 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_ArrayBufferViewObject_h +#define vm_ArrayBufferViewObject_h + +#include "builtin/TypedArrayConstants.h" +#include "vm/ArrayBufferObject.h" +#include "vm/NativeObject.h" +#include "vm/SharedArrayObject.h" +#include "vm/SharedMem.h" + +namespace js { + +/* + * ArrayBufferViewObject + * + * 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, + "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; + + // Offset of view within underlying (Shared)ArrayBufferObject. + static constexpr size_t BYTEOFFSET_SLOT = 2; + + // Pointer to raw buffer memory. + static constexpr size_t DATA_SLOT = 3; + + static constexpr size_t RESERVED_SLOTS = 4; + +#ifdef DEBUG + static const uint8_t ZeroLengthArrayData = 0x4A; +#endif + + static constexpr int bufferOffset() { + return NativeObject::getFixedSlotOffset(BUFFER_SLOT); + } + static constexpr int lengthOffset() { + return NativeObject::getFixedSlotOffset(LENGTH_SLOT); + } + static constexpr int byteOffsetOffset() { + return NativeObject::getFixedSlotOffset(BYTEOFFSET_SLOT); + } + static constexpr int dataOffset() { + return NativeObject::getFixedSlotOffset(DATA_SLOT); + } + + private: + void* dataPointerEither_() const { + // Note, do not check whether shared or not + // Keep synced with js::Get<Type>ArrayLengthAndData in jsfriendapi.h! + return maybePtrFromReservedSlot<void>(DATA_SLOT); + } + + public: + [[nodiscard]] bool init(JSContext* cx, ArrayBufferObjectMaybeShared* buffer, + size_t byteOffset, size_t length, + uint32_t bytesPerElement); + + static ArrayBufferObjectMaybeShared* bufferObject( + JSContext* cx, Handle<ArrayBufferViewObject*> obj); + + void notifyBufferDetached(); + + 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. + void* data = viewData.unwrap(/*safe - see above*/); + initReservedSlot(DATA_SLOT, PrivateValue(data)); + } + + 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_(); + } + + Value bufferValue() const { return getFixedSlot(BUFFER_SLOT); } + bool hasBuffer() const { return bufferValue().isObject(); } + + ArrayBufferObject* bufferUnshared() const { + MOZ_ASSERT(!isSharedMemory()); + ArrayBufferObjectMaybeShared* obj = bufferEither(); + if (!obj) { + return nullptr; + } + return &obj->as<ArrayBufferObject>(); + } + SharedArrayBufferObject* bufferShared() const { + MOZ_ASSERT(isSharedMemory()); + ArrayBufferObjectMaybeShared* obj = bufferEither(); + if (!obj) { + return nullptr; + } + return &obj->as<SharedArrayBufferObject>(); + } + ArrayBufferObjectMaybeShared* bufferEither() const { + JSObject* obj = bufferValue().toObjectOrNull(); + if (!obj) { + return nullptr; + } + MOZ_ASSERT(isSharedMemory() ? obj->is<SharedArrayBufferObject>() + : obj->is<ArrayBufferObject>()); + return &obj->as<ArrayBufferObjectMaybeShared>(); + } + + 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(); + } + + size_t byteOffset() const { + return size_t(getFixedSlot(BYTEOFFSET_SLOT).toPrivate()); + } + + Value byteOffsetValue() const { + size_t offset = byteOffset(); + return NumberValue(offset); + } + + static void trace(JSTracer* trc, JSObject* obj); +}; + +} // namespace js + +template <> +bool JSObject::is<js::ArrayBufferViewObject>() const; + +#endif // vm_ArrayBufferViewObject_h |