1 // Copyright 2021 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 INCLUDE_V8_ARRAY_BUFFER_H_ 6 #define INCLUDE_V8_ARRAY_BUFFER_H_ 7 8 #include <stddef.h> 9 10 #include <memory> 11 12 #include "v8-local-handle.h" // NOLINT(build/include_directory) 13 #include "v8-object.h" // NOLINT(build/include_directory) 14 #include "v8config.h" // NOLINT(build/include_directory) 15 16 namespace v8 { 17 18 class SharedArrayBuffer; 19 20 #ifndef V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT 21 // The number of required internal fields can be defined by embedder. 22 #define V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT 2 23 #endif 24 25 enum class ArrayBufferCreationMode { kInternalized, kExternalized }; 26 27 /** 28 * A wrapper around the backing store (i.e. the raw memory) of an array buffer. 29 * See a document linked in http://crbug.com/v8/9908 for more information. 30 * 31 * The allocation and destruction of backing stores is generally managed by 32 * V8. Clients should always use standard C++ memory ownership types (i.e. 33 * std::unique_ptr and std::shared_ptr) to manage lifetimes of backing stores 34 * properly, since V8 internal objects may alias backing stores. 35 * 36 * This object does not keep the underlying |ArrayBuffer::Allocator| alive by 37 * default. Use Isolate::CreateParams::array_buffer_allocator_shared when 38 * creating the Isolate to make it hold a reference to the allocator itself. 39 */ 40 class V8_EXPORT BackingStore : public v8::internal::BackingStoreBase { 41 public: 42 ~BackingStore(); 43 44 /** 45 * Return a pointer to the beginning of the memory block for this backing 46 * store. The pointer is only valid as long as this backing store object 47 * lives. 48 */ 49 void* Data() const; 50 51 /** 52 * The length (in bytes) of this backing store. 53 */ 54 size_t ByteLength() const; 55 56 /** 57 * Indicates whether the backing store was created for an ArrayBuffer or 58 * a SharedArrayBuffer. 59 */ 60 bool IsShared() const; 61 62 /** 63 * Prevent implicit instantiation of operator delete with size_t argument. 64 * The size_t argument would be incorrect because ptr points to the 65 * internal BackingStore object. 66 */ delete(void * ptr)67 void operator delete(void* ptr) { ::operator delete(ptr); } 68 69 /** 70 * Wrapper around ArrayBuffer::Allocator::Reallocate that preserves IsShared. 71 * Assumes that the backing_store was allocated by the ArrayBuffer allocator 72 * of the given isolate. 73 */ 74 static std::unique_ptr<BackingStore> Reallocate( 75 v8::Isolate* isolate, std::unique_ptr<BackingStore> backing_store, 76 size_t byte_length); 77 78 /** 79 * This callback is used only if the memory block for a BackingStore cannot be 80 * allocated with an ArrayBuffer::Allocator. In such cases the destructor of 81 * the BackingStore invokes the callback to free the memory block. 82 */ 83 using DeleterCallback = void (*)(void* data, size_t length, 84 void* deleter_data); 85 86 /** 87 * If the memory block of a BackingStore is static or is managed manually, 88 * then this empty deleter along with nullptr deleter_data can be passed to 89 * ArrayBuffer::NewBackingStore to indicate that. 90 * 91 * The manually managed case should be used with caution and only when it 92 * is guaranteed that the memory block freeing happens after detaching its 93 * ArrayBuffer. 94 */ 95 static void EmptyDeleter(void* data, size_t length, void* deleter_data); 96 97 private: 98 /** 99 * See [Shared]ArrayBuffer::GetBackingStore and 100 * [Shared]ArrayBuffer::NewBackingStore. 101 */ 102 BackingStore(); 103 }; 104 105 #if !defined(V8_IMMINENT_DEPRECATION_WARNINGS) 106 // Use v8::BackingStore::DeleterCallback instead. 107 using BackingStoreDeleterCallback = void (*)(void* data, size_t length, 108 void* deleter_data); 109 110 #endif 111 112 /** 113 * An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5). 114 */ 115 class V8_EXPORT ArrayBuffer : public Object { 116 public: 117 /** 118 * A thread-safe allocator that V8 uses to allocate |ArrayBuffer|'s memory. 119 * The allocator is a global V8 setting. It has to be set via 120 * Isolate::CreateParams. 121 * 122 * Memory allocated through this allocator by V8 is accounted for as external 123 * memory by V8. Note that V8 keeps track of the memory for all internalized 124 * |ArrayBuffer|s. Responsibility for tracking external memory (using 125 * Isolate::AdjustAmountOfExternalAllocatedMemory) is handed over to the 126 * embedder upon externalization and taken over upon internalization (creating 127 * an internalized buffer from an existing buffer). 128 * 129 * Note that it is unsafe to call back into V8 from any of the allocator 130 * functions. 131 */ 132 class V8_EXPORT Allocator { 133 public: 134 virtual ~Allocator() = default; 135 136 /** 137 * Allocate |length| bytes. Return nullptr if allocation is not successful. 138 * Memory should be initialized to zeroes. 139 */ 140 virtual void* Allocate(size_t length) = 0; 141 142 /** 143 * Allocate |length| bytes. Return nullptr if allocation is not successful. 144 * Memory does not have to be initialized. 145 */ 146 virtual void* AllocateUninitialized(size_t length) = 0; 147 148 /** 149 * Free the memory block of size |length|, pointed to by |data|. 150 * That memory is guaranteed to be previously allocated by |Allocate|. 151 */ 152 virtual void Free(void* data, size_t length) = 0; 153 154 /** 155 * Reallocate the memory block of size |old_length| to a memory block of 156 * size |new_length| by expanding, contracting, or copying the existing 157 * memory block. If |new_length| > |old_length|, then the new part of 158 * the memory must be initialized to zeros. Return nullptr if reallocation 159 * is not successful. 160 * 161 * The caller guarantees that the memory block was previously allocated 162 * using Allocate or AllocateUninitialized. 163 * 164 * The default implementation allocates a new block and copies data. 165 */ 166 virtual void* Reallocate(void* data, size_t old_length, size_t new_length); 167 168 /** 169 * ArrayBuffer allocation mode. kNormal is a malloc/free style allocation, 170 * while kReservation is for larger allocations with the ability to set 171 * access permissions. 172 */ 173 enum class AllocationMode { kNormal, kReservation }; 174 175 /** 176 * Convenience allocator. 177 * 178 * When the sandbox is enabled, this allocator will allocate its backing 179 * memory inside the sandbox. Otherwise, it will rely on malloc/free. 180 * 181 * Caller takes ownership, i.e. the returned object needs to be freed using 182 * |delete allocator| once it is no longer in use. 183 */ 184 static Allocator* NewDefaultAllocator(); 185 }; 186 187 /** 188 * Data length in bytes. 189 */ 190 size_t ByteLength() const; 191 192 /** 193 * Create a new ArrayBuffer. Allocate |byte_length| bytes. 194 * Allocated memory will be owned by a created ArrayBuffer and 195 * will be deallocated when it is garbage-collected, 196 * unless the object is externalized. 197 */ 198 static Local<ArrayBuffer> New(Isolate* isolate, size_t byte_length); 199 200 /** 201 * Create a new ArrayBuffer with an existing backing store. 202 * The created array keeps a reference to the backing store until the array 203 * is garbage collected. Note that the IsExternal bit does not affect this 204 * reference from the array to the backing store. 205 * 206 * In future IsExternal bit will be removed. Until then the bit is set as 207 * follows. If the backing store does not own the underlying buffer, then 208 * the array is created in externalized state. Otherwise, the array is created 209 * in internalized state. In the latter case the array can be transitioned 210 * to the externalized state using Externalize(backing_store). 211 */ 212 static Local<ArrayBuffer> New(Isolate* isolate, 213 std::shared_ptr<BackingStore> backing_store); 214 215 /** 216 * Returns a new standalone BackingStore that is allocated using the array 217 * buffer allocator of the isolate. The result can be later passed to 218 * ArrayBuffer::New. 219 * 220 * If the allocator returns nullptr, then the function may cause GCs in the 221 * given isolate and re-try the allocation. If GCs do not help, then the 222 * function will crash with an out-of-memory error. 223 */ 224 static std::unique_ptr<BackingStore> NewBackingStore(Isolate* isolate, 225 size_t byte_length); 226 /** 227 * Returns a new standalone BackingStore that takes over the ownership of 228 * the given buffer. The destructor of the BackingStore invokes the given 229 * deleter callback. 230 * 231 * The result can be later passed to ArrayBuffer::New. The raw pointer 232 * to the buffer must not be passed again to any V8 API function. 233 */ 234 static std::unique_ptr<BackingStore> NewBackingStore( 235 void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter, 236 void* deleter_data); 237 238 /** 239 * Returns true if this ArrayBuffer may be detached. 240 */ 241 bool IsDetachable() const; 242 243 /** 244 * Returns true if this ArrayBuffer has been detached. 245 */ 246 bool WasDetached() const; 247 248 /** 249 * Detaches this ArrayBuffer and all its views (typed arrays). 250 * Detaching sets the byte length of the buffer and all typed arrays to zero, 251 * preventing JavaScript from ever accessing underlying backing store. 252 * ArrayBuffer should have been externalized and must be detachable. 253 */ 254 void Detach(); 255 256 /** 257 * Get a shared pointer to the backing store of this array buffer. This 258 * pointer coordinates the lifetime management of the internal storage 259 * with any live ArrayBuffers on the heap, even across isolates. The embedder 260 * should not attempt to manage lifetime of the storage through other means. 261 * 262 * The returned shared pointer will not be empty, even if the ArrayBuffer has 263 * been detached. Use |WasDetached| to tell if it has been detached instead. 264 */ 265 std::shared_ptr<BackingStore> GetBackingStore(); 266 267 /** 268 * More efficient shortcut for GetBackingStore()->Data(). The returned pointer 269 * is valid as long as the ArrayBuffer is alive. 270 */ 271 void* Data() const; 272 Cast(Value * value)273 V8_INLINE static ArrayBuffer* Cast(Value* value) { 274 #ifdef V8_ENABLE_CHECKS 275 CheckCast(value); 276 #endif 277 return static_cast<ArrayBuffer*>(value); 278 } 279 280 static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; 281 static const int kEmbedderFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; 282 283 private: 284 ArrayBuffer(); 285 static void CheckCast(Value* obj); 286 }; 287 288 #ifndef V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT 289 // The number of required internal fields can be defined by embedder. 290 #define V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT 2 291 #endif 292 293 /** 294 * A base class for an instance of one of "views" over ArrayBuffer, 295 * including TypedArrays and DataView (ES6 draft 15.13). 296 */ 297 class V8_EXPORT ArrayBufferView : public Object { 298 public: 299 /** 300 * Returns underlying ArrayBuffer. 301 */ 302 Local<ArrayBuffer> Buffer(); 303 /** 304 * Byte offset in |Buffer|. 305 */ 306 size_t ByteOffset(); 307 /** 308 * Size of a view in bytes. 309 */ 310 size_t ByteLength(); 311 312 /** 313 * Copy the contents of the ArrayBufferView's buffer to an embedder defined 314 * memory without additional overhead that calling ArrayBufferView::Buffer 315 * might incur. 316 * 317 * Will write at most min(|byte_length|, ByteLength) bytes starting at 318 * ByteOffset of the underlying buffer to the memory starting at |dest|. 319 * Returns the number of bytes actually written. 320 */ 321 size_t CopyContents(void* dest, size_t byte_length); 322 323 /** 324 * Returns true if ArrayBufferView's backing ArrayBuffer has already been 325 * allocated. 326 */ 327 bool HasBuffer() const; 328 Cast(Value * value)329 V8_INLINE static ArrayBufferView* Cast(Value* value) { 330 #ifdef V8_ENABLE_CHECKS 331 CheckCast(value); 332 #endif 333 return static_cast<ArrayBufferView*>(value); 334 } 335 336 static const int kInternalFieldCount = 337 V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT; 338 static const int kEmbedderFieldCount = 339 V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT; 340 341 private: 342 ArrayBufferView(); 343 static void CheckCast(Value* obj); 344 }; 345 346 /** 347 * An instance of DataView constructor (ES6 draft 15.13.7). 348 */ 349 class V8_EXPORT DataView : public ArrayBufferView { 350 public: 351 static Local<DataView> New(Local<ArrayBuffer> array_buffer, 352 size_t byte_offset, size_t length); 353 static Local<DataView> New(Local<SharedArrayBuffer> shared_array_buffer, 354 size_t byte_offset, size_t length); Cast(Value * value)355 V8_INLINE static DataView* Cast(Value* value) { 356 #ifdef V8_ENABLE_CHECKS 357 CheckCast(value); 358 #endif 359 return static_cast<DataView*>(value); 360 } 361 362 private: 363 DataView(); 364 static void CheckCast(Value* obj); 365 }; 366 367 /** 368 * An instance of the built-in SharedArrayBuffer constructor. 369 */ 370 class V8_EXPORT SharedArrayBuffer : public Object { 371 public: 372 /** 373 * Data length in bytes. 374 */ 375 size_t ByteLength() const; 376 377 /** 378 * Create a new SharedArrayBuffer. Allocate |byte_length| bytes. 379 * Allocated memory will be owned by a created SharedArrayBuffer and 380 * will be deallocated when it is garbage-collected, 381 * unless the object is externalized. 382 */ 383 static Local<SharedArrayBuffer> New(Isolate* isolate, size_t byte_length); 384 385 /** 386 * Create a new SharedArrayBuffer with an existing backing store. 387 * The created array keeps a reference to the backing store until the array 388 * is garbage collected. Note that the IsExternal bit does not affect this 389 * reference from the array to the backing store. 390 * 391 * In future IsExternal bit will be removed. Until then the bit is set as 392 * follows. If the backing store does not own the underlying buffer, then 393 * the array is created in externalized state. Otherwise, the array is created 394 * in internalized state. In the latter case the array can be transitioned 395 * to the externalized state using Externalize(backing_store). 396 */ 397 static Local<SharedArrayBuffer> New( 398 Isolate* isolate, std::shared_ptr<BackingStore> backing_store); 399 400 /** 401 * Returns a new standalone BackingStore that is allocated using the array 402 * buffer allocator of the isolate. The result can be later passed to 403 * SharedArrayBuffer::New. 404 * 405 * If the allocator returns nullptr, then the function may cause GCs in the 406 * given isolate and re-try the allocation. If GCs do not help, then the 407 * function will crash with an out-of-memory error. 408 */ 409 static std::unique_ptr<BackingStore> NewBackingStore(Isolate* isolate, 410 size_t byte_length); 411 /** 412 * Returns a new standalone BackingStore that takes over the ownership of 413 * the given buffer. The destructor of the BackingStore invokes the given 414 * deleter callback. 415 * 416 * The result can be later passed to SharedArrayBuffer::New. The raw pointer 417 * to the buffer must not be passed again to any V8 functions. 418 */ 419 static std::unique_ptr<BackingStore> NewBackingStore( 420 void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter, 421 void* deleter_data); 422 423 /** 424 * Get a shared pointer to the backing store of this array buffer. This 425 * pointer coordinates the lifetime management of the internal storage 426 * with any live ArrayBuffers on the heap, even across isolates. The embedder 427 * should not attempt to manage lifetime of the storage through other means. 428 */ 429 std::shared_ptr<BackingStore> GetBackingStore(); 430 431 /** 432 * More efficient shortcut for GetBackingStore()->Data(). The returned pointer 433 * is valid as long as the ArrayBuffer is alive. 434 */ 435 void* Data() const; 436 Cast(Value * value)437 V8_INLINE static SharedArrayBuffer* Cast(Value* value) { 438 #ifdef V8_ENABLE_CHECKS 439 CheckCast(value); 440 #endif 441 return static_cast<SharedArrayBuffer*>(value); 442 } 443 444 static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; 445 446 private: 447 SharedArrayBuffer(); 448 static void CheckCast(Value* obj); 449 }; 450 451 } // namespace v8 452 453 #endif // INCLUDE_V8_ARRAY_BUFFER_H_ 454