Bug 1842773 - Part 2: Add "resizable" flag to ArrayBuffer objects. r=sfink
[gecko.git] / js / src / vm / ArrayBufferViewObject.h
blob5e077cda38752d4f61abca4065dbc9557b8dbf72
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"
16 namespace js {
19 * ArrayBufferViewObject
21 * Common base class for all array buffer views (DataViewObject and
22 * TypedArrayObject).
25 class ArrayBufferViewObject : public NativeObject {
26 public:
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 "
34 "right buffer slot");
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;
47 #ifdef DEBUG
48 static const uint8_t ZeroLengthArrayData = 0x4A;
49 #endif
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);
64 private:
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);
71 public:
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();
114 if (!obj) {
115 return nullptr;
117 return &obj->as<ArrayBufferObject>();
119 SharedArrayBufferObject* bufferShared() const {
120 MOZ_ASSERT(isSharedMemory());
121 ArrayBufferObjectMaybeShared* obj = bufferEither();
122 if (!obj) {
123 return nullptr;
125 return &obj->as<SharedArrayBufferObject>();
127 ArrayBufferObjectMaybeShared* bufferEither() const {
128 JSObject* obj =
129 bufferValue().isBoolean() ? nullptr : bufferValue().toObjectOrNull();
130 if (!obj) {
131 return nullptr;
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()) {
141 return false;
144 // A typed array with a null buffer has never had its buffer exposed to
145 // become detached.
146 ArrayBufferObject* buffer = bufferUnshared();
147 if (!buffer) {
148 return false;
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()) {
162 return true;
164 return bufferUnshared()->isLengthPinned();
167 bool pinLength(bool pin) {
168 if (isSharedMemory()) {
169 // Always pinned, cannot change.
170 return false;
173 if (hasBuffer()) {
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) {
183 return false;
186 setFixedSlot(BUFFER_SLOT, JS::BooleanValue(pin));
187 return true;
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);
205 } // namespace js
207 template <>
208 bool JSObject::is<js::ArrayBufferViewObject>() const;
210 #endif // vm_ArrayBufferViewObject_h