1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef vm_ArrayBufferViewObject_h
8 #define vm_ArrayBufferViewObject_h
10 #include "builtin/TypedArrayConstants.h"
11 #include "vm/ArrayBufferObject.h"
12 #include "vm/NativeObject.h"
13 #include "vm/SharedArrayObject.h"
14 #include "vm/SharedMem.h"
19 * ArrayBufferViewObject
21 * Common base class for all array buffer views (DataViewObject and
25 class ArrayBufferViewObject
: public NativeObject
{
27 // Underlying (Shared)ArrayBufferObject. ObjectValue if there is
28 // a buffer. Otherwise, the buffer is implicit because the data
29 // is held inline, and the buffer slot will store the pinned status
30 // (FalseValue or TrueValue).
31 static constexpr size_t BUFFER_SLOT
= 0;
32 static_assert(BUFFER_SLOT
== JS_TYPEDARRAYLAYOUT_BUFFER_SLOT
,
33 "self-hosted code with burned-in constants must get the "
36 // Slot containing length of the view in number of typed elements.
37 static constexpr size_t LENGTH_SLOT
= 1;
39 // Offset of view within underlying (Shared)ArrayBufferObject.
40 static constexpr size_t BYTEOFFSET_SLOT
= 2;
42 // Pointer to raw buffer memory.
43 static constexpr size_t DATA_SLOT
= 3;
45 static constexpr size_t RESERVED_SLOTS
= 4;
48 static const uint8_t ZeroLengthArrayData
= 0x4A;
51 static constexpr int bufferOffset() {
52 return NativeObject::getFixedSlotOffset(BUFFER_SLOT
);
54 static constexpr int lengthOffset() {
55 return NativeObject::getFixedSlotOffset(LENGTH_SLOT
);
57 static constexpr int byteOffsetOffset() {
58 return NativeObject::getFixedSlotOffset(BYTEOFFSET_SLOT
);
60 static constexpr int dataOffset() {
61 return NativeObject::getFixedSlotOffset(DATA_SLOT
);
65 void* dataPointerEither_() const {
66 // Note, do not check whether shared or not
67 // Keep synced with js::Get<Type>ArrayLengthAndData in jsfriendapi.h!
68 return maybePtrFromReservedSlot
<void>(DATA_SLOT
);
72 [[nodiscard
]] bool init(JSContext
* cx
, ArrayBufferObjectMaybeShared
* buffer
,
73 size_t byteOffset
, size_t length
,
74 uint32_t bytesPerElement
);
76 static ArrayBufferObjectMaybeShared
* ensureBufferObject(
77 JSContext
* cx
, Handle
<ArrayBufferViewObject
*> obj
);
79 void notifyBufferDetached();
80 void notifyBufferMoved(uint8_t* srcBufStart
, uint8_t* dstBufStart
);
82 void initDataPointer(SharedMem
<uint8_t*> viewData
) {
83 // Install a pointer to the buffer location that corresponds
84 // to offset zero within the typed array.
86 // The following unwrap is safe because the DATA_SLOT is
87 // accessed only from jitted code and from the
88 // dataPointerEither_() accessor above; in neither case does the
89 // raw pointer escape untagged into C++ code.
90 void* data
= viewData
.unwrap(/*safe - see above*/);
91 initReservedSlot(DATA_SLOT
, PrivateValue(data
));
94 SharedMem
<void*> dataPointerShared() const {
95 return SharedMem
<void*>::shared(dataPointerEither_());
97 SharedMem
<void*> dataPointerEither() const {
98 if (isSharedMemory()) {
99 return SharedMem
<void*>::shared(dataPointerEither_());
101 return SharedMem
<void*>::unshared(dataPointerEither_());
103 void* dataPointerUnshared() const {
104 MOZ_ASSERT(!isSharedMemory());
105 return dataPointerEither_();
108 Value
bufferValue() const { return getFixedSlot(BUFFER_SLOT
); }
109 bool hasBuffer() const { return bufferValue().isObject(); }
111 ArrayBufferObject
* bufferUnshared() const {
112 MOZ_ASSERT(!isSharedMemory());
113 ArrayBufferObjectMaybeShared
* obj
= bufferEither();
117 return &obj
->as
<ArrayBufferObject
>();
119 SharedArrayBufferObject
* bufferShared() const {
120 MOZ_ASSERT(isSharedMemory());
121 ArrayBufferObjectMaybeShared
* obj
= bufferEither();
125 return &obj
->as
<SharedArrayBufferObject
>();
127 ArrayBufferObjectMaybeShared
* bufferEither() const {
129 bufferValue().isBoolean() ? nullptr : bufferValue().toObjectOrNull();
133 MOZ_ASSERT(isSharedMemory() ? obj
->is
<SharedArrayBufferObject
>()
134 : obj
->is
<ArrayBufferObject
>());
135 return &obj
->as
<ArrayBufferObjectMaybeShared
>();
138 bool hasDetachedBuffer() const {
139 // Shared buffers can't be detached.
140 if (isSharedMemory()) {
144 // A typed array with a null buffer has never had its buffer exposed to
146 ArrayBufferObject
* buffer
= bufferUnshared();
151 return buffer
->isDetached();
154 bool hasResizableBuffer() const;
156 bool isLengthPinned() const {
157 Value buffer
= bufferValue();
158 if (buffer
.isBoolean()) {
159 return buffer
.toBoolean();
161 if (isSharedMemory()) {
164 return bufferUnshared()->isLengthPinned();
167 bool pinLength(bool pin
) {
168 if (isSharedMemory()) {
169 // Always pinned, cannot change.
174 return bufferUnshared()->pinLength(pin
);
177 // No ArrayBuffer (data is inline in the view). bufferValue() is a
178 // BooleanValue saying whether the length is currently pinned.
179 MOZ_ASSERT(bufferValue().isBoolean());
181 bool wasPinned
= bufferValue().toBoolean();
182 if (wasPinned
== pin
) {
186 setFixedSlot(BUFFER_SLOT
, JS::BooleanValue(pin
));
190 static bool ensureNonInline(JSContext
* cx
,
191 JS::Handle
<ArrayBufferViewObject
*> view
);
193 size_t byteOffset() const {
194 return size_t(getFixedSlot(BYTEOFFSET_SLOT
).toPrivate());
197 Value
byteOffsetValue() const {
198 size_t offset
= byteOffset();
199 return NumberValue(offset
);
202 static void trace(JSTracer
* trc
, JSObject
* obj
);
208 bool JSObject::is
<js::ArrayBufferViewObject
>() const;
210 #endif // vm_ArrayBufferViewObject_h