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