Merge mozilla-central to autoland. a=merge CLOSED TREE
[gecko.git] / js / public / ArrayBuffer.h
blobddb8ba3932cb2e916330f20a33893bfed729ac1f
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;
23 namespace JS {
25 class JS_PUBLIC_API AutoRequireNoGC;
27 // CREATION
29 /**
30 * Create a new ArrayBuffer with the given byte length.
32 extern JS_PUBLIC_API JSObject* NewArrayBuffer(JSContext* cx, size_t nbytes);
34 /**
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
37 * by |JS_free|.
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);
49 /**
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
52 * by |JS_free|.
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));
68 /**
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
71 * by |JS_free|.
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));
87 /**
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 };
93 /**
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
96 * by |JS_free|.
98 * !!! IMPORTANT !!!
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;
141 public:
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
158 * contents.
160 * `freeFunc()` must not call any JSAPI functions that could cause a garbage
161 * collection.
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
170 * any thread.
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
188 * |contents|:
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,
209 size_t nbytes,
210 void* contents);
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,
217 size_t offset,
218 size_t length);
221 * Release the allocated resource of mapped ArrayBuffer contents before the
222 * object is created.
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,
228 size_t length);
230 // TYPE TESTING
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);
240 // PREDICATES
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
245 * unwrapping.
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
252 * unwrapping.
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);
266 // ACCESSORS
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
277 * |*data|.
279 extern JS_PUBLIC_API JSObject* GetObjectAsArrayBuffer(JSObject* obj,
280 size_t* length,
281 uint8_t** data);
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,
298 size_t* length,
299 bool* isSharedMemory,
300 uint8_t** data);
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&);
320 // MUTATORS
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
328 * in asm.js code.
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,
337 bool* isDefined);
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,
376 size_t srcLength);
378 } // namespace JS
380 #endif /* js_ArrayBuffer_h */