1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 * Typed array, ArrayBuffer, and DataView creation, predicate, and accessor
12 #ifndef js_experimental_TypedData_h
13 #define js_experimental_TypedData_h
15 #include "mozilla/Assertions.h" // MOZ_ASSERT, MOZ_CRASH
16 #include "mozilla/Casting.h" // mozilla::AssertedCast
18 #include <stddef.h> // size_t
19 #include <stdint.h> // {,u}int8_t, {,u}int16_t, {,u}int32_t
21 #include "jstypes.h" // JS_PUBLIC_API
23 #include "js/Object.h" // JS::GetClass, JS::GetPrivate, JS::GetReservedSlot
24 #include "js/RootingAPI.h" // JS::Handle
25 #include "js/ScalarType.h" // js::Scalar::Type
28 class JS_PUBLIC_API JSObject
;
32 class JS_PUBLIC_API AutoRequireNoGC
;
37 * Create a new typed array with nelements elements.
39 * These functions (except the WithBuffer variants) fill in the array with
43 extern JS_PUBLIC_API JSObject
* JS_NewInt8Array(JSContext
* cx
, size_t nelements
);
44 extern JS_PUBLIC_API JSObject
* JS_NewUint8Array(JSContext
* cx
,
46 extern JS_PUBLIC_API JSObject
* JS_NewUint8ClampedArray(JSContext
* cx
,
48 extern JS_PUBLIC_API JSObject
* JS_NewInt16Array(JSContext
* cx
,
50 extern JS_PUBLIC_API JSObject
* JS_NewUint16Array(JSContext
* cx
,
52 extern JS_PUBLIC_API JSObject
* JS_NewInt32Array(JSContext
* cx
,
54 extern JS_PUBLIC_API JSObject
* JS_NewUint32Array(JSContext
* cx
,
56 extern JS_PUBLIC_API JSObject
* JS_NewFloat32Array(JSContext
* cx
,
58 extern JS_PUBLIC_API JSObject
* JS_NewFloat64Array(JSContext
* cx
,
62 * Create a new typed array and copy in values from the given object. The
63 * object is used as if it were an array; that is, the new array (if
64 * successfully created) will have length given by array.length, and its
65 * elements will be those specified by array[0], array[1], and so on, after
66 * conversion to the typed array element type.
69 extern JS_PUBLIC_API JSObject
* JS_NewInt8ArrayFromArray(
70 JSContext
* cx
, JS::Handle
<JSObject
*> array
);
71 extern JS_PUBLIC_API JSObject
* JS_NewUint8ArrayFromArray(
72 JSContext
* cx
, JS::Handle
<JSObject
*> array
);
73 extern JS_PUBLIC_API JSObject
* JS_NewUint8ClampedArrayFromArray(
74 JSContext
* cx
, JS::Handle
<JSObject
*> array
);
75 extern JS_PUBLIC_API JSObject
* JS_NewInt16ArrayFromArray(
76 JSContext
* cx
, JS::Handle
<JSObject
*> array
);
77 extern JS_PUBLIC_API JSObject
* JS_NewUint16ArrayFromArray(
78 JSContext
* cx
, JS::Handle
<JSObject
*> array
);
79 extern JS_PUBLIC_API JSObject
* JS_NewInt32ArrayFromArray(
80 JSContext
* cx
, JS::Handle
<JSObject
*> array
);
81 extern JS_PUBLIC_API JSObject
* JS_NewUint32ArrayFromArray(
82 JSContext
* cx
, JS::Handle
<JSObject
*> array
);
83 extern JS_PUBLIC_API JSObject
* JS_NewFloat32ArrayFromArray(
84 JSContext
* cx
, JS::Handle
<JSObject
*> array
);
85 extern JS_PUBLIC_API JSObject
* JS_NewFloat64ArrayFromArray(
86 JSContext
* cx
, JS::Handle
<JSObject
*> array
);
89 * Create a new typed array using the given ArrayBuffer or
90 * SharedArrayBuffer for storage. The length value is optional; if -1
91 * is passed, enough elements to use up the remainder of the byte
92 * array is used as the default value.
95 extern JS_PUBLIC_API JSObject
* JS_NewInt8ArrayWithBuffer(
96 JSContext
* cx
, JS::Handle
<JSObject
*> arrayBuffer
, size_t byteOffset
,
98 extern JS_PUBLIC_API JSObject
* JS_NewUint8ArrayWithBuffer(
99 JSContext
* cx
, JS::Handle
<JSObject
*> arrayBuffer
, size_t byteOffset
,
101 extern JS_PUBLIC_API JSObject
* JS_NewUint8ClampedArrayWithBuffer(
102 JSContext
* cx
, JS::Handle
<JSObject
*> arrayBuffer
, size_t byteOffset
,
104 extern JS_PUBLIC_API JSObject
* JS_NewInt16ArrayWithBuffer(
105 JSContext
* cx
, JS::Handle
<JSObject
*> arrayBuffer
, size_t byteOffset
,
107 extern JS_PUBLIC_API JSObject
* JS_NewUint16ArrayWithBuffer(
108 JSContext
* cx
, JS::Handle
<JSObject
*> arrayBuffer
, size_t byteOffset
,
110 extern JS_PUBLIC_API JSObject
* JS_NewInt32ArrayWithBuffer(
111 JSContext
* cx
, JS::Handle
<JSObject
*> arrayBuffer
, size_t byteOffset
,
113 extern JS_PUBLIC_API JSObject
* JS_NewUint32ArrayWithBuffer(
114 JSContext
* cx
, JS::Handle
<JSObject
*> arrayBuffer
, size_t byteOffset
,
116 extern JS_PUBLIC_API JSObject
* JS_NewBigInt64ArrayWithBuffer(
117 JSContext
* cx
, JS::Handle
<JSObject
*> arrayBuffer
, size_t byteOffset
,
119 extern JS_PUBLIC_API JSObject
* JS_NewBigUint64ArrayWithBuffer(
120 JSContext
* cx
, JS::Handle
<JSObject
*> arrayBuffer
, size_t byteOffset
,
122 extern JS_PUBLIC_API JSObject
* JS_NewFloat32ArrayWithBuffer(
123 JSContext
* cx
, JS::Handle
<JSObject
*> arrayBuffer
, size_t byteOffset
,
125 extern JS_PUBLIC_API JSObject
* JS_NewFloat64ArrayWithBuffer(
126 JSContext
* cx
, JS::Handle
<JSObject
*> arrayBuffer
, size_t byteOffset
,
130 * Check whether obj supports JS_GetTypedArray* APIs. Note that this may return
131 * false if a security wrapper is encountered that denies the unwrapping. If
132 * this test or one of the JS_Is*Array tests succeeds, then it is safe to call
133 * the various accessor JSAPI calls defined below.
135 extern JS_PUBLIC_API
bool JS_IsTypedArrayObject(JSObject
* obj
);
138 * Check whether obj supports JS_GetArrayBufferView* APIs. Note that this may
139 * return false if a security wrapper is encountered that denies the
140 * unwrapping. If this test or one of the more specific tests succeeds, then it
141 * is safe to call the various ArrayBufferView accessor JSAPI calls defined
144 extern JS_PUBLIC_API
bool JS_IsArrayBufferViewObject(JSObject
* obj
);
147 * Test for specific typed array types (ArrayBufferView subtypes)
150 extern JS_PUBLIC_API
bool JS_IsInt8Array(JSObject
* obj
);
151 extern JS_PUBLIC_API
bool JS_IsUint8Array(JSObject
* obj
);
152 extern JS_PUBLIC_API
bool JS_IsUint8ClampedArray(JSObject
* obj
);
153 extern JS_PUBLIC_API
bool JS_IsInt16Array(JSObject
* obj
);
154 extern JS_PUBLIC_API
bool JS_IsUint16Array(JSObject
* obj
);
155 extern JS_PUBLIC_API
bool JS_IsInt32Array(JSObject
* obj
);
156 extern JS_PUBLIC_API
bool JS_IsUint32Array(JSObject
* obj
);
157 extern JS_PUBLIC_API
bool JS_IsFloat32Array(JSObject
* obj
);
158 extern JS_PUBLIC_API
bool JS_IsFloat64Array(JSObject
* obj
);
161 * Return the isShared flag of a typed array, which denotes whether
162 * the underlying buffer is a SharedArrayBuffer.
164 * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
165 * be known that it would pass such a test: it is a typed array or a wrapper of
166 * a typed array, and the unwrapping will succeed.
168 extern JS_PUBLIC_API
bool JS_GetTypedArraySharedness(JSObject
* obj
);
171 * Test for specific typed array types (ArrayBufferView subtypes) and return
172 * the unwrapped object if so, else nullptr. Never throws.
177 extern JS_PUBLIC_API JSObject
* UnwrapInt8Array(JSObject
* obj
);
178 extern JS_PUBLIC_API JSObject
* UnwrapUint8Array(JSObject
* obj
);
179 extern JS_PUBLIC_API JSObject
* UnwrapUint8ClampedArray(JSObject
* obj
);
180 extern JS_PUBLIC_API JSObject
* UnwrapInt16Array(JSObject
* obj
);
181 extern JS_PUBLIC_API JSObject
* UnwrapUint16Array(JSObject
* obj
);
182 extern JS_PUBLIC_API JSObject
* UnwrapInt32Array(JSObject
* obj
);
183 extern JS_PUBLIC_API JSObject
* UnwrapUint32Array(JSObject
* obj
);
184 extern JS_PUBLIC_API JSObject
* UnwrapBigInt64Array(JSObject
* obj
);
185 extern JS_PUBLIC_API JSObject
* UnwrapBigUint64Array(JSObject
* obj
);
186 extern JS_PUBLIC_API JSObject
* UnwrapFloat32Array(JSObject
* obj
);
187 extern JS_PUBLIC_API JSObject
* UnwrapFloat64Array(JSObject
* obj
);
189 extern JS_PUBLIC_API JSObject
* UnwrapArrayBufferView(JSObject
* obj
);
191 extern JS_PUBLIC_API JSObject
* UnwrapReadableStream(JSObject
* obj
);
195 extern JS_PUBLIC_DATA
const JSClass
* const Int8ArrayClassPtr
;
196 extern JS_PUBLIC_DATA
const JSClass
* const Uint8ArrayClassPtr
;
197 extern JS_PUBLIC_DATA
const JSClass
* const Uint8ClampedArrayClassPtr
;
198 extern JS_PUBLIC_DATA
const JSClass
* const Int16ArrayClassPtr
;
199 extern JS_PUBLIC_DATA
const JSClass
* const Uint16ArrayClassPtr
;
200 extern JS_PUBLIC_DATA
const JSClass
* const Int32ArrayClassPtr
;
201 extern JS_PUBLIC_DATA
const JSClass
* const Uint32ArrayClassPtr
;
202 extern JS_PUBLIC_DATA
const JSClass
* const BigInt64ArrayClassPtr
;
203 extern JS_PUBLIC_DATA
const JSClass
* const BigUint64ArrayClassPtr
;
204 extern JS_PUBLIC_DATA
const JSClass
* const Float32ArrayClassPtr
;
205 extern JS_PUBLIC_DATA
const JSClass
* const Float64ArrayClassPtr
;
207 const size_t TypedArrayLengthSlot
= 1;
209 } // namespace detail
211 #define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \
212 inline void Get##Type##ArrayLengthAndData( \
213 JSObject* obj, size_t* length, bool* isSharedMemory, type** data) { \
214 MOZ_ASSERT(JS::GetClass(obj) == detail::Type##ArrayClassPtr); \
215 const JS::Value& lenSlot = \
216 JS::GetReservedSlot(obj, detail::TypedArrayLengthSlot); \
217 *length = size_t(lenSlot.toPrivate()); \
218 *isSharedMemory = JS_GetTypedArraySharedness(obj); \
219 *data = static_cast<type*>(JS::GetPrivate(obj)); \
222 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int8
, int8_t)
223 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8
, uint8_t)
224 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8Clamped
, uint8_t)
225 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int16
, int16_t)
226 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint16
, uint16_t)
227 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int32
, int32_t)
228 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint32
, uint32_t)
229 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float32
, float)
230 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float64
, double)
232 #undef JS_DEFINE_DATA_AND_LENGTH_ACCESSOR
234 // This one isn't inlined because it's rather tricky (by dint of having to deal
235 // with a dozen-plus classes and varying slot layouts.
236 extern JS_PUBLIC_API
void GetArrayBufferViewLengthAndData(JSObject
* obj
,
238 bool* isSharedMemory
,
244 * Unwrap Typed arrays all at once. Return nullptr without throwing if the
245 * object cannot be viewed as the correct typed array, or the typed array
246 * object on success, filling both outparameters.
248 extern JS_PUBLIC_API JSObject
* JS_GetObjectAsInt8Array(JSObject
* obj
,
250 bool* isSharedMemory
,
252 extern JS_PUBLIC_API JSObject
* JS_GetObjectAsUint8Array(JSObject
* obj
,
254 bool* isSharedMemory
,
256 extern JS_PUBLIC_API JSObject
* JS_GetObjectAsUint8ClampedArray(
257 JSObject
* obj
, size_t* length
, bool* isSharedMemory
, uint8_t** data
);
258 extern JS_PUBLIC_API JSObject
* JS_GetObjectAsInt16Array(JSObject
* obj
,
260 bool* isSharedMemory
,
262 extern JS_PUBLIC_API JSObject
* JS_GetObjectAsUint16Array(JSObject
* obj
,
264 bool* isSharedMemory
,
266 extern JS_PUBLIC_API JSObject
* JS_GetObjectAsInt32Array(JSObject
* obj
,
268 bool* isSharedMemory
,
270 extern JS_PUBLIC_API JSObject
* JS_GetObjectAsUint32Array(JSObject
* obj
,
272 bool* isSharedMemory
,
274 extern JS_PUBLIC_API JSObject
* JS_GetObjectAsFloat32Array(JSObject
* obj
,
276 bool* isSharedMemory
,
278 extern JS_PUBLIC_API JSObject
* JS_GetObjectAsFloat64Array(JSObject
* obj
,
280 bool* isSharedMemory
,
282 extern JS_PUBLIC_API JSObject
* JS_GetObjectAsArrayBufferView(
283 JSObject
* obj
, size_t* length
, bool* isSharedMemory
, uint8_t** data
);
286 * Get the type of elements in a typed array, or MaxTypedArrayViewType if a
289 * |obj| must have passed a JS_IsArrayBufferView/JS_Is*Array test, or somehow
290 * be known that it would pass such a test: it is an ArrayBufferView or a
291 * wrapper of an ArrayBufferView, and the unwrapping will succeed.
293 extern JS_PUBLIC_API
js::Scalar::Type
JS_GetArrayBufferViewType(JSObject
* obj
);
296 * Return the number of elements in a typed array.
298 * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
299 * be known that it would pass such a test: it is a typed array or a wrapper of
300 * a typed array, and the unwrapping will succeed.
302 extern JS_PUBLIC_API
size_t JS_GetTypedArrayLength(JSObject
* obj
);
305 * Return the byte offset from the start of an ArrayBuffer to the start of a
308 * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
309 * be known that it would pass such a test: it is a typed array or a wrapper of
310 * a typed array, and the unwrapping will succeed.
312 extern JS_PUBLIC_API
size_t JS_GetTypedArrayByteOffset(JSObject
* obj
);
315 * Return the byte length of a typed array.
317 * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
318 * be known that it would pass such a test: it is a typed array or a wrapper of
319 * a typed array, and the unwrapping will succeed.
321 extern JS_PUBLIC_API
size_t JS_GetTypedArrayByteLength(JSObject
* obj
);
324 * More generic name for JS_GetTypedArrayByteLength to cover DataViews as well
326 extern JS_PUBLIC_API
size_t JS_GetArrayBufferViewByteLength(JSObject
* obj
);
329 * More generic name for JS_GetTypedArrayByteOffset to cover DataViews as well
331 extern JS_PUBLIC_API
size_t JS_GetArrayBufferViewByteOffset(JSObject
* obj
);
334 * Return a pointer to the start of the data referenced by a typed array. The
335 * data is still owned by the typed array, and should not be modified on
336 * another thread. Furthermore, the pointer can become invalid on GC (if the
337 * data is small and fits inside the array's GC header), so callers must take
338 * care not to hold on across anything that could GC.
340 * |obj| must have passed a JS_Is*Array test, or somehow be known that it would
341 * pass such a test: it is a typed array or a wrapper of a typed array, and the
342 * unwrapping will succeed.
344 * |*isSharedMemory| will be set to true if the typed array maps a
345 * SharedArrayBuffer, otherwise to false.
348 extern JS_PUBLIC_API
int8_t* JS_GetInt8ArrayData(JSObject
* obj
,
349 bool* isSharedMemory
,
350 const JS::AutoRequireNoGC
&);
351 extern JS_PUBLIC_API
uint8_t* JS_GetUint8ArrayData(JSObject
* obj
,
352 bool* isSharedMemory
,
353 const JS::AutoRequireNoGC
&);
354 extern JS_PUBLIC_API
uint8_t* JS_GetUint8ClampedArrayData(
355 JSObject
* obj
, bool* isSharedMemory
, const JS::AutoRequireNoGC
&);
356 extern JS_PUBLIC_API
int16_t* JS_GetInt16ArrayData(JSObject
* obj
,
357 bool* isSharedMemory
,
358 const JS::AutoRequireNoGC
&);
359 extern JS_PUBLIC_API
uint16_t* JS_GetUint16ArrayData(
360 JSObject
* obj
, bool* isSharedMemory
, const JS::AutoRequireNoGC
&);
361 extern JS_PUBLIC_API
int32_t* JS_GetInt32ArrayData(JSObject
* obj
,
362 bool* isSharedMemory
,
363 const JS::AutoRequireNoGC
&);
364 extern JS_PUBLIC_API
uint32_t* JS_GetUint32ArrayData(
365 JSObject
* obj
, bool* isSharedMemory
, const JS::AutoRequireNoGC
&);
366 extern JS_PUBLIC_API
float* JS_GetFloat32ArrayData(JSObject
* obj
,
367 bool* isSharedMemory
,
368 const JS::AutoRequireNoGC
&);
369 extern JS_PUBLIC_API
double* JS_GetFloat64ArrayData(JSObject
* obj
,
370 bool* isSharedMemory
,
371 const JS::AutoRequireNoGC
&);
374 * Same as above, but for any kind of ArrayBufferView. Prefer the type-specific
375 * versions when possible.
377 extern JS_PUBLIC_API
void* JS_GetArrayBufferViewData(
378 JSObject
* obj
, bool* isSharedMemory
, const JS::AutoRequireNoGC
&);
381 * Return a "fixed" pointer (one that will not move during a GC) to the
382 * ArrayBufferView's data. Note that this will not keep the object alive; the
383 * holding object should be rooted or traced. If the view is storing the data
384 * inline, this will copy the data to the provided buffer, returning nullptr if
385 * bufSize is inadequate.
387 * Avoid using this unless necessary. JS_GetArrayBufferViewData is simpler and
388 * more efficient because it requires the caller to ensure that a GC will not
389 * occur and thus does not need to handle movable data.
391 extern JS_PUBLIC_API
uint8_t* JS_GetArrayBufferViewFixedData(JSObject
* obj
,
396 * If the bufSize passed to JS_GetArrayBufferViewFixedData is at least this
397 * many bytes, then any copied data is guaranteed to fit into the provided
400 extern JS_PUBLIC_API
size_t JS_MaxMovableTypedArraySize();
403 * Return the ArrayBuffer or SharedArrayBuffer underlying an ArrayBufferView.
404 * This may return a detached buffer. |obj| must be an object that would
405 * return true for JS_IsArrayBufferViewObject().
407 extern JS_PUBLIC_API JSObject
* JS_GetArrayBufferViewBuffer(
408 JSContext
* cx
, JS::Handle
<JSObject
*> obj
, bool* isSharedMemory
);
411 * Create a new DataView using the given buffer for storage. The given buffer
412 * must be an ArrayBuffer or SharedArrayBuffer (or a cross-compartment wrapper
413 * of either type), and the offset and length must fit within the bounds of the
414 * buffer. Currently, nullptr will be returned and an exception will be thrown
415 * if these conditions do not hold, but do not depend on that behavior.
417 JS_PUBLIC_API JSObject
* JS_NewDataView(JSContext
* cx
,
418 JS::Handle
<JSObject
*> buffer
,
419 size_t byteOffset
, size_t byteLength
);
424 * Returns whether the passed array buffer view is 'large': its byteLength >= 2
425 * GB. See also SetLargeArrayBuffersEnabled.
427 * |obj| must pass a JS_IsArrayBufferViewObject test.
429 JS_PUBLIC_API
bool IsLargeArrayBufferView(JSObject
* obj
);
433 #endif // js_experimental_TypedData_h