summaryrefslogtreecommitdiffstats
path: root/js/src/vm/ArrayBufferViewObject.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm/ArrayBufferViewObject.h')
-rw-r--r--js/src/vm/ArrayBufferViewObject.h215
1 files changed, 215 insertions, 0 deletions
diff --git a/js/src/vm/ArrayBufferViewObject.h b/js/src/vm/ArrayBufferViewObject.h
new file mode 100644
index 0000000000..c1c1ccac88
--- /dev/null
+++ b/js/src/vm/ArrayBufferViewObject.h
@@ -0,0 +1,215 @@
+/* -*- 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 {
+
+class JS_PUBLIC_API GenericPrinter;
+class JSONPrinter;
+
+/*
+ * ArrayBufferViewObject
+ *
+ * Common base class for all array buffer views (DataViewObject and
+ * TypedArrayObject).
+ */
+
+class ArrayBufferViewObject : public NativeObject {
+ public:
+ // Underlying (Shared)ArrayBufferObject. ObjectValue if there is
+ // a buffer. Otherwise, the buffer is implicit because the data
+ // is held inline, and the buffer slot will store the pinned status
+ // (FalseValue or TrueValue).
+ 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* ensureBufferObject(
+ JSContext* cx, Handle<ArrayBufferViewObject*> obj);
+
+ void notifyBufferDetached();
+ void notifyBufferMoved(uint8_t* srcBufStart, uint8_t* dstBufStart);
+
+ 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().isBoolean() ? nullptr : 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();
+ }
+
+ bool hasResizableBuffer() const;
+
+ bool isLengthPinned() const {
+ Value buffer = bufferValue();
+ if (buffer.isBoolean()) {
+ return buffer.toBoolean();
+ }
+ if (isSharedMemory()) {
+ return true;
+ }
+ return bufferUnshared()->isLengthPinned();
+ }
+
+ bool pinLength(bool pin) {
+ if (isSharedMemory()) {
+ // Always pinned, cannot change.
+ return false;
+ }
+
+ if (hasBuffer()) {
+ return bufferUnshared()->pinLength(pin);
+ }
+
+ // No ArrayBuffer (data is inline in the view). bufferValue() is a
+ // BooleanValue saying whether the length is currently pinned.
+ MOZ_ASSERT(bufferValue().isBoolean());
+
+ bool wasPinned = bufferValue().toBoolean();
+ if (wasPinned == pin) {
+ return false;
+ }
+
+ setFixedSlot(BUFFER_SLOT, JS::BooleanValue(pin));
+ return true;
+ }
+
+ static bool ensureNonInline(JSContext* cx,
+ JS::Handle<ArrayBufferViewObject*> view);
+
+ protected:
+ size_t byteOffset() const {
+ return size_t(getFixedSlot(BYTEOFFSET_SLOT).toPrivate());
+ }
+
+ public:
+ static void trace(JSTracer* trc, JSObject* obj);
+
+#if defined(DEBUG) || defined(JS_JITSPEW)
+ void dumpOwnFields(js::JSONPrinter& json) const;
+ void dumpOwnStringContent(js::GenericPrinter& out) const;
+#endif
+};
+
+} // namespace js
+
+template <>
+bool JSObject::is<js::ArrayBufferViewObject>() const;
+
+#endif // vm_ArrayBufferViewObject_h