2019-03-05 02:19:16 +03:00
|
|
|
/* -*- 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 <stddef.h> // size_t
|
|
|
|
#include <stdint.h> // uint32_t
|
|
|
|
|
|
|
|
#include "jstypes.h" // JS_PUBLIC_API
|
|
|
|
|
|
|
|
#include "js/GCAPI.h" // JS::AutoRequireNoGC
|
|
|
|
#include "js/RootingAPI.h" // JS::Handle
|
|
|
|
|
2019-10-28 01:34:11 +03:00
|
|
|
struct JS_PUBLIC_API JSContext;
|
|
|
|
class JS_PUBLIC_API JSObject;
|
2019-03-05 02:19:16 +03:00
|
|
|
|
|
|
|
namespace JS {
|
|
|
|
|
|
|
|
// CREATION
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new ArrayBuffer with the given byte length.
|
|
|
|
*/
|
2021-01-28 18:53:44 +03:00
|
|
|
extern JS_PUBLIC_API JSObject* NewArrayBuffer(JSContext* cx, size_t nbytes);
|
2019-03-05 02:19:16 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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|.
|
|
|
|
*
|
|
|
|
* If and only if an ArrayBuffer is successfully created and returned,
|
|
|
|
* ownership of |contents| is transferred to the new ArrayBuffer.
|
2020-05-08 02:46:22 +03:00
|
|
|
*
|
|
|
|
* Care must be taken that |nbytes| bytes of |content| 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.
|
2019-03-05 02:19:16 +03:00
|
|
|
*/
|
|
|
|
extern JS_PUBLIC_API JSObject* NewArrayBufferWithContents(JSContext* cx,
|
|
|
|
size_t nbytes,
|
|
|
|
void* contents);
|
|
|
|
|
2020-05-08 02:46:22 +03:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
2019-03-05 02:19:16 +03:00
|
|
|
using BufferContentsFreeFunc = void (*)(void* contents, void* 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, void* contents,
|
|
|
|
BufferContentsFreeFunc freeFunc, void* freeUserData = nullptr);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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,
|
|
|
|
uint32_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 uint32_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,
|
|
|
|
uint32_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);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
2021-01-30 19:14:30 +03:00
|
|
|
/**
|
|
|
|
* Enable or disable support for large (>= 2 GB) ArrayBuffers on 64-bit builds.
|
|
|
|
* Has no effect on 32-bit builds.
|
|
|
|
*/
|
|
|
|
extern JS_PUBLIC_API void SetLargeArrayBuffersEnabled(bool enable);
|
|
|
|
|
2019-03-05 02:19:16 +03:00
|
|
|
} // namespace JS
|
|
|
|
|
|
|
|
#endif /* js_ArrayBuffer_h */
|