• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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