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_INL_H_
6 #define V8_OBJECTS_JS_ARRAY_BUFFER_INL_H_
7 
8 #include "src/common/external-pointer.h"
9 #include "src/objects/js-array-buffer.h"
10 
11 #include "src/common/external-pointer-inl.h"
12 #include "src/heap/heap-write-barrier-inl.h"
13 #include "src/objects/js-objects-inl.h"
14 #include "src/objects/objects-inl.h"
15 #include "src/wasm/wasm-engine.h"
16 
17 // Has to be the last include (doesn't have include guards):
18 #include "src/objects/object-macros.h"
19 
20 namespace v8 {
21 namespace internal {
22 
23 #include "torque-generated/src/objects/js-array-buffer-tq-inl.inc"
24 
25 TQ_OBJECT_CONSTRUCTORS_IMPL(JSArrayBuffer)
TQ_OBJECT_CONSTRUCTORS_IMPL(JSArrayBufferView)26 TQ_OBJECT_CONSTRUCTORS_IMPL(JSArrayBufferView)
27 TQ_OBJECT_CONSTRUCTORS_IMPL(JSTypedArray)
28 TQ_OBJECT_CONSTRUCTORS_IMPL(JSDataView)
29 
30 void JSArrayBuffer::AllocateExternalPointerEntries(Isolate* isolate) {
31   InitExternalPointerField(kBackingStoreOffset, isolate);
32 }
33 
byte_length()34 size_t JSArrayBuffer::byte_length() const {
35   return ReadField<size_t>(kByteLengthOffset);
36 }
37 
set_byte_length(size_t value)38 void JSArrayBuffer::set_byte_length(size_t value) {
39   WriteField<size_t>(kByteLengthOffset, value);
40 }
41 
DEF_GETTER(JSArrayBuffer,backing_store,void *)42 DEF_GETTER(JSArrayBuffer, backing_store, void*) {
43   Address value = ReadExternalPointerField(kBackingStoreOffset, isolate,
44                                            kArrayBufferBackingStoreTag);
45   return reinterpret_cast<void*>(value);
46 }
47 
set_backing_store(Isolate * isolate,void * value)48 void JSArrayBuffer::set_backing_store(Isolate* isolate, void* value) {
49   WriteExternalPointerField(kBackingStoreOffset, isolate,
50                             reinterpret_cast<Address>(value),
51                             kArrayBufferBackingStoreTag);
52 }
53 
GetBackingStoreRefForDeserialization()54 uint32_t JSArrayBuffer::GetBackingStoreRefForDeserialization() const {
55   return static_cast<uint32_t>(
56       ReadField<ExternalPointer_t>(kBackingStoreOffset));
57 }
58 
SetBackingStoreRefForSerialization(uint32_t ref)59 void JSArrayBuffer::SetBackingStoreRefForSerialization(uint32_t ref) {
60   WriteField<ExternalPointer_t>(kBackingStoreOffset,
61                                 static_cast<ExternalPointer_t>(ref));
62 }
63 
extension()64 ArrayBufferExtension* JSArrayBuffer::extension() const {
65 #if V8_COMPRESS_POINTERS
66     // With pointer compression the extension-field might not be
67     // pointer-aligned. However on ARM64 this field needs to be aligned to
68     // perform atomic operations on it. Therefore we split the pointer into two
69     // 32-bit words that we update atomically. We don't have an ABA problem here
70     // since there can never be an Attach() after Detach() (transitions only
71     // from NULL --> some ptr --> NULL).
72 
73     // Synchronize with publishing release store of non-null extension
74     uint32_t lo = base::AsAtomic32::Acquire_Load(extension_lo());
75     if (lo & kUninitializedTagMask) return nullptr;
76 
77     // Synchronize with release store of null extension
78     uint32_t hi = base::AsAtomic32::Acquire_Load(extension_hi());
79     uint32_t verify_lo = base::AsAtomic32::Relaxed_Load(extension_lo());
80     if (lo != verify_lo) return nullptr;
81 
82     uintptr_t address = static_cast<uintptr_t>(lo);
83     address |= static_cast<uintptr_t>(hi) << 32;
84     return reinterpret_cast<ArrayBufferExtension*>(address);
85 #else
86     return base::AsAtomicPointer::Acquire_Load(extension_location());
87 #endif
88 }
89 
set_extension(ArrayBufferExtension * extension)90 void JSArrayBuffer::set_extension(ArrayBufferExtension* extension) {
91 #if V8_COMPRESS_POINTERS
92     if (extension != nullptr) {
93       uintptr_t address = reinterpret_cast<uintptr_t>(extension);
94       base::AsAtomic32::Relaxed_Store(extension_hi(),
95                                       static_cast<uint32_t>(address >> 32));
96       base::AsAtomic32::Release_Store(extension_lo(),
97                                       static_cast<uint32_t>(address));
98     } else {
99       base::AsAtomic32::Relaxed_Store(extension_lo(),
100                                       0 | kUninitializedTagMask);
101       base::AsAtomic32::Release_Store(extension_hi(), 0);
102     }
103 #else
104     base::AsAtomicPointer::Release_Store(extension_location(), extension);
105 #endif
106     WriteBarrier::Marking(*this, extension);
107 }
108 
extension_location()109 ArrayBufferExtension** JSArrayBuffer::extension_location() const {
110   Address location = field_address(kExtensionOffset);
111   return reinterpret_cast<ArrayBufferExtension**>(location);
112 }
113 
114 #if V8_COMPRESS_POINTERS
extension_lo()115 uint32_t* JSArrayBuffer::extension_lo() const {
116   Address location = field_address(kExtensionOffset);
117   return reinterpret_cast<uint32_t*>(location);
118 }
119 
extension_hi()120 uint32_t* JSArrayBuffer::extension_hi() const {
121   Address location = field_address(kExtensionOffset) + sizeof(uint32_t);
122   return reinterpret_cast<uint32_t*>(location);
123 }
124 #endif
125 
allocation_length()126 size_t JSArrayBuffer::allocation_length() const {
127   if (backing_store() == nullptr) {
128     return 0;
129   }
130   return byte_length();
131 }
132 
allocation_base()133 void* JSArrayBuffer::allocation_base() const {
134   if (backing_store() == nullptr) {
135     return nullptr;
136   }
137   return backing_store();
138 }
139 
clear_padding()140 void JSArrayBuffer::clear_padding() {
141   if (FIELD_SIZE(kOptionalPaddingOffset) != 0) {
142     DCHECK_EQ(4, FIELD_SIZE(kOptionalPaddingOffset));
143     memset(reinterpret_cast<void*>(address() + kOptionalPaddingOffset), 0,
144            FIELD_SIZE(kOptionalPaddingOffset));
145   }
146 }
147 
set_bit_field(uint32_t bits)148 void JSArrayBuffer::set_bit_field(uint32_t bits) {
149   RELAXED_WRITE_UINT32_FIELD(*this, kBitFieldOffset, bits);
150 }
151 
bit_field()152 uint32_t JSArrayBuffer::bit_field() const {
153   return RELAXED_READ_UINT32_FIELD(*this, kBitFieldOffset);
154 }
155 
156 // |bit_field| fields.
BIT_FIELD_ACCESSORS(JSArrayBuffer,bit_field,is_external,JSArrayBuffer::IsExternalBit)157 BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_external,
158                     JSArrayBuffer::IsExternalBit)
159 BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_detachable,
160                     JSArrayBuffer::IsDetachableBit)
161 BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, was_detached,
162                     JSArrayBuffer::WasDetachedBit)
163 BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_asmjs_memory,
164                     JSArrayBuffer::IsAsmJsMemoryBit)
165 BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_shared,
166                     JSArrayBuffer::IsSharedBit)
167 
168 size_t JSArrayBufferView::byte_offset() const {
169   return ReadField<size_t>(kByteOffsetOffset);
170 }
171 
set_byte_offset(size_t value)172 void JSArrayBufferView::set_byte_offset(size_t value) {
173   WriteField<size_t>(kByteOffsetOffset, value);
174 }
175 
byte_length()176 size_t JSArrayBufferView::byte_length() const {
177   return ReadField<size_t>(kByteLengthOffset);
178 }
179 
set_byte_length(size_t value)180 void JSArrayBufferView::set_byte_length(size_t value) {
181   WriteField<size_t>(kByteLengthOffset, value);
182 }
183 
WasDetached()184 bool JSArrayBufferView::WasDetached() const {
185   return JSArrayBuffer::cast(buffer()).was_detached();
186 }
187 
AllocateExternalPointerEntries(Isolate * isolate)188 void JSTypedArray::AllocateExternalPointerEntries(Isolate* isolate) {
189   InitExternalPointerField(kExternalPointerOffset, isolate);
190 }
191 
length()192 size_t JSTypedArray::length() const { return ReadField<size_t>(kLengthOffset); }
193 
set_length(size_t value)194 void JSTypedArray::set_length(size_t value) {
195   WriteField<size_t>(kLengthOffset, value);
196 }
197 
DEF_GETTER(JSTypedArray,external_pointer,Address)198 DEF_GETTER(JSTypedArray, external_pointer, Address) {
199   return ReadExternalPointerField(kExternalPointerOffset, isolate,
200                                   kTypedArrayExternalPointerTag);
201 }
202 
DEF_GETTER(JSTypedArray,external_pointer_raw,ExternalPointer_t)203 DEF_GETTER(JSTypedArray, external_pointer_raw, ExternalPointer_t) {
204   return ReadField<ExternalPointer_t>(kExternalPointerOffset);
205 }
206 
set_external_pointer(Isolate * isolate,Address value)207 void JSTypedArray::set_external_pointer(Isolate* isolate, Address value) {
208   WriteExternalPointerField(kExternalPointerOffset, isolate, value,
209                             kTypedArrayExternalPointerTag);
210 }
211 
ExternalPointerCompensationForOnHeapArray(IsolateRoot isolate)212 Address JSTypedArray::ExternalPointerCompensationForOnHeapArray(
213     IsolateRoot isolate) {
214 #ifdef V8_COMPRESS_POINTERS
215   return isolate.address();
216 #else
217   return 0;
218 #endif
219 }
220 
GetExternalBackingStoreRefForDeserialization()221 uint32_t JSTypedArray::GetExternalBackingStoreRefForDeserialization() const {
222   DCHECK(!is_on_heap());
223   return static_cast<uint32_t>(
224       ReadField<ExternalPointer_t>(kExternalPointerOffset));
225 }
226 
SetExternalBackingStoreRefForSerialization(uint32_t ref)227 void JSTypedArray::SetExternalBackingStoreRefForSerialization(uint32_t ref) {
228   DCHECK(!is_on_heap());
229   WriteField<ExternalPointer_t>(kExternalPointerOffset,
230                                 static_cast<ExternalPointer_t>(ref));
231 }
232 
RemoveExternalPointerCompensationForSerialization(Isolate * isolate)233 void JSTypedArray::RemoveExternalPointerCompensationForSerialization(
234     Isolate* isolate) {
235   DCHECK(is_on_heap());
236   // TODO(v8:10391): once we have an external table, avoid the need for
237   // compensation by replacing external_pointer and base_pointer fields
238   // with one data_pointer field which can point to either external data
239   // backing store or into on-heap backing store.
240   Address offset =
241       external_pointer() - ExternalPointerCompensationForOnHeapArray(isolate);
242 #ifdef V8_HEAP_SANDBOX
243   // Write decompensated offset directly to the external pointer field, thus
244   // allowing the offset to be propagated through serialization-deserialization.
245   WriteField<ExternalPointer_t>(kExternalPointerOffset, offset);
246 #else
247   set_external_pointer(isolate, offset);
248 #endif
249 }
250 
DataPtr()251 void* JSTypedArray::DataPtr() {
252   // Zero-extend Tagged_t to Address according to current compression scheme
253   // so that the addition with |external_pointer| (which already contains
254   // compensated offset value) will decompress the tagged value.
255   // See JSTypedArray::ExternalPointerCompensationForOnHeapArray() for details.
256   return reinterpret_cast<void*>(external_pointer() +
257                                  static_cast<Tagged_t>(base_pointer().ptr()));
258 }
259 
SetOffHeapDataPtr(Isolate * isolate,void * base,Address offset)260 void JSTypedArray::SetOffHeapDataPtr(Isolate* isolate, void* base,
261                                      Address offset) {
262   set_base_pointer(Smi::zero(), SKIP_WRITE_BARRIER);
263   Address address = reinterpret_cast<Address>(base) + offset;
264   set_external_pointer(isolate, address);
265   DCHECK_EQ(address, reinterpret_cast<Address>(DataPtr()));
266 }
267 
SetOnHeapDataPtr(Isolate * isolate,HeapObject base,Address offset)268 void JSTypedArray::SetOnHeapDataPtr(Isolate* isolate, HeapObject base,
269                                     Address offset) {
270   set_base_pointer(base);
271   set_external_pointer(
272       isolate, offset + ExternalPointerCompensationForOnHeapArray(isolate));
273   DCHECK_EQ(base.ptr() + offset, reinterpret_cast<Address>(DataPtr()));
274 }
275 
is_on_heap()276 bool JSTypedArray::is_on_heap() const {
277   DisallowHeapAllocation no_gc;
278   // Checking that buffer()->backing_store() is not nullptr is not sufficient;
279   // it will be nullptr when byte_length is 0 as well.
280   return base_pointer() == elements();
281 }
282 
283 // static
Validate(Isolate * isolate,Handle<Object> receiver,const char * method_name)284 MaybeHandle<JSTypedArray> JSTypedArray::Validate(Isolate* isolate,
285                                                  Handle<Object> receiver,
286                                                  const char* method_name) {
287   if (V8_UNLIKELY(!receiver->IsJSTypedArray())) {
288     const MessageTemplate message = MessageTemplate::kNotTypedArray;
289     THROW_NEW_ERROR(isolate, NewTypeError(message), JSTypedArray);
290   }
291 
292   Handle<JSTypedArray> array = Handle<JSTypedArray>::cast(receiver);
293   if (V8_UNLIKELY(array->WasDetached())) {
294     const MessageTemplate message = MessageTemplate::kDetachedOperation;
295     Handle<String> operation =
296         isolate->factory()->NewStringFromAsciiChecked(method_name);
297     THROW_NEW_ERROR(isolate, NewTypeError(message, operation), JSTypedArray);
298   }
299 
300   // spec describes to return `buffer`, but it may disrupt current
301   // implementations, and it's much useful to return array for now.
302   return array;
303 }
304 
DEF_GETTER(JSDataView,data_pointer,void *)305 DEF_GETTER(JSDataView, data_pointer, void*) {
306   return reinterpret_cast<void*>(ReadExternalPointerField(
307       kDataPointerOffset, isolate, kDataViewDataPointerTag));
308 }
309 
AllocateExternalPointerEntries(Isolate * isolate)310 void JSDataView::AllocateExternalPointerEntries(Isolate* isolate) {
311   InitExternalPointerField(kDataPointerOffset, isolate);
312 }
313 
set_data_pointer(Isolate * isolate,void * value)314 void JSDataView::set_data_pointer(Isolate* isolate, void* value) {
315   WriteExternalPointerField(kDataPointerOffset, isolate,
316                             reinterpret_cast<Address>(value),
317                             kDataViewDataPointerTag);
318 }
319 
320 }  // namespace internal
321 }  // namespace v8
322 
323 #include "src/objects/object-macros-undef.h"
324 
325 #endif  // V8_OBJECTS_JS_ARRAY_BUFFER_INL_H_
326