1 | // Copyright 2018 the V8 project authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #ifndef V8_OBJECTS_JS_ARRAY_BUFFER_H_ |
6 | #define V8_OBJECTS_JS_ARRAY_BUFFER_H_ |
7 | |
8 | #include "src/objects/js-objects.h" |
9 | |
10 | // Has to be the last include (doesn't have include guards): |
11 | #include "src/objects/object-macros.h" |
12 | |
13 | namespace v8 { |
14 | namespace internal { |
15 | |
16 | // Whether a JSArrayBuffer is a SharedArrayBuffer or not. |
17 | enum class SharedFlag : uint32_t { kNotShared, kShared }; |
18 | |
19 | class JSArrayBuffer : public JSObject { |
20 | public: |
21 | // The maximum length for JSArrayBuffer's supported by V8. |
22 | // On 32-bit architectures we limit this to 2GiB, so that |
23 | // we can continue to use CheckBounds with the Unsigned31 |
24 | // restriction for the length. |
25 | #if V8_HOST_ARCH_32_BIT |
26 | static constexpr size_t kMaxByteLength = kMaxInt; |
27 | #else |
28 | static constexpr size_t kMaxByteLength = kMaxSafeInteger; |
29 | #endif |
30 | |
31 | // [byte_length]: length in bytes |
32 | DECL_PRIMITIVE_ACCESSORS(byte_length, size_t) |
33 | |
34 | // [backing_store]: backing memory for this array |
35 | DECL_ACCESSORS(backing_store, void*) |
36 | |
37 | // For non-wasm, allocation_length and allocation_base are byte_length and |
38 | // backing_store, respectively. |
39 | inline size_t allocation_length() const; |
40 | inline void* allocation_base() const; |
41 | |
42 | // [bit_field]: boolean flags |
43 | DECL_PRIMITIVE_ACCESSORS(bit_field, uint32_t) |
44 | |
45 | // Clear uninitialized padding space. This ensures that the snapshot content |
46 | // is deterministic. Depending on the V8 build mode there could be no padding. |
47 | V8_INLINE void clear_padding(); |
48 | |
49 | // Bit positions for [bit_field]. |
50 | #define JS_ARRAY_BUFFER_BIT_FIELD_FIELDS(V, _) \ |
51 | V(IsExternalBit, bool, 1, _) \ |
52 | V(IsDetachableBit, bool, 1, _) \ |
53 | V(WasDetachedBit, bool, 1, _) \ |
54 | V(IsSharedBit, bool, 1, _) \ |
55 | V(IsWasmMemoryBit, bool, 1, _) |
56 | DEFINE_BIT_FIELDS(JS_ARRAY_BUFFER_BIT_FIELD_FIELDS) |
57 | #undef JS_ARRAY_BUFFER_BIT_FIELD_FIELDS |
58 | |
59 | // [is_external]: true indicates that the embedder is in charge of freeing the |
60 | // backing_store, while is_external == false means that v8 will free the |
61 | // memory block once all ArrayBuffers referencing it are collected by the GC. |
62 | DECL_BOOLEAN_ACCESSORS(is_external) |
63 | |
64 | // [is_detachable]: false indicates that this buffer cannot be detached. |
65 | DECL_BOOLEAN_ACCESSORS(is_detachable) |
66 | |
67 | // [was_detached]: true if the buffer was previously detached. |
68 | DECL_BOOLEAN_ACCESSORS(was_detached) |
69 | |
70 | // [is_shared]: tells whether this is an ArrayBuffer or a SharedArrayBuffer. |
71 | DECL_BOOLEAN_ACCESSORS(is_shared) |
72 | |
73 | // [is_wasm_memory]: whether the buffer is tracked by the WasmMemoryTracker. |
74 | DECL_BOOLEAN_ACCESSORS(is_wasm_memory) |
75 | |
76 | DECL_CAST(JSArrayBuffer) |
77 | |
78 | void Detach(); |
79 | |
80 | struct Allocation { |
81 | Allocation(void* allocation_base, size_t length, void* backing_store, |
82 | bool is_wasm_memory) |
83 | : allocation_base(allocation_base), |
84 | length(length), |
85 | backing_store(backing_store), |
86 | is_wasm_memory(is_wasm_memory) {} |
87 | |
88 | void* allocation_base; |
89 | size_t length; |
90 | void* backing_store; |
91 | bool is_wasm_memory; |
92 | }; |
93 | |
94 | V8_EXPORT_PRIVATE void FreeBackingStoreFromMainThread(); |
95 | V8_EXPORT_PRIVATE static void FreeBackingStore(Isolate* isolate, |
96 | Allocation allocation); |
97 | |
98 | V8_EXPORT_PRIVATE static void Setup( |
99 | Handle<JSArrayBuffer> array_buffer, Isolate* isolate, bool is_external, |
100 | void* data, size_t allocated_length, |
101 | SharedFlag shared_flag = SharedFlag::kNotShared, |
102 | bool is_wasm_memory = false); |
103 | |
104 | // Initialize the object as empty one to avoid confusing heap verifier if |
105 | // the failure happened in the middle of JSArrayBuffer construction. |
106 | V8_EXPORT_PRIVATE static void SetupAsEmpty(Handle<JSArrayBuffer> array_buffer, |
107 | Isolate* isolate); |
108 | |
109 | // Returns false if array buffer contents could not be allocated. |
110 | // In this case, |array_buffer| will not be set up. |
111 | V8_EXPORT_PRIVATE static bool SetupAllocatingData( |
112 | Handle<JSArrayBuffer> array_buffer, Isolate* isolate, |
113 | size_t allocated_length, bool initialize = true, |
114 | SharedFlag shared_flag = SharedFlag::kNotShared) V8_WARN_UNUSED_RESULT; |
115 | |
116 | // Dispatched behavior. |
117 | DECL_PRINTER(JSArrayBuffer) |
118 | DECL_VERIFIER(JSArrayBuffer) |
119 | |
120 | // Layout description. |
121 | #define JS_ARRAY_BUFFER_FIELDS(V) \ |
122 | V(kEndOfTaggedFieldsOffset, 0) \ |
123 | /* Raw data fields. */ \ |
124 | V(kByteLengthOffset, kUIntptrSize) \ |
125 | V(kBackingStoreOffset, kSystemPointerSize) \ |
126 | V(kBitFieldOffset, kInt32Size) \ |
127 | /* Pads header size to be a multiple of kTaggedSize. */ \ |
128 | V(kOptionalPaddingOffset, OBJECT_POINTER_PADDING(kOptionalPaddingOffset)) \ |
129 | /* Header size. */ \ |
130 | V(, 0) |
131 | |
132 | DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, JS_ARRAY_BUFFER_FIELDS) |
133 | #undef JS_ARRAY_BUFFER_FIELDS |
134 | |
135 | static const int kSizeWithEmbedderFields = |
136 | kHeaderSize + |
137 | v8::ArrayBuffer::kEmbedderFieldCount * kEmbedderDataSlotSize; |
138 | |
139 | class BodyDescriptor; |
140 | |
141 | OBJECT_CONSTRUCTORS(JSArrayBuffer, JSObject); |
142 | }; |
143 | |
144 | class JSArrayBufferView : public JSObject { |
145 | public: |
146 | // [buffer]: ArrayBuffer that this typed array views. |
147 | DECL_ACCESSORS(buffer, Object) |
148 | |
149 | // [byte_offset]: offset of typed array in bytes. |
150 | DECL_PRIMITIVE_ACCESSORS(byte_offset, size_t) |
151 | |
152 | // [byte_length]: length of typed array in bytes. |
153 | DECL_PRIMITIVE_ACCESSORS(byte_length, size_t) |
154 | |
155 | DECL_CAST(JSArrayBufferView) |
156 | |
157 | DECL_VERIFIER(JSArrayBufferView) |
158 | |
159 | inline bool WasDetached() const; |
160 | |
161 | // Layout description. |
162 | #define JS_ARRAY_BUFFER_VIEW_FIELDS(V) \ |
163 | V(kBufferOffset, kTaggedSize) \ |
164 | V(kEndOfTaggedFieldsOffset, 0) \ |
165 | /* Raw data fields. */ \ |
166 | V(kByteOffsetOffset, kUIntptrSize) \ |
167 | V(kByteLengthOffset, kUIntptrSize) \ |
168 | /* Header size. */ \ |
169 | V(, 0) |
170 | |
171 | DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, |
172 | JS_ARRAY_BUFFER_VIEW_FIELDS) |
173 | #undef JS_ARRAY_BUFFER_VIEW_FIELDS |
174 | |
175 | class BodyDescriptor; |
176 | |
177 | OBJECT_CONSTRUCTORS(JSArrayBufferView, JSObject); |
178 | }; |
179 | |
180 | class JSTypedArray : public JSArrayBufferView { |
181 | public: |
182 | // [length]: length of typed array in elements. |
183 | DECL_PRIMITIVE_ACCESSORS(length, size_t) |
184 | |
185 | // ES6 9.4.5.3 |
186 | V8_WARN_UNUSED_RESULT static Maybe<bool> DefineOwnProperty( |
187 | Isolate* isolate, Handle<JSTypedArray> o, Handle<Object> key, |
188 | PropertyDescriptor* desc, Maybe<ShouldThrow> should_throw); |
189 | |
190 | DECL_CAST(JSTypedArray) |
191 | |
192 | ExternalArrayType type(); |
193 | V8_EXPORT_PRIVATE size_t element_size(); |
194 | |
195 | V8_EXPORT_PRIVATE Handle<JSArrayBuffer> GetBuffer(); |
196 | |
197 | // Whether the buffer's backing store is on-heap or off-heap. |
198 | inline bool is_on_heap() const; |
199 | |
200 | static inline MaybeHandle<JSTypedArray> Validate(Isolate* isolate, |
201 | Handle<Object> receiver, |
202 | const char* method_name); |
203 | |
204 | // Dispatched behavior. |
205 | DECL_PRINTER(JSTypedArray) |
206 | DECL_VERIFIER(JSTypedArray) |
207 | |
208 | // Layout description. |
209 | #define JS_TYPED_ARRAY_FIELDS(V) \ |
210 | /* Raw data fields. */ \ |
211 | V(kLengthOffset, kTaggedSize) \ |
212 | /* Header size. */ \ |
213 | V(, 0) |
214 | |
215 | DEFINE_FIELD_OFFSET_CONSTANTS(JSArrayBufferView::kHeaderSize, |
216 | JS_TYPED_ARRAY_FIELDS) |
217 | #undef JS_TYPED_ARRAY_FIELDS |
218 | |
219 | static const int kSizeWithEmbedderFields = |
220 | kHeaderSize + |
221 | v8::ArrayBufferView::kEmbedderFieldCount * kEmbedderDataSlotSize; |
222 | |
223 | private: |
224 | static Handle<JSArrayBuffer> MaterializeArrayBuffer( |
225 | Handle<JSTypedArray> typed_array); |
226 | |
227 | DECL_ACCESSORS(raw_length, Object) |
228 | |
229 | OBJECT_CONSTRUCTORS(JSTypedArray, JSArrayBufferView); |
230 | }; |
231 | |
232 | class JSDataView : public JSArrayBufferView { |
233 | public: |
234 | DECL_CAST(JSDataView) |
235 | |
236 | // Dispatched behavior. |
237 | DECL_PRINTER(JSDataView) |
238 | DECL_VERIFIER(JSDataView) |
239 | |
240 | // Layout description. |
241 | static const int kSizeWithEmbedderFields = |
242 | kHeaderSize + |
243 | v8::ArrayBufferView::kEmbedderFieldCount * kEmbedderDataSlotSize; |
244 | |
245 | OBJECT_CONSTRUCTORS(JSDataView, JSArrayBufferView); |
246 | }; |
247 | |
248 | } // namespace internal |
249 | } // namespace v8 |
250 | |
251 | #include "src/objects/object-macros-undef.h" |
252 | |
253 | #endif // V8_OBJECTS_JS_ARRAY_BUFFER_H_ |
254 | |