1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /* ArrayBuffer functionality. */
8 #ifndef js_ArrayBuffer_h
9 #define js_ArrayBuffer_h
11 #include "mozilla/UniquePtr.h"
13 #include <stddef.h> // size_t
14 #include <stdint.h> // uint32_t
16 #include "jstypes.h" // JS_PUBLIC_API
17 #include "js/TypeDecls.h"
18 #include "js/Utility.h"
20 struct JS_PUBLIC_API JSContext
;
21 class JS_PUBLIC_API JSObject
;
25 class JS_PUBLIC_API AutoRequireNoGC
;
30 * Create a new ArrayBuffer with the given byte length.
32 extern JS_PUBLIC_API JSObject
* NewArrayBuffer(JSContext
* cx
, size_t nbytes
);
35 * Create a new ArrayBuffer with the given |contents|, which may be null only
36 * if |nbytes == 0|. |contents| must be allocated compatible with deallocation
39 * Care must be taken that |nbytes| bytes of |contents| remain valid for the
40 * duration of this call. In particular, passing the length/pointer of existing
41 * typed array or ArrayBuffer data is generally unsafe: if a GC occurs during a
42 * call to this function, it could move those contents to a different location
43 * and invalidate the provided pointer.
45 extern JS_PUBLIC_API JSObject
* NewArrayBufferWithContents(
46 JSContext
* cx
, size_t nbytes
,
47 mozilla::UniquePtr
<void, JS::FreePolicy
> contents
);
50 * Create a new ArrayBuffer with the given |contents|, which may be null only
51 * if |nbytes == 0|. |contents| must be allocated compatible with deallocation
54 * Care must be taken that |nbytes| bytes of |contents| remain valid for the
55 * duration of this call. In particular, passing the length/pointer of existing
56 * typed array or ArrayBuffer data is generally unsafe: if a GC occurs during a
57 * call to this function, it could move those contents to a different location
58 * and invalidate the provided pointer.
60 inline JS_PUBLIC_API JSObject
* NewArrayBufferWithContents(
61 JSContext
* cx
, size_t nbytes
,
62 mozilla::UniquePtr
<char[], JS::FreePolicy
> contents
) {
63 // As a convenience, provide an overload for UniquePtr<char[]>.
64 mozilla::UniquePtr
<void, JS::FreePolicy
> ptr
{contents
.release()};
65 return NewArrayBufferWithContents(cx
, nbytes
, std::move(ptr
));
69 * Create a new ArrayBuffer with the given |contents|, which may be null only
70 * if |nbytes == 0|. |contents| must be allocated compatible with deallocation
73 * Care must be taken that |nbytes| bytes of |contents| remain valid for the
74 * duration of this call. In particular, passing the length/pointer of existing
75 * typed array or ArrayBuffer data is generally unsafe: if a GC occurs during a
76 * call to this function, it could move those contents to a different location
77 * and invalidate the provided pointer.
79 inline JS_PUBLIC_API JSObject
* NewArrayBufferWithContents(
80 JSContext
* cx
, size_t nbytes
,
81 mozilla::UniquePtr
<uint8_t[], JS::FreePolicy
> contents
) {
82 // As a convenience, provide an overload for UniquePtr<uint8_t[]>.
83 mozilla::UniquePtr
<void, JS::FreePolicy
> ptr
{contents
.release()};
84 return NewArrayBufferWithContents(cx
, nbytes
, std::move(ptr
));
88 * Marker enum to notify callers that the buffer contents must be freed manually
89 * when the ArrayBuffer allocation failed.
91 enum class NewArrayBufferOutOfMemory
{ CallerMustFreeMemory
};
94 * Create a new ArrayBuffer with the given |contents|, which may be null only
95 * if |nbytes == 0|. |contents| must be allocated compatible with deallocation
99 * If and only if an ArrayBuffer is successfully created and returned,
100 * ownership of |contents| is transferred to the new ArrayBuffer.
102 * Care must be taken that |nbytes| bytes of |contents| remain valid for the
103 * duration of this call. In particular, passing the length/pointer of existing
104 * typed array or ArrayBuffer data is generally unsafe: if a GC occurs during a
105 * call to this function, it could move those contents to a different location
106 * and invalidate the provided pointer.
108 extern JS_PUBLIC_API JSObject
* NewArrayBufferWithContents(
109 JSContext
* cx
, size_t nbytes
, void* contents
, NewArrayBufferOutOfMemory
);
112 * Create a new ArrayBuffer, whose bytes are set to the values of the bytes in
113 * the provided ArrayBuffer.
115 * |maybeArrayBuffer| is asserted to be non-null. An error is thrown if
116 * |maybeArrayBuffer| would fail the |IsArrayBufferObject| test given further
117 * below or if |maybeArrayBuffer| is detached.
119 * |maybeArrayBuffer| may store its contents in any fashion (i.e. it doesn't
120 * matter whether |maybeArrayBuffer| was allocated using |JS::NewArrayBuffer|,
121 * |JS::NewExternalArrayBuffer|, or any other ArrayBuffer-allocating function).
123 * The newly-created ArrayBuffer is effectively creatd as if by
124 * |JS::NewArrayBufferWithContents| passing in |maybeArrayBuffer|'s internal
125 * data pointer and length, in a manner safe against |maybeArrayBuffer|'s data
126 * being moved around by the GC. In particular, the new ArrayBuffer will not
127 * behave like one created for WASM or asm.js, so it *can* be detached.
129 extern JS_PUBLIC_API JSObject
* CopyArrayBuffer(
130 JSContext
* cx
, JS::Handle
<JSObject
*> maybeArrayBuffer
);
132 using BufferContentsFreeFunc
= void (*)(void* contents
, void* userData
);
135 * UniquePtr deleter for external buffer contents.
137 class JS_PUBLIC_API BufferContentsDeleter
{
138 BufferContentsFreeFunc freeFunc_
= nullptr;
139 void* userData_
= nullptr;
142 MOZ_IMPLICIT
BufferContentsDeleter(BufferContentsFreeFunc freeFunc
,
143 void* userData
= nullptr)
144 : freeFunc_(freeFunc
), userData_(userData
) {}
146 void operator()(void* contents
) const { freeFunc_(contents
, userData_
); }
148 BufferContentsFreeFunc
freeFunc() const { return freeFunc_
; }
149 void* userData() const { return userData_
; }
153 * Create a new ArrayBuffer with the given contents. The contents must not be
154 * modified by any other code, internal or external.
156 * When the ArrayBuffer is ready to be disposed of, `freeFunc(contents,
157 * freeUserData)` will be called to release the ArrayBuffer's reference on the
160 * `freeFunc()` must not call any JSAPI functions that could cause a garbage
163 * The caller must keep the buffer alive until `freeFunc()` is called, or, if
164 * `freeFunc` is null, until the JSRuntime is destroyed.
166 * The caller must not access the buffer on other threads. The JS engine will
167 * not allow the buffer to be transferred to other threads. If you try to
168 * transfer an external ArrayBuffer to another thread, the data is copied to a
169 * new malloc buffer. `freeFunc()` must be threadsafe, and may be called from
172 * This allows ArrayBuffers to be used with embedder objects that use reference
173 * counting, for example. In that case the caller is responsible
174 * for incrementing the reference count before passing the contents to this
175 * function. This also allows using non-reference-counted contents that must be
176 * freed with some function other than free().
178 extern JS_PUBLIC_API JSObject
* NewExternalArrayBuffer(
179 JSContext
* cx
, size_t nbytes
,
180 mozilla::UniquePtr
<void, BufferContentsDeleter
> contents
);
183 * Create a new ArrayBuffer with the given non-null |contents|.
185 * Ownership of |contents| remains with the caller: it isn't transferred to the
186 * returned ArrayBuffer. Callers of this function *must* ensure that they
187 * perform these two steps, in this order, to properly relinquish ownership of
190 * 1. Call |JS::DetachArrayBuffer| on the buffer returned by this function.
191 * (|JS::DetachArrayBuffer| is generally fallible, but a call under these
192 * circumstances is guaranteed to succeed.)
193 * 2. |contents| may be deallocated or discarded consistent with the manner
194 * in which it was allocated.
196 * Do not simply allow the returned buffer to be garbage-collected before
197 * deallocating |contents|, because in general there is no way to know *when*
198 * an object is fully garbage-collected to the point where this would be safe.
200 extern JS_PUBLIC_API JSObject
* NewArrayBufferWithUserOwnedContents(
201 JSContext
* cx
, size_t nbytes
, void* contents
);
204 * Create a new mapped ArrayBuffer with the given memory mapped contents. It
205 * must be legal to free the contents pointer by unmapping it. On success,
206 * ownership is transferred to the new mapped ArrayBuffer.
208 extern JS_PUBLIC_API JSObject
* NewMappedArrayBufferWithContents(JSContext
* cx
,
213 * Create memory mapped ArrayBuffer contents.
214 * Caller must take care of closing fd after calling this function.
216 extern JS_PUBLIC_API
void* CreateMappedArrayBufferContents(int fd
,
221 * Release the allocated resource of mapped ArrayBuffer contents before the
223 * If a new object has been created by JS::NewMappedArrayBufferWithContents()
224 * with this content, then JS::DetachArrayBuffer() should be used instead to
225 * release the resource used by the object.
227 extern JS_PUBLIC_API
void ReleaseMappedArrayBufferContents(void* contents
,
233 * Check whether obj supports the JS::GetArrayBuffer* APIs. Note that this may
234 * return false if a security wrapper is encountered that denies the unwrapping.
235 * If this test succeeds, then it is safe to call the various predicate and
236 * accessor JSAPI calls defined below.
238 extern JS_PUBLIC_API
bool IsArrayBufferObject(JSObject
* obj
);
243 * Check whether the obj is a detached ArrayBufferObject. Note that this may
244 * return false if a security wrapper is encountered that denies the
247 extern JS_PUBLIC_API
bool IsDetachedArrayBufferObject(JSObject
* obj
);
250 * Check whether the obj is ArrayBufferObject and memory mapped. Note that this
251 * may return false if a security wrapper is encountered that denies the
254 extern JS_PUBLIC_API
bool IsMappedArrayBufferObject(JSObject
* obj
);
257 * Return true if the ArrayBuffer |obj| contains any data, i.e. it is not a
258 * detached ArrayBuffer. (ArrayBuffer.prototype is not an ArrayBuffer.)
260 * |obj| must have passed a JS::IsArrayBufferObject test, or somehow be known
261 * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
262 * ArrayBuffer, and the unwrapping will succeed.
264 extern JS_PUBLIC_API
bool ArrayBufferHasData(JSObject
* obj
);
268 extern JS_PUBLIC_API JSObject
* UnwrapArrayBuffer(JSObject
* obj
);
271 * Attempt to unwrap |obj| as an ArrayBuffer.
273 * If |obj| *is* an ArrayBuffer, return it unwrapped and set |*length| and
274 * |*data| to weakly refer to the ArrayBuffer's contents.
276 * If |obj| isn't an ArrayBuffer, return nullptr and do not modify |*length| or
279 extern JS_PUBLIC_API JSObject
* GetObjectAsArrayBuffer(JSObject
* obj
,
284 * Return the available byte length of an ArrayBuffer.
286 * |obj| must have passed a JS::IsArrayBufferObject test, or somehow be known
287 * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
288 * ArrayBuffer, and the unwrapping will succeed.
290 extern JS_PUBLIC_API
size_t GetArrayBufferByteLength(JSObject
* obj
);
292 // This one isn't inlined because there are a bunch of different ArrayBuffer
293 // classes that would have to be individually handled here.
295 // There is an isShared out argument for API consistency (eases use from DOM).
296 // It will always be set to false.
297 extern JS_PUBLIC_API
void GetArrayBufferLengthAndData(JSObject
* obj
,
299 bool* isSharedMemory
,
303 * Return a pointer to the start of the data referenced by a typed array. The
304 * data is still owned by the typed array, and should not be modified on
305 * another thread. Furthermore, the pointer can become invalid on GC (if the
306 * data is small and fits inside the array's GC header), so callers must take
307 * care not to hold on across anything that could GC.
309 * |obj| must have passed a JS::IsArrayBufferObject test, or somehow be known
310 * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
311 * ArrayBuffer, and the unwrapping will succeed.
313 * |*isSharedMemory| is always set to false. The argument is present to
314 * simplify its use from code that also interacts with SharedArrayBuffer.
316 extern JS_PUBLIC_API
uint8_t* GetArrayBufferData(JSObject
* obj
,
317 bool* isSharedMemory
,
318 const AutoRequireNoGC
&);
323 * Detach an ArrayBuffer, causing all associated views to no longer refer to
324 * the ArrayBuffer's original attached memory.
326 * This function throws only if it is provided a non-ArrayBuffer object or if
327 * the provided ArrayBuffer is a WASM-backed ArrayBuffer or an ArrayBuffer used
330 extern JS_PUBLIC_API
bool DetachArrayBuffer(JSContext
* cx
,
331 Handle
<JSObject
*> obj
);
333 // Indicates if an object has a defined [[ArrayBufferDetachKey]] internal slot,
334 // which indicates an ArrayBuffer cannot be detached
335 extern JS_PUBLIC_API
bool HasDefinedArrayBufferDetachKey(JSContext
* cx
,
336 Handle
<JSObject
*> obj
,
340 * Steal the contents of the given ArrayBuffer. The ArrayBuffer has its length
341 * set to 0 and its contents array cleared. The caller takes ownership of the
342 * return value and must free it or transfer ownership via
343 * JS::NewArrayBufferWithContents when done using it.
345 extern JS_PUBLIC_API
void* StealArrayBufferContents(JSContext
* cx
,
346 Handle
<JSObject
*> obj
);
349 * Copy data from one array buffer to another.
351 * Both fromBuffer and toBuffer must be (possibly wrapped)
352 * ArrayBufferObjectMaybeShared.
354 * This method may throw if the sizes don't match, or if unwrapping fails.
356 * The API for this is modelled on CopyDataBlockBytes from the spec:
357 * https://tc39.es/ecma262/#sec-copydatablockbytes
359 [[nodiscard
]] extern JS_PUBLIC_API
bool ArrayBufferCopyData(
360 JSContext
* cx
, Handle
<JSObject
*> toBlock
, size_t toIndex
,
361 Handle
<JSObject
*> fromBlock
, size_t fromIndex
, size_t count
);
364 * Copy data from one array buffer to another.
366 * srcBuffer must be a (possibly wrapped) ArrayBufferObjectMaybeShared.
368 * This method may throw if unwrapping or allocation fails.
370 * The API for this is modelled on CloneArrayBuffer from the spec:
371 * https://tc39.es/ecma262/#sec-clonearraybuffer
373 extern JS_PUBLIC_API JSObject
* ArrayBufferClone(JSContext
* cx
,
374 Handle
<JSObject
*> srcBuffer
,
375 size_t srcByteOffset
,
380 #endif /* js_ArrayBuffer_h */