68.14.5 - js

This commit is contained in:
Fedor 2024-11-25 17:11:59 +02:00
parent dad6ce97e1
commit 4ccbd6ec3b
2298 changed files with 102536 additions and 50597 deletions

View File

@ -24,7 +24,7 @@ DIRS += [
'/mozglue',
]
if CONFIG['USE_ICU']:
if CONFIG['JS_HAS_INTL_API']:
DIRS += [
'/config/external/icu',
]

View File

@ -10,8 +10,8 @@ def force_system_ffi(target):
imply_option('--with-system-ffi', force_system_ffi, "target")
js_option('--with-system-ffi',
help='Use system libffi (located with pkgconfig)')
option('--with-system-ffi',
help='Use system libffi (located with pkgconfig)')
use_system_ffi = depends_if('--with-system-ffi')(lambda _: True)

File diff suppressed because it is too large Load Diff

View File

@ -185,6 +185,21 @@ class TempAllocPolicy : public AllocPolicyBase {
}
};
/*
* A replacement for MallocAllocPolicy that allocates in the JS heap and adds no
* extra behaviours.
*
* This is currently used for allocating source buffers for parsing. Since these
* are temporary and will not be freed by GC, the memory is not tracked by the
* usual accounting.
*/
class MallocAllocPolicy : public AllocPolicyBase {
public:
void reportAllocOverflow() const {}
[[nodiscard]] bool checkSimulatedOOM() const { return true; }
};
} /* namespace js */
#endif /* js_AllocPolicy_h */

View File

@ -25,7 +25,7 @@ namespace JS {
/**
* Create a new ArrayBuffer with the given byte length.
*/
extern JS_PUBLIC_API JSObject* NewArrayBuffer(JSContext* cx, uint32_t nbytes);
extern JS_PUBLIC_API JSObject* NewArrayBuffer(JSContext* cx, size_t nbytes);
/**
* Create a new ArrayBuffer with the given |contents|, which may be null only
@ -196,7 +196,7 @@ extern JS_PUBLIC_API JSObject* UnwrapArrayBuffer(JSObject* obj);
* |*data|.
*/
extern JS_PUBLIC_API JSObject* GetObjectAsArrayBuffer(JSObject* obj,
uint32_t* length,
size_t* length,
uint8_t** data);
/**
@ -206,7 +206,7 @@ extern JS_PUBLIC_API JSObject* GetObjectAsArrayBuffer(JSObject* obj,
* 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);
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.
@ -214,7 +214,7 @@ extern JS_PUBLIC_API uint32_t GetArrayBufferByteLength(JSObject* obj);
// 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,
size_t* length,
bool* isSharedMemory,
uint8_t** data);
@ -258,6 +258,12 @@ extern JS_PUBLIC_API bool DetachArrayBuffer(JSContext* cx,
extern JS_PUBLIC_API void* StealArrayBufferContents(JSContext* cx,
Handle<JSObject*> obj);
/**
* 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);
} // namespace JS
#endif /* js_ArrayBuffer_h */

View File

@ -62,7 +62,7 @@ extern JS_PUBLIC_API JSObject* UnwrapArrayBufferMaybeShared(JSObject* obj);
* |*data| will be set to a pointer to the bytes in the buffer.
*/
extern JS_PUBLIC_API void GetArrayBufferMaybeSharedLengthAndData(
JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data);
JSObject* obj, size_t* length, bool* isSharedMemory, uint8_t** data);
/**
* Return a pointer to the start of the array buffer's data, and indicate
@ -88,6 +88,14 @@ extern JS_PUBLIC_API void GetArrayBufferMaybeSharedLengthAndData(
extern JS_PUBLIC_API uint8_t* GetArrayBufferMaybeSharedData(
JSObject* obj, bool* isSharedMemory, const AutoRequireNoGC&);
/**
* Returns whether the passed array buffer is 'large': its byteLength >= 2 GB.
* See also SetLargeArrayBuffersEnabled.
*
* |obj| must pass a JS::IsArrayBufferObjectMaybeShared test.
*/
extern JS_FRIEND_API bool IsLargeArrayBufferMaybeShared(JSObject* obj);
} // namespace JS
#endif /* js_ArrayBufferMaybeShared_h */

View File

@ -11,8 +11,6 @@
#ifndef js_BuildId_h
#define js_BuildId_h
#include "mozilla/Attributes.h" // MOZ_MUST_USE
#include "jstypes.h" // JS_PUBLIC_API
#include "js/Vector.h" // js::Vector
@ -56,7 +54,7 @@ extern JS_PUBLIC_API void SetProcessBuildIdOp(BuildIdOp buildIdOp);
* on having consistent buildId *and* on the CPU supporting features identical
* to those in play when the cached data was computed.
*/
extern MOZ_MUST_USE JS_PUBLIC_API bool GetOptimizedEncodingBuildId(
[[nodiscard]] extern JS_PUBLIC_API bool GetOptimizedEncodingBuildId(
BuildIdCharVector* buildId);
/**
@ -75,7 +73,7 @@ extern MOZ_MUST_USE JS_PUBLIC_API bool GetOptimizedEncodingBuildId(
* Embedders should use this function to tag transcoded bytecode.
* See Transcoding.h.
*/
extern MOZ_MUST_USE JS_PUBLIC_API bool GetScriptTranscodingBuildId(
[[nodiscard]] extern JS_PUBLIC_API bool GetScriptTranscodingBuildId(
BuildIdCharVector* buildId);
} // namespace JS

View File

@ -70,7 +70,7 @@ namespace JS {
*
* Users don't have to call `result.report()`; another possible ending is:
*
* argv.rval().setBoolean(result.reallyOk());
* argv.rval().setBoolean(result.ok());
* return true;
*/
class ObjectOpResult {
@ -89,25 +89,16 @@ class ObjectOpResult {
public:
enum SpecialCodes : uintptr_t { OkCode = 0, Uninitialized = uintptr_t(-1) };
static const uintptr_t SoftFailBit = uintptr_t(1)
<< (sizeof(uintptr_t) * 8 - 1);
ObjectOpResult() : code_(Uninitialized) {}
/* Return true if succeed() or failSoft() was called. */
bool ok() const {
MOZ_ASSERT(code_ != Uninitialized);
return code_ == OkCode || (code_ & SoftFailBit);
}
explicit operator bool() const { return ok(); }
/* Return true if succeed() was called. */
bool reallyOk() const {
bool ok() const {
MOZ_ASSERT(code_ != Uninitialized);
return code_ == OkCode;
}
explicit operator bool() const { return ok(); }
/* Set this ObjectOpResult to true and return true. */
bool succeed() {
code_ = OkCode;
@ -128,26 +119,10 @@ class ObjectOpResult {
*/
bool fail(uint32_t msg) {
MOZ_ASSERT(msg != OkCode);
MOZ_ASSERT((msg & SoftFailBit) == 0);
code_ = msg;
return true;
}
/*
* DEPRECATED: This is a non-standard compatibility hack.
*
* Set this ObjectOpResult to true, but remembers an error code.
* This is used for situations where we really want to fail,
* but can't for legacy reasons.
*
* Always returns true, as a convenience.
*/
bool failSoft(uint32_t msg) {
// The msg code is currently never extracted again.
code_ = msg | SoftFailBit;
return true;
}
JS_PUBLIC_API bool failCantRedefineProp();
JS_PUBLIC_API bool failReadOnly();
JS_PUBLIC_API bool failGetterOnly();
@ -813,7 +788,19 @@ struct alignas(js::gc::JSClassAlignBytes) JSClass {
*/
static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
bool isNative() const { return !(flags & NON_NATIVE); }
// A JSObject created from a JSClass extends from one of:
// - js::NativeObject
// - js::ProxyObject
//
// While it is possible to introduce new families of objects, it is strongly
// discouraged. The JITs would be entirely unable to optimize them and testing
// coverage is low. The existing NativeObject and ProxyObject are extremely
// flexible and are able to represent the entire Gecko embedding requirements.
//
// NOTE: Internal to SpiderMonkey, there is an experimental js::TypedObject
// object family for future WASM features.
bool isNativeObject() const { return !(flags & NON_NATIVE); }
bool isProxyObject() const { return flags & JSCLASS_IS_PROXY; }
bool hasPrivate() const { return !!(flags & JSCLASS_HAS_PRIVATE); }
@ -822,14 +809,12 @@ struct alignas(js::gc::JSClassAlignBytes) JSClass {
bool isJSFunction() const { return this == js::FunctionClassPtr; }
bool nonProxyCallable() const {
MOZ_ASSERT(!isProxy());
MOZ_ASSERT(!isProxyObject());
return isJSFunction() || getCall();
}
bool isGlobal() const { return flags & JSCLASS_IS_GLOBAL; }
bool isProxy() const { return flags & JSCLASS_IS_PROXY; }
bool isDOMClass() const { return flags & JSCLASS_IS_DOMJSCLASS; }
bool shouldDelayMetadataBuilder() const {

View File

@ -51,7 +51,6 @@
#ifndef js_CompileOptions_h
#define js_CompileOptions_h
#include "mozilla/Attributes.h" // MOZ_MUST_USE
#include "mozilla/MemoryReporting.h" // mozilla::MallocSizeOf
#include <stddef.h> // size_t
@ -131,6 +130,7 @@ class JS_PUBLIC_API TransitiveCompileOptions {
bool nonSyntacticScope = false;
bool privateClassFields = false;
bool privateClassMethods = false;
bool topLevelAwait = false;
// True if transcoding to XDR should use Stencil instead of JSScripts.
bool useStencilXDR = false;

View File

@ -26,6 +26,10 @@ class JS_PUBLIC_API ContextOptions {
wasmFunctionReferences_(false),
wasmGc_(false),
wasmMultiValue_(false),
#ifdef ENABLE_WASM_SIMD
wasmSimd_(false),
#endif
wasmExceptions_(false),
testWasmAwaitTier2_(false),
throwOnAsmJSValidationFailure_(false),
disableIon_(false),
@ -42,7 +46,8 @@ class JS_PUBLIC_API ContextOptions {
#endif
fuzzing_(false),
privateClassFields_(false),
privateClassMethods_(false) {
privateClassMethods_(false),
topLevelAwait_(false) {
}
bool asmJS() const { return asmJS_; }
@ -111,6 +116,16 @@ class JS_PUBLIC_API ContextOptions {
// Defined out-of-line because it depends on a compile-time option
ContextOptions& setWasmMultiValue(bool flag);
#ifdef ENABLE_WASM_SIMD
bool wasmSimd() const { return wasmSimd_; }
// Defined out-of-line because it depends on a compile-time option
ContextOptions& setWasmSimd(bool flag);
#endif
bool wasmExceptions() const { return wasmExceptions_; }
// Defined out-of-line because it depends on a compile-time option
ContextOptions& setWasmExceptions(bool flag);
bool throwOnAsmJSValidationFailure() const {
return throwOnAsmJSValidationFailure_;
}
@ -144,6 +159,12 @@ class JS_PUBLIC_API ContextOptions {
return *this;
}
bool topLevelAwait() const { return topLevelAwait_; }
ContextOptions& setTopLevelAwait(bool enabled) {
topLevelAwait_ = enabled;
return *this;
}
// Override to allow disabling the eval restriction security checks for
// this context.
bool disableEvalSecurityChecks() const { return disableEvalSecurityChecks_; }
@ -222,6 +243,9 @@ class JS_PUBLIC_API ContextOptions {
void disableOptionsForSafeMode() {
setAsmJS(false);
setWasmBaseline(false);
#ifdef ENABLE_WASM_SIMD
setWasmSimd(false);
#endif
}
private:
@ -235,6 +259,10 @@ class JS_PUBLIC_API ContextOptions {
bool wasmFunctionReferences_ : 1;
bool wasmGc_ : 1;
bool wasmMultiValue_ : 1;
#ifdef ENABLE_WASM_SIMD
bool wasmSimd_ : 1;
#endif
bool wasmExceptions_ : 1;
bool testWasmAwaitTier2_ : 1;
bool throwOnAsmJSValidationFailure_ : 1;
bool disableIon_ : 1;
@ -252,6 +280,7 @@ class JS_PUBLIC_API ContextOptions {
bool fuzzing_ : 1;
bool privateClassFields_ : 1;
bool privateClassMethods_ : 1;
bool topLevelAwait_ : 1;
};
JS_PUBLIC_API ContextOptions& ContextOptionsRef(JSContext* cx);

View File

@ -10,7 +10,7 @@
#ifndef js_ForOfIterator_h
#define js_ForOfIterator_h
#include "mozilla/Attributes.h" // MOZ_MUST_USE, MOZ_STACK_CLASS
#include "mozilla/Attributes.h" // MOZ_STACK_CLASS
#include <stdint.h> // UINT32_MAX, uint32_t
@ -85,7 +85,7 @@ class MOZ_STACK_CLASS JS_PUBLIC_API ForOfIterator {
* return true instead of throwing. Callers must then check
* valueIsIterable() before continuing with the iteration.
*/
MOZ_MUST_USE bool init(
[[nodiscard]] bool init(
Handle<Value> iterable,
NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable);
@ -93,7 +93,7 @@ class MOZ_STACK_CLASS JS_PUBLIC_API ForOfIterator {
* Get the next value from the iterator. If false *done is true
* after this call, do not examine val.
*/
MOZ_MUST_USE bool next(MutableHandle<Value> val, bool* done);
[[nodiscard]] bool next(MutableHandle<Value> val, bool* done);
/**
* Close the iterator.

View File

@ -28,20 +28,6 @@ struct Statistics;
} // namespace gcstats
} // namespace js
typedef enum JSGCMode {
/** Perform only global GCs. */
JSGC_MODE_GLOBAL = 0,
/** Perform per-zone GCs until too much garbage has accumulated. */
JSGC_MODE_ZONE = 1,
/** Collect in short time slices rather than all at once. */
JSGC_MODE_INCREMENTAL = 2,
/** Both of the above. */
JSGC_MODE_ZONE_INCREMENTAL = 3,
} JSGCMode;
/**
* Kinds of js_GC invocation.
*/
@ -84,14 +70,21 @@ typedef enum JSGCParamKey {
JSGC_NUMBER = 4,
/**
* Select GC mode.
* Whether incremental GC is enabled. If not, GC will always run to
* completion.
*
* See: JSGCMode in GCAPI.h
* prefs: javascript.options.mem.gc_per_zone and
* javascript.options.mem.gc_incremental.
* Default: JSGC_MODE_ZONE_INCREMENTAL
* prefs: javascript.options.mem.gc_incremental.
* Default: false
*/
JSGC_MODE = 6,
JSGC_INCREMENTAL_GC_ENABLED = 5,
/**
* Whether per-zone GC is enabled. If not, all zones are collected every time.
*
* prefs: javascript.options.mem.gc_per_zone
* Default: false
*/
JSGC_PER_ZONE_GC_ENABLED = 6,
/** Number of cached empty GC chunks. */
JSGC_UNUSED_CHUNKS = 7,
@ -102,6 +95,8 @@ typedef enum JSGCParamKey {
/**
* Max milliseconds to spend in an incremental GC slice.
*
* A value of zero means there is no maximum.
*
* Pref: javascript.options.mem.gc_incremental_slice_ms
* Default: DefaultTimeBudgetMS.
*/
@ -383,6 +378,22 @@ typedef enum JSGCParamKey {
* nursery.)
*/
JSGC_PRETENURE_STRING_THRESHOLD = 42,
/**
* If the finalization rate of the tenured strings exceeds this threshold,
* string will be allocated in nursery.
*/
JSGC_STOP_PRETENURE_STRING_THRESHOLD = 43,
/**
* A number that is incremented on every major GC slice.
*/
JSGC_MAJOR_GC_NUMBER = 44,
/**
* A number that is incremented on every minor GC.
*/
JSGC_MINOR_GC_NUMBER = 45,
} JSGCParamKey;
/*
@ -506,7 +517,7 @@ namespace JS {
D(DOM_WINDOW_UTILS, FIRST_FIREFOX_REASON) \
D(COMPONENT_UTILS, 34) \
D(MEM_PRESSURE, 35) \
D(CC_WAITING, 36) \
D(CC_FINISHED, 36) \
D(CC_FORCED, 37) \
D(LOAD_END, 38) \
D(UNUSED3, 39) \
@ -571,7 +582,7 @@ extern JS_PUBLIC_API bool InternalGCReason(JS::GCReason reason);
/**
* Schedule the given zone to be collected as part of the next GC.
*/
extern JS_PUBLIC_API void PrepareZoneForGC(Zone* zone);
extern JS_PUBLIC_API void PrepareZoneForGC(JSContext* cx, Zone* zone);
/**
* Schedule all zones to be collected in the next GC.
@ -595,7 +606,7 @@ extern JS_PUBLIC_API bool IsGCScheduled(JSContext* cx);
* Undoes the effect of the Prepare methods above. The given zone will not be
* collected in the next GC.
*/
extern JS_PUBLIC_API void SkipZoneForGC(Zone* zone);
extern JS_PUBLIC_API void SkipZoneForGC(JSContext* cx, Zone* zone);
/*
* Non-Incremental GC:
@ -629,8 +640,7 @@ extern JS_PUBLIC_API void NonIncrementalGC(JSContext* cx,
* must be met:
* - The collection must be run by calling JS::IncrementalGC() rather than
* JS_GC().
* - The GC mode must have been set to JSGC_MODE_INCREMENTAL or
* JSGC_MODE_ZONE_INCREMENTAL with JS_SetGCParameter().
* - The GC parameter JSGC_INCREMENTAL_GC_ENABLED must be true.
*
* Note: Even if incremental GC is enabled and working correctly,
* non-incremental collections can still happen when low on memory.

View File

@ -356,7 +356,7 @@ class MutableWrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper>
void clear() { set().clear(); }
void clearAndCompact() { set().clearAndCompact(); }
MOZ_MUST_USE bool reserve(uint32_t len) { return set().reserve(len); }
[[nodiscard]] bool reserve(uint32_t len) { return set().reserve(len); }
void remove(Ptr p) { set().remove(p); }
void remove(const Lookup& l) { set().remove(l); }
AddPtr lookupForAdd(const Lookup& l) { return set().lookupForAdd(l); }

View File

@ -7,6 +7,7 @@
#include "mozilla/Vector.h"
#include "js/AllocPolicy.h"
#include "js/GCPolicyAPI.h"
#include "js/RootingAPI.h"
#include "js/TracingAPI.h"
@ -63,11 +64,11 @@ class GCVector {
const T& back() const { return vector.back(); }
bool initCapacity(size_t cap) { return vector.initCapacity(cap); }
MOZ_MUST_USE bool reserve(size_t req) { return vector.reserve(req); }
[[nodiscard]] bool reserve(size_t req) { return vector.reserve(req); }
void shrinkBy(size_t amount) { return vector.shrinkBy(amount); }
void shrinkTo(size_t newLen) { return vector.shrinkTo(newLen); }
MOZ_MUST_USE bool growBy(size_t amount) { return vector.growBy(amount); }
MOZ_MUST_USE bool resize(size_t newLen) { return vector.resize(newLen); }
[[nodiscard]] bool growBy(size_t amount) { return vector.growBy(amount); }
[[nodiscard]] bool resize(size_t newLen) { return vector.resize(newLen); }
void clear() { return vector.clear(); }
void clearAndFree() { return vector.clearAndFree(); }
@ -89,7 +90,7 @@ class GCVector {
}
template <typename... Args>
MOZ_MUST_USE bool emplaceBack(Args&&... args) {
[[nodiscard]] bool emplaceBack(Args&&... args) {
return vector.emplaceBack(std::forward<Args>(args)...);
}
@ -115,20 +116,25 @@ class GCVector {
}
template <typename U>
MOZ_MUST_USE bool appendAll(const U& aU) {
[[nodiscard]] bool appendAll(const U& aU) {
return vector.append(aU.begin(), aU.end());
}
template <typename T2, size_t MinInlineCapacity2, typename AllocPolicy2>
[[nodiscard]] bool appendAll(
GCVector<T2, MinInlineCapacity2, AllocPolicy2>&& aU) {
return vector.appendAll(aU.begin(), aU.end());
}
MOZ_MUST_USE bool appendN(const T& val, size_t count) {
[[nodiscard]] bool appendN(const T& val, size_t count) {
return vector.appendN(val, count);
}
template <typename U>
MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd) {
[[nodiscard]] bool append(const U* aBegin, const U* aEnd) {
return vector.append(aBegin, aEnd);
}
template <typename U>
MOZ_MUST_USE bool append(const U* aBegin, size_t aLength) {
[[nodiscard]] bool append(const U* aBegin, size_t aLength) {
return vector.append(aBegin, aLength);
}
@ -247,32 +253,34 @@ class MutableWrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>,
return JS::MutableHandle<T>::fromMarkedLocation(&vec().operator[](aIndex));
}
MOZ_MUST_USE bool initCapacity(size_t aRequest) {
[[nodiscard]] bool initCapacity(size_t aRequest) {
return vec().initCapacity(aRequest);
}
MOZ_MUST_USE bool reserve(size_t aRequest) { return vec().reserve(aRequest); }
[[nodiscard]] bool reserve(size_t aRequest) {
return vec().reserve(aRequest);
}
void shrinkBy(size_t aIncr) { vec().shrinkBy(aIncr); }
MOZ_MUST_USE bool growBy(size_t aIncr) { return vec().growBy(aIncr); }
MOZ_MUST_USE bool resize(size_t aNewLength) {
[[nodiscard]] bool growBy(size_t aIncr) { return vec().growBy(aIncr); }
[[nodiscard]] bool resize(size_t aNewLength) {
return vec().resize(aNewLength);
}
MOZ_MUST_USE bool growByUninitialized(size_t aIncr) {
[[nodiscard]] bool growByUninitialized(size_t aIncr) {
return vec().growByUninitialized(aIncr);
}
void infallibleGrowByUninitialized(size_t aIncr) {
vec().infallibleGrowByUninitialized(aIncr);
}
MOZ_MUST_USE bool resizeUninitialized(size_t aNewLength) {
[[nodiscard]] bool resizeUninitialized(size_t aNewLength) {
return vec().resizeUninitialized(aNewLength);
}
void clear() { vec().clear(); }
void clearAndFree() { vec().clearAndFree(); }
template <typename U>
MOZ_MUST_USE bool append(U&& aU) {
[[nodiscard]] bool append(U&& aU) {
return vec().append(std::forward<U>(aU));
}
template <typename... Args>
MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) {
[[nodiscard]] bool emplaceBack(Args&&... aArgs) {
return vec().emplaceBack(std::forward<Args>(aArgs)...);
}
template <typename... Args>
@ -280,18 +288,18 @@ class MutableWrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>,
vec().infallibleEmplaceBack(std::forward<Args>(args)...);
}
template <typename U>
MOZ_MUST_USE bool appendAll(const U& aU) {
[[nodiscard]] bool appendAll(U&& aU) {
return vec().appendAll(aU);
}
MOZ_MUST_USE bool appendN(const T& aT, size_t aN) {
[[nodiscard]] bool appendN(const T& aT, size_t aN) {
return vec().appendN(aT, aN);
}
template <typename U>
MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd) {
[[nodiscard]] bool append(const U* aBegin, const U* aEnd) {
return vec().append(aBegin, aEnd);
}
template <typename U>
MOZ_MUST_USE bool append(const U* aBegin, size_t aLength) {
[[nodiscard]] bool append(const U* aBegin, size_t aLength) {
return vec().append(aBegin, aLength);
}
template <typename U>

View File

@ -6,6 +6,7 @@
#define js_HeapAPI_h
#include "mozilla/Atomics.h"
#include "mozilla/BitSet.h"
#include <limits.h>
#include <type_traits>
@ -29,11 +30,16 @@ struct JSExternalStringCallbacks;
/* These values are private to the JS engine. */
namespace js {
class NurseryDecommitTask;
JS_FRIEND_API bool CurrentThreadCanAccessZone(JS::Zone* zone);
namespace gc {
class Arena;
struct Cell;
class TenuredChunk;
class StoreBuffer;
class TenuredCell;
const size_t ArenaShift = 12;
@ -53,39 +59,114 @@ const size_t CellAlignBytes = size_t(1) << CellAlignShift;
const size_t CellAlignMask = CellAlignBytes - 1;
const size_t CellBytesPerMarkBit = CellAlignBytes;
const size_t MarkBitsPerCell = 2;
/*
* We sometimes use an index to refer to a cell in an arena. The index for a
* cell is found by dividing by the cell alignment so not all indicies refer to
* valid cells.
* The mark bitmap has one bit per each possible cell start position. This
* wastes some space for larger GC things but allows us to avoid division by the
* cell's size when accessing the bitmap.
*/
const size_t ArenaCellIndexBytes = CellAlignBytes;
const size_t MaxArenaCellIndex = ArenaSize / CellAlignBytes;
const size_t ArenaBitmapBits = ArenaSize / CellBytesPerMarkBit;
const size_t ArenaBitmapBytes = HowMany(ArenaBitmapBits, 8);
const size_t ArenaBitmapWords = HowMany(ArenaBitmapBits, JS_BITS_PER_WORD);
/* These are magic constants derived from actual offsets in gc/Heap.h. */
// The base class for all GC chunks, either in the nursery or in the tenured
// heap memory. This structure is locatable from any GC pointer by aligning to
// the chunk size.
class alignas(CellAlignBytes) ChunkBase {
protected:
ChunkBase(JSRuntime* rt, StoreBuffer* sb) : storeBuffer(sb), runtime(rt) {
MOZ_ASSERT((uintptr_t(this) & ChunkMask) == 0);
}
public:
// The store buffer for pointers from tenured things to things in this
// chunk. Will be non-null if and only if this is a nursery chunk.
StoreBuffer* storeBuffer;
// Provide quick access to the runtime from absolutely anywhere.
JSRuntime* runtime;
};
// Information about tenured heap chunks.
struct TenuredChunkInfo {
private:
friend class ChunkPool;
TenuredChunk* next = nullptr;
TenuredChunk* prev = nullptr;
public:
/* List of free committed arenas, linked together with arena.next. */
Arena* freeArenasHead;
/*
* Decommitted arenas are tracked by a bitmap in the TenuredChunkBase. We use
* this offset to start our search iteration close to a decommitted arena that
* we can allocate.
*/
uint32_t lastDecommittedArenaOffset;
/* Number of free arenas, either committed or decommitted. */
uint32_t numArenasFree;
/* Number of free, committed arenas. */
uint32_t numArenasFreeCommitted;
};
/*
* Calculating ArenasPerChunk:
*
* To figure out how many Arenas will fit in a chunk we need to know how much
* extra space is available after we allocate the header data. This is a problem
* because the header size depends on the number of arenas in the chunk.
*
* The two dependent fields are bitmap and decommittedArenas. bitmap needs
* ArenaBitmapBytes bytes per arena and decommittedArenas needs one bit per
* arena.
*
* We can calculate an approximate value by dividing the number of bits of free
* space in the chunk by the number of bits needed per arena. This is an
* approximation because it doesn't take account of the fact that the variable
* sized fields must be rounded up to a whole number of words, or any padding
* the compiler adds between fields.
*
* Fortunately, for the chunk and arena size parameters we use this
* approximation turns out to be correct. If it were not we might need to adjust
* the arena count down by one to allow more space for the padding.
*/
const size_t BitsPerArenaWithHeaders =
(ArenaSize + ArenaBitmapBytes) * CHAR_BIT + 1;
const size_t ChunkBitsAvailable =
(ChunkSize - sizeof(ChunkBase) - sizeof(TenuredChunkInfo)) * CHAR_BIT;
const size_t ArenasPerChunk = ChunkBitsAvailable / BitsPerArenaWithHeaders;
const size_t CalculatedChunkSizeRequired =
sizeof(ChunkBase) + sizeof(TenuredChunkInfo) +
RoundUp(ArenasPerChunk * ArenaBitmapBytes, sizeof(uintptr_t)) +
RoundUp(ArenasPerChunk, sizeof(uint32_t) * CHAR_BIT) / CHAR_BIT +
ArenasPerChunk * ArenaSize;
static_assert(CalculatedChunkSizeRequired <= ChunkSize,
"Calculated ArenasPerChunk is too large");
const size_t CalculatedChunkPadSize = ChunkSize - CalculatedChunkSizeRequired;
static_assert(CalculatedChunkPadSize * CHAR_BIT < BitsPerArenaWithHeaders,
"Calculated ArenasPerChunk is too small");
// Define a macro for the expected number of arenas so its value appears in the
// error message if the assertion fails.
#ifdef JS_GC_SMALL_CHUNK_SIZE
const size_t ChunkMarkBitmapOffset = 258104;
const size_t ChunkMarkBitmapBits = 31744;
# define EXPECTED_ARENA_COUNT 63
#else
const size_t ChunkMarkBitmapOffset = 1032352;
const size_t ChunkMarkBitmapBits = 129024;
# define EXPECTED_ARENA_COUNT 252
#endif
const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*);
const size_t ChunkTrailerSize = 2 * sizeof(uintptr_t) + sizeof(uint64_t);
const size_t ChunkLocationOffset = ChunkSize - ChunkTrailerSize;
const size_t ChunkStoreBufferOffset =
ChunkSize - ChunkTrailerSize + sizeof(uint64_t);
const size_t ArenaZoneOffset = sizeof(size_t);
const size_t ArenaHeaderSize =
sizeof(size_t) + 2 * sizeof(uintptr_t) + sizeof(size_t) + sizeof(uintptr_t);
static_assert(ArenasPerChunk == EXPECTED_ARENA_COUNT,
"Do not accidentally change our heap's density.");
#undef EXPECTED_ARENA_COUNT
// The first word of a GC thing has certain requirements from the GC and is used
// to store flags in the low bits.
const size_t CellFlagBitsReservedForGC = 3;
// The first word can be used to store JSClass pointers for some thing kinds, so
// these must be suitably aligned.
const size_t JSClassAlignBytes = size_t(1) << CellFlagBitsReservedForGC;
// Mark bitmaps are atomic because they can be written by gray unmarking on the
// main thread while read by sweeping on a background thread. The former does
// not affect the result of the latter.
using MarkBitmapWord = mozilla::Atomic<uintptr_t, mozilla::Relaxed>;
/*
* Live objects are marked black or gray. Everything reachable from a JS root is
@ -99,16 +180,83 @@ const size_t JSClassAlignBytes = size_t(1) << CellFlagBitsReservedForGC;
*/
enum class ColorBit : uint32_t { BlackBit = 0, GrayOrBlackBit = 1 };
/*
* The "location" field in the Chunk trailer is a enum indicating various roles
* of the chunk.
*/
enum class ChunkLocation : uint32_t {
Invalid = 0,
Nursery = 1,
TenuredHeap = 2
// Mark colors. Order is important here: the greater value the 'more marked' a
// cell is.
enum class MarkColor : uint8_t { Gray = 1, Black = 2 };
// Mark bitmap for a tenured heap chunk.
struct MarkBitmap {
static constexpr size_t WordCount = ArenaBitmapWords * ArenasPerChunk;
MarkBitmapWord bitmap[WordCount];
inline void getMarkWordAndMask(const TenuredCell* cell, ColorBit colorBit,
MarkBitmapWord** wordp, uintptr_t* maskp);
// The following are not exported and are defined in gc/Heap.h:
inline bool markBit(const TenuredCell* cell, ColorBit colorBit);
inline bool isMarkedAny(const TenuredCell* cell);
inline bool isMarkedBlack(const TenuredCell* cell);
inline bool isMarkedGray(const TenuredCell* cell);
inline bool markIfUnmarked(const TenuredCell* cell, MarkColor color);
inline void markBlack(const TenuredCell* cell);
inline void copyMarkBit(TenuredCell* dst, const TenuredCell* src,
ColorBit colorBit);
inline void unmark(const TenuredCell* cell);
inline void clear();
inline MarkBitmapWord* arenaBits(Arena* arena);
};
static_assert(ArenaBitmapBytes * ArenasPerChunk == sizeof(MarkBitmap),
"Ensure our MarkBitmap actually covers all arenas.");
// Decommit bitmap for a heap chunk.
using DecommitBitmap = mozilla::BitSet<ArenasPerChunk, uint32_t>;
// Base class containing data members for a tenured heap chunk.
class TenuredChunkBase : public ChunkBase {
public:
TenuredChunkInfo info;
MarkBitmap markBits;
DecommitBitmap decommittedArenas;
protected:
explicit TenuredChunkBase(JSRuntime* runtime) : ChunkBase(runtime, nullptr) {}
};
/*
* We sometimes use an index to refer to a cell in an arena. The index for a
* cell is found by dividing by the cell alignment so not all indices refer to
* valid cells.
*/
const size_t ArenaCellIndexBytes = CellAlignBytes;
const size_t MaxArenaCellIndex = ArenaSize / CellAlignBytes;
const size_t MarkBitmapWordBits = sizeof(MarkBitmapWord) * CHAR_BIT;
constexpr size_t FirstArenaAdjustmentBits =
RoundUp(sizeof(gc::TenuredChunkBase), ArenaSize) / gc::CellBytesPerMarkBit;
static_assert((FirstArenaAdjustmentBits % MarkBitmapWordBits) == 0);
constexpr size_t FirstArenaAdjustmentWords =
FirstArenaAdjustmentBits / MarkBitmapWordBits;
const size_t ChunkRuntimeOffset = offsetof(ChunkBase, runtime);
const size_t ChunkStoreBufferOffset = offsetof(ChunkBase, storeBuffer);
const size_t ChunkMarkBitmapOffset = offsetof(TenuredChunkBase, markBits);
// Hardcoded offsets into Arena class.
const size_t ArenaZoneOffset = sizeof(size_t);
const size_t ArenaHeaderSize =
sizeof(size_t) + 2 * sizeof(uintptr_t) + sizeof(size_t) + sizeof(uintptr_t);
// The first word of a GC thing has certain requirements from the GC and is used
// to store flags in the low bits.
const size_t CellFlagBitsReservedForGC = 3;
// The first word can be used to store JSClass pointers for some thing kinds, so
// these must be suitably aligned.
const size_t JSClassAlignBytes = size_t(1) << CellFlagBitsReservedForGC;
#ifdef JS_DEBUG
/* When downcasting, ensure we are actually the right type. */
extern JS_FRIEND_API void AssertGCThingHasType(js::gc::Cell* cell,
@ -118,6 +266,7 @@ inline void AssertGCThingHasType(js::gc::Cell* cell, JS::TraceKind kind) {}
#endif
MOZ_ALWAYS_INLINE bool IsInsideNursery(const js::gc::Cell* cell);
MOZ_ALWAYS_INLINE bool IsInsideNursery(const js::gc::TenuredCell* cell);
} /* namespace gc */
} /* namespace js */
@ -333,36 +482,35 @@ inline bool operator!=(const JS::GCCellPtr& ptr1, const JS::GCCellPtr& ptr2) {
namespace js {
namespace gc {
// Mark bitmaps are atomic because they can be written by gray unmarking on the
// main thread while read by sweeping on a background thread. The former does
// not affect the result of the latter.
using MarkBitmapWord = mozilla::Atomic<uintptr_t, mozilla::Relaxed>;
/* static */
MOZ_ALWAYS_INLINE void MarkBitmap::getMarkWordAndMask(const TenuredCell* cell,
ColorBit colorBit,
MarkBitmapWord** wordp,
uintptr_t* maskp) {
// Note: the JIT pre-barrier trampolines inline this code. Update
// MacroAssembler::emitPreBarrierFastPath code too when making changes here!
MOZ_ASSERT(size_t(colorBit) < MarkBitsPerCell);
size_t offset = uintptr_t(cell) & ChunkMask;
const size_t bit = offset / CellBytesPerMarkBit + size_t(colorBit);
size_t word = bit / MarkBitmapWordBits - FirstArenaAdjustmentWords;
MOZ_ASSERT(word < WordCount);
*wordp = &bitmap[word];
*maskp = uintptr_t(1) << (bit % MarkBitmapWordBits);
}
namespace detail {
static MOZ_ALWAYS_INLINE MarkBitmapWord* GetGCThingMarkBitmap(
const uintptr_t addr) {
// Note: the JIT pre-barrier trampolines inline this code. Update that
// code too when making changes here!
MOZ_ASSERT(addr);
const uintptr_t bmap_addr = (addr & ~ChunkMask) | ChunkMarkBitmapOffset;
return reinterpret_cast<MarkBitmapWord*>(bmap_addr);
static MOZ_ALWAYS_INLINE ChunkBase* GetCellChunkBase(const Cell* cell) {
MOZ_ASSERT(cell);
return reinterpret_cast<ChunkBase*>(uintptr_t(cell) & ~ChunkMask);
}
static MOZ_ALWAYS_INLINE void GetGCThingMarkWordAndMask(const uintptr_t addr,
ColorBit colorBit,
MarkBitmapWord** wordp,
uintptr_t* maskp) {
// Note: the JIT pre-barrier trampolines inline this code. Update that
// code too when making changes here!
MOZ_ASSERT(addr);
const size_t bit = (addr & js::gc::ChunkMask) / js::gc::CellBytesPerMarkBit +
static_cast<uint32_t>(colorBit);
MOZ_ASSERT(bit < js::gc::ChunkMarkBitmapBits);
MarkBitmapWord* bitmap = GetGCThingMarkBitmap(addr);
const uintptr_t nbits = sizeof(*bitmap) * CHAR_BIT;
*maskp = uintptr_t(1) << (bit % nbits);
*wordp = &bitmap[bit / nbits];
static MOZ_ALWAYS_INLINE TenuredChunkBase* GetCellChunkBase(
const TenuredCell* cell) {
MOZ_ASSERT(cell);
return reinterpret_cast<TenuredChunkBase*>(uintptr_t(cell) & ~ChunkMask);
}
static MOZ_ALWAYS_INLINE JS::Zone* GetTenuredGCThingZone(const uintptr_t addr) {
@ -371,23 +519,24 @@ static MOZ_ALWAYS_INLINE JS::Zone* GetTenuredGCThingZone(const uintptr_t addr) {
return *reinterpret_cast<JS::Zone**>(zone_addr);
}
static MOZ_ALWAYS_INLINE bool TenuredCellIsMarkedGray(const Cell* cell) {
static MOZ_ALWAYS_INLINE bool TenuredCellIsMarkedGray(const TenuredCell* cell) {
// Return true if GrayOrBlackBit is set and BlackBit is not set.
MOZ_ASSERT(cell);
MOZ_ASSERT(!js::gc::IsInsideNursery(cell));
MarkBitmapWord* grayWord;
uintptr_t grayMask;
js::gc::detail::GetGCThingMarkWordAndMask(
uintptr_t(cell), js::gc::ColorBit::GrayOrBlackBit, &grayWord, &grayMask);
TenuredChunkBase* chunk = GetCellChunkBase(cell);
chunk->markBits.getMarkWordAndMask(cell, js::gc::ColorBit::GrayOrBlackBit,
&grayWord, &grayMask);
if (!(*grayWord & grayMask)) {
return false;
}
MarkBitmapWord* blackWord;
uintptr_t blackMask;
js::gc::detail::GetGCThingMarkWordAndMask(
uintptr_t(cell), js::gc::ColorBit::BlackBit, &blackWord, &blackMask);
chunk->markBits.getMarkWordAndMask(cell, js::gc::ColorBit::BlackBit,
&blackWord, &blackMask);
return !(*blackWord & blackMask);
}
@ -396,7 +545,7 @@ static MOZ_ALWAYS_INLINE bool CellIsMarkedGray(const Cell* cell) {
if (js::gc::IsInsideNursery(cell)) {
return false;
}
return TenuredCellIsMarkedGray(cell);
return TenuredCellIsMarkedGray(reinterpret_cast<const TenuredCell*>(cell));
}
extern JS_PUBLIC_API bool CellIsMarkedGrayIfKnown(const Cell* cell);
@ -407,18 +556,8 @@ extern JS_PUBLIC_API void AssertCellIsNotGray(const Cell* cell);
extern JS_PUBLIC_API bool ObjectIsMarkedBlack(const JSObject* obj);
#endif
MOZ_ALWAYS_INLINE ChunkLocation GetCellLocation(const void* cell) {
uintptr_t addr = uintptr_t(cell);
addr &= ~js::gc::ChunkMask;
addr |= js::gc::ChunkLocationOffset;
return *reinterpret_cast<ChunkLocation*>(addr);
}
MOZ_ALWAYS_INLINE bool NurseryCellHasStoreBuffer(const void* cell) {
uintptr_t addr = uintptr_t(cell);
addr &= ~js::gc::ChunkMask;
addr |= js::gc::ChunkStoreBufferOffset;
return *reinterpret_cast<void**>(addr) != nullptr;
MOZ_ALWAYS_INLINE bool CellHasStoreBuffer(const Cell* cell) {
return GetCellChunkBase(cell)->storeBuffer;
}
} /* namespace detail */
@ -427,15 +566,12 @@ MOZ_ALWAYS_INLINE bool IsInsideNursery(const Cell* cell) {
if (!cell) {
return false;
}
auto location = detail::GetCellLocation(cell);
MOZ_ASSERT(location == ChunkLocation::Nursery ||
location == ChunkLocation::TenuredHeap);
return location == ChunkLocation::Nursery;
return detail::CellHasStoreBuffer(cell);
}
MOZ_ALWAYS_INLINE bool IsInsideNursery(const TenuredCell* cell) {
MOZ_ASSERT_IF(cell,
detail::GetCellLocation(cell) == ChunkLocation::TenuredHeap);
MOZ_ASSERT_IF(
cell, !detail::CellHasStoreBuffer(reinterpret_cast<const Cell*>(cell)));
return false;
}
@ -451,19 +587,18 @@ MOZ_ALWAYS_INLINE bool IsInsideNursery(const JS::BigInt* bi) {
return IsInsideNursery(reinterpret_cast<const Cell*>(bi));
}
MOZ_ALWAYS_INLINE bool IsCellPointerValid(const void* cell) {
auto addr = uintptr_t(cell);
MOZ_ALWAYS_INLINE bool IsCellPointerValid(const void* ptr) {
auto addr = uintptr_t(ptr);
if (addr < ChunkSize || addr % CellAlignBytes != 0) {
return false;
}
auto location = detail::GetCellLocation(cell);
if (location == ChunkLocation::TenuredHeap) {
return !!detail::GetTenuredGCThingZone(addr);
auto* cell = reinterpret_cast<const Cell*>(ptr);
if (!IsInsideNursery(cell)) {
return detail::GetTenuredGCThingZone(addr) != nullptr;
}
if (location == ChunkLocation::Nursery) {
return detail::NurseryCellHasStoreBuffer(cell);
}
return false;
return true;
}
MOZ_ALWAYS_INLINE bool IsCellPointerValidOrNull(const void* cell) {
@ -554,21 +689,12 @@ namespace gc {
extern JS_PUBLIC_API void PerformIncrementalReadBarrier(JS::GCCellPtr thing);
static MOZ_ALWAYS_INLINE bool IsIncrementalBarrierNeededOnTenuredGCThing(
const JS::GCCellPtr thing) {
MOZ_ASSERT(thing);
MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell()));
static MOZ_ALWAYS_INLINE void ExposeGCThingToActiveJS(JS::GCCellPtr thing) {
// TODO: I'd like to assert !RuntimeHeapIsBusy() here but this gets
// called while we are tracing the heap, e.g. during memory reporting
// (see bug 1313318).
MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
JS::Zone* zone = JS::GetTenuredGCThingZone(thing);
return JS::shadow::Zone::from(zone)->needsIncrementalBarrier();
}
static MOZ_ALWAYS_INLINE void ExposeGCThingToActiveJS(JS::GCCellPtr thing) {
// GC things residing in the nursery cannot be gray: they have no mark bits.
// All live objects in the nursery are moved to tenured at the beginning of
// each GC slice, so the gray marker never sees nursery things.
@ -576,19 +702,22 @@ static MOZ_ALWAYS_INLINE void ExposeGCThingToActiveJS(JS::GCCellPtr thing) {
return;
}
auto* cell = reinterpret_cast<TenuredCell*>(thing.asCell());
// There's nothing to do for permanent GC things that might be owned by
// another runtime.
if (thing.mayBeOwnedByOtherRuntime()) {
return;
}
if (IsIncrementalBarrierNeededOnTenuredGCThing(thing)) {
auto* zone = JS::shadow::Zone::from(JS::GetTenuredGCThingZone(thing));
if (zone->needsIncrementalBarrier()) {
PerformIncrementalReadBarrier(thing);
} else if (detail::TenuredCellIsMarkedGray(thing.asCell())) {
JS::UnmarkGrayGCThingRecursively(thing);
} else if (!zone->isGCPreparing() && detail::TenuredCellIsMarkedGray(cell)) {
MOZ_ALWAYS_TRUE(JS::UnmarkGrayGCThingRecursively(thing));
}
MOZ_ASSERT(!detail::TenuredCellIsMarkedGray(thing.asCell()));
MOZ_ASSERT_IF(!zone->isGCPreparing(), !detail::TenuredCellIsMarkedGray(cell));
}
template <typename T>

View File

@ -8,7 +8,6 @@
#define js_MemoryFunctions_h
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include "mozilla/Attributes.h" // MOZ_MUST_USE
#include <stddef.h> // size_t

View File

@ -626,7 +626,6 @@ struct ZoneStats {
MACRO(Other, MallocHeap, scopesMallocHeap) \
MACRO(Other, GCHeapUsed, regExpSharedsGCHeap) \
MACRO(Other, MallocHeap, regExpSharedsMallocHeap) \
MACRO(Other, MallocHeap, typePool) \
MACRO(Other, MallocHeap, regexpZone) \
MACRO(Other, MallocHeap, jitZone) \
MACRO(Other, MallocHeap, baselineStubsOptimized) \
@ -709,24 +708,21 @@ struct RealmStats {
// actually guaranteed. But for Servo, at least, it's a moot point because
// it doesn't provide an ObjectPrivateVisitor so the value will always be
// zero.
#define FOR_EACH_SIZE(MACRO) \
MACRO(Private, MallocHeap, objectsPrivate) \
MACRO(Other, GCHeapUsed, scriptsGCHeap) \
MACRO(Other, MallocHeap, scriptsMallocHeapData) \
MACRO(Other, MallocHeap, baselineData) \
MACRO(Other, MallocHeap, baselineStubsFallback) \
MACRO(Other, MallocHeap, ionData) \
MACRO(Other, MallocHeap, jitScripts) \
MACRO(Other, MallocHeap, typeInferenceAllocationSiteTables) \
MACRO(Other, MallocHeap, typeInferenceArrayTypeTables) \
MACRO(Other, MallocHeap, typeInferenceObjectTypeTables) \
MACRO(Other, MallocHeap, realmObject) \
MACRO(Other, MallocHeap, realmTables) \
MACRO(Other, MallocHeap, innerViewsTable) \
MACRO(Other, MallocHeap, objectMetadataTable) \
MACRO(Other, MallocHeap, savedStacksSet) \
MACRO(Other, MallocHeap, varNamesSet) \
MACRO(Other, MallocHeap, nonSyntacticLexicalScopesTable) \
#define FOR_EACH_SIZE(MACRO) \
MACRO(Private, MallocHeap, objectsPrivate) \
MACRO(Other, GCHeapUsed, scriptsGCHeap) \
MACRO(Other, MallocHeap, scriptsMallocHeapData) \
MACRO(Other, MallocHeap, baselineData) \
MACRO(Other, MallocHeap, baselineStubsFallback) \
MACRO(Other, MallocHeap, ionData) \
MACRO(Other, MallocHeap, jitScripts) \
MACRO(Other, MallocHeap, realmObject) \
MACRO(Other, MallocHeap, realmTables) \
MACRO(Other, MallocHeap, innerViewsTable) \
MACRO(Other, MallocHeap, objectMetadataTable) \
MACRO(Other, MallocHeap, savedStacksSet) \
MACRO(Other, MallocHeap, varNamesSet) \
MACRO(Other, MallocHeap, nonSyntacticLexicalScopesTable) \
MACRO(Other, MallocHeap, jitRealm)
RealmStats() = default;

View File

@ -88,10 +88,24 @@ enum class DynamicImportStatus { Failed = 0, Ok };
/**
* This must be called after a dynamic import operation is complete.
*
* If |status| is Failed, any pending exception on the context will be used to
* If |evaluationPromise| is rejected, the rejection reason will be used to
* complete the user's promise.
*/
extern JS_PUBLIC_API bool FinishDynamicModuleImport(
JSContext* cx, Handle<JSObject*> evaluationPromise,
Handle<Value> referencingPrivate, Handle<JSString*> specifier,
Handle<JSObject*> promise);
/**
* This must be called after a dynamic import operation is complete.
*
* This is used so that Top Level Await functionality can be turned off
* entirely. It will be removed in bug#1676612.
*
* If |status| is Failed, any pending exception on the context will be used to
* complete the user's promise.
*/
extern JS_PUBLIC_API bool FinishDynamicModuleImport_NoTLA(
JSContext* cx, DynamicImportStatus status, Handle<Value> referencingPrivate,
Handle<JSString*> specifier, Handle<JSObject*> promise);
@ -135,16 +149,32 @@ extern JS_PUBLIC_API bool ModuleInstantiate(JSContext* cx,
Handle<JSObject*> moduleRecord);
/*
* Perform the ModuleEvaluate operation on the given source text module record.
* Perform the ModuleEvaluate operation on the given source text module record
* and returns a bool. A result value is returned in result and is either
* undefined (and ignored) or a promise (if Top Level Await is enabled).
*
* This does nothing if this module has already been evaluated. Otherwise, it
* transitively evaluates all dependences of this module and then evaluates this
* module.
* If this module has already been evaluated, it returns the evaluation
* promise. Otherwise, it transitively evaluates all dependences of this module
* and then evaluates this module.
*
* ModuleInstantiate must have completed prior to calling this.
*/
extern JS_PUBLIC_API bool ModuleEvaluate(JSContext* cx,
Handle<JSObject*> moduleRecord);
Handle<JSObject*> moduleRecord,
MutableHandleValue rval);
/*
* If a module evaluation fails, unwrap the resulting evaluation promise
* and rethrow.
*
* This does nothing if this module succeeds in evaluation. Otherwise, it
* takes the reason for the module throwing, unwraps it and throws it as a
* regular error rather than as an uncaught promise.
*
* ModuleEvaluate must have completed prior to calling this.
*/
extern JS_PUBLIC_API bool ThrowOnModuleEvaluationFailure(
JSContext* cx, Handle<JSObject*> evaluationPromise);
/*
* Get a list of the module specifiers used by a source text module

View File

@ -59,19 +59,19 @@ using OffThreadCompileCallback = void (*)(OffThreadToken* token,
extern JS_PUBLIC_API bool CanCompileOffThread(
JSContext* cx, const ReadOnlyCompileOptions& options, size_t length);
extern JS_PUBLIC_API bool CompileOffThread(
extern JS_PUBLIC_API OffThreadToken* CompileOffThread(
JSContext* cx, const ReadOnlyCompileOptions& options,
SourceText<char16_t>& srcBuf, OffThreadCompileCallback callback,
void* callbackData, OffThreadToken** tokenOut = nullptr);
void* callbackData);
// NOTE: Unlike for the normal sync compilation functions, this function NEVER
// INFLATES TO UTF-16. Therefore, it is ALWAYS invoking experimental
// UTF-8 support. Inflate to UTF-16 yourself and use the other overload
// if you're unable to take a risk using unstable functionality.
extern JS_PUBLIC_API bool CompileOffThread(
extern JS_PUBLIC_API OffThreadToken* CompileOffThread(
JSContext* cx, const ReadOnlyCompileOptions& options,
SourceText<mozilla::Utf8Unit>& srcBuf, OffThreadCompileCallback callback,
void* callbackData, OffThreadToken** tokenOut = nullptr);
void* callbackData);
// Finish the off-thread parse/decode task and return the script. Return the
// script on success, or return null on failure (usually with an error reported)
@ -93,19 +93,19 @@ extern JS_PUBLIC_API JSScript* FinishOffThreadScriptAndStartIncrementalEncoding(
extern JS_PUBLIC_API void CancelOffThreadScript(JSContext* cx,
OffThreadToken* token);
extern JS_PUBLIC_API bool CompileOffThreadModule(
extern JS_PUBLIC_API OffThreadToken* CompileOffThreadModule(
JSContext* cx, const ReadOnlyCompileOptions& options,
SourceText<char16_t>& srcBuf, OffThreadCompileCallback callback,
void* callbackData, OffThreadToken** tokenOut = nullptr);
void* callbackData);
// NOTE: Unlike for the normal sync compilation functions, this function NEVER
// INFLATES TO UTF-16. Therefore, it is ALWAYS invoking experimental
// UTF-8 support. Inflate to UTF-16 yourself and use the other overload
// if you're unable to take a risk using unstable functionality.
extern JS_PUBLIC_API bool CompileOffThreadModule(
extern JS_PUBLIC_API OffThreadToken* CompileOffThreadModule(
JSContext* cx, const ReadOnlyCompileOptions& options,
SourceText<mozilla::Utf8Unit>& srcBuf, OffThreadCompileCallback callback,
void* callbackData, OffThreadToken** tokenOut = nullptr);
void* callbackData);
extern JS_PUBLIC_API JSObject* FinishOffThreadModule(JSContext* cx,
OffThreadToken* token);
@ -121,17 +121,26 @@ extern JS_PUBLIC_API bool CanDecodeOffThread(
//
// If options.useOffThreadParseGlobal is false,
// decode stencil from the buffer and instantiate JSScript from it.
extern JS_PUBLIC_API bool DecodeOffThreadScript(
//
// The start of `buffer` and `cursor` should meet
// IsTranscodingBytecodeAligned and IsTranscodingBytecodeOffsetAligned.
// (This should be handled while encoding).
//
// `buffer` should be alive until the end of `FinishOffThreadScriptDecoder`.
extern JS_PUBLIC_API OffThreadToken* DecodeOffThreadScript(
JSContext* cx, const ReadOnlyCompileOptions& options,
mozilla::Vector<uint8_t>& buffer /* TranscodeBuffer& */, size_t cursor,
OffThreadCompileCallback callback, void* callbackData,
OffThreadToken** tokenOut = nullptr);
OffThreadCompileCallback callback, void* callbackData);
extern JS_PUBLIC_API bool DecodeOffThreadScript(
// The start of `range` should be meet IsTranscodingBytecodeAligned and
// AlignTranscodingBytecodeOffset.
// (This should be handled while encoding).
//
// `range` should be alive until the end of `FinishOffThreadScriptDecoder`.
extern JS_PUBLIC_API OffThreadToken* DecodeOffThreadScript(
JSContext* cx, const ReadOnlyCompileOptions& options,
const mozilla::Range<uint8_t>& range /* TranscodeRange& */,
OffThreadCompileCallback callback, void* callbackData,
OffThreadToken** tokenOut = nullptr);
OffThreadCompileCallback callback, void* callbackData);
extern JS_PUBLIC_API JSScript* FinishOffThreadScriptDecoder(
JSContext* cx, OffThreadToken* token);
@ -140,7 +149,7 @@ extern JS_PUBLIC_API void CancelOffThreadScriptDecoder(JSContext* cx,
OffThreadToken* token);
// Decode multiple JSScript from the sources.
extern JS_PUBLIC_API bool DecodeMultiOffThreadScripts(
extern JS_PUBLIC_API OffThreadToken* DecodeMultiOffThreadScripts(
JSContext* cx, const ReadOnlyCompileOptions& options,
mozilla::Vector<TranscodeSource>& sources,
OffThreadCompileCallback callback, void* callbackData);

View File

@ -119,6 +119,8 @@
REAL(WasmMemory, OCLASP(WasmMemory)) \
REAL(WasmTable, OCLASP(WasmTable)) \
REAL(WasmGlobal, OCLASP(WasmGlobal)) \
REAL(WasmException, OCLASP(WasmException)) \
REAL(WasmRuntimeException, OCLASP(WasmRuntimeException)) \
REAL(FinalizationRegistry, OCLASP(FinalizationRegistry)) \
REAL(WeakRef, OCLASP(WeakRef)) \
REAL(Iterator, OCLASP(Iterator)) \

View File

@ -369,7 +369,7 @@ class JS_FRIEND_API BaseProxyHandler {
extern JS_FRIEND_DATA const JSClass ProxyClass;
inline bool IsProxy(const JSObject* obj) {
return JS::GetClass(obj)->isProxy();
return JS::GetClass(obj)->isProxyObject();
}
namespace detail {
@ -581,10 +581,6 @@ JS_FRIEND_API JSObject* NewProxyObject(
JSContext* cx, const BaseProxyHandler* handler, JS::HandleValue priv,
JSObject* proto, const ProxyOptions& options = ProxyOptions());
JS_FRIEND_API JSObject* NewSingletonProxyObject(
JSContext* cx, const BaseProxyHandler* handler, JS::HandleValue priv,
JSObject* proto, const ProxyOptions& options = ProxyOptions());
JSObject* RenewProxyObject(JSContext* cx, JSObject* obj,
BaseProxyHandler* handler, const JS::Value& priv);

View File

@ -46,6 +46,9 @@ enum class CompartmentSpecifier {
// Create a new realm in an existing compartment.
ExistingCompartment,
// Internal use only. Create the self-hosting compartment.
NewCompartmentInSelfHostingZone,
};
/**
@ -93,6 +96,7 @@ class JS_PUBLIC_API RealmCreationOptions {
RealmCreationOptions& setNewCompartmentAndZone();
RealmCreationOptions& setExistingCompartment(JSObject* obj);
RealmCreationOptions& setExistingCompartment(Compartment* compartment);
RealmCreationOptions& setNewCompartmentInSelfHostingZone();
// Certain compartments are implementation details of the embedding, and
// references to them should never leak out to script. This flag causes this
@ -349,9 +353,11 @@ extern JS_PUBLIC_API const RealmCreationOptions& RealmCreationOptionsRef(
extern JS_PUBLIC_API const RealmCreationOptions& RealmCreationOptionsRef(
JSContext* cx);
extern JS_PUBLIC_API RealmBehaviors& RealmBehaviorsRef(Realm* realm);
extern JS_PUBLIC_API const RealmBehaviors& RealmBehaviorsRef(Realm* realm);
extern JS_PUBLIC_API RealmBehaviors& RealmBehaviorsRef(JSContext* cx);
extern JS_PUBLIC_API const RealmBehaviors& RealmBehaviorsRef(JSContext* cx);
extern JS_PUBLIC_API void SetRealmNonLive(Realm* realm);
} // namespace JS

View File

@ -17,7 +17,7 @@ namespace JS {
/**
* Regular expression flag values, suitable for initializing a collection of
* regular expression flags as defined below in |RegExpFlags|. Flags are listed
* in alphabetical order by syntax -- /g, /i, /m, /s, /u, /y.
* in alphabetical order by syntax -- /d, /g, /i, /m, /s, /u, /y.
*/
class RegExpFlag {
// WARNING TO SPIDERMONKEY HACKERS (embedders must assume these values can
@ -28,35 +28,40 @@ class RegExpFlag {
// ascending order) unless you also add a translation layer.
public:
/**
* Add .indices property to the match result, i.e. /d
*/
static constexpr uint8_t HasIndices = 0b100'0000;
/**
* Act globally and find *all* matches (rather than stopping after just the
* first one), i.e. /g.
*/
static constexpr uint8_t Global = 0b00'0010;
static constexpr uint8_t Global = 0b000'0010;
/**
* Interpret regular expression source text case-insensitively by folding
* uppercase letters to lowercase, i.e. /i.
*/
static constexpr uint8_t IgnoreCase = 0b00'0001;
static constexpr uint8_t IgnoreCase = 0b000'0001;
/** Treat ^ and $ as begin and end of line, i.e. /m. */
static constexpr uint8_t Multiline = 0b00'0100;
static constexpr uint8_t Multiline = 0b000'0100;
/* Allow . to match newline characters, i.e. /s. */
static constexpr uint8_t DotAll = 0b10'0000;
static constexpr uint8_t DotAll = 0b010'0000;
/** Use Unicode semantics, i.e. /u. */
static constexpr uint8_t Unicode = 0b01'0000;
static constexpr uint8_t Unicode = 0b001'0000;
/** Only match starting from <regular expression>.lastIndex, i.e. /y. */
static constexpr uint8_t Sticky = 0b00'1000;
static constexpr uint8_t Sticky = 0b000'1000;
/** No regular expression flags. */
static constexpr uint8_t NoFlags = 0b00'0000;
static constexpr uint8_t NoFlags = 0b000'0000;
/** All regular expression flags. */
static constexpr uint8_t AllFlags = 0b11'1111;
static constexpr uint8_t AllFlags = 0b111'1111;
};
/**
@ -106,6 +111,7 @@ class RegExpFlags {
return RegExpFlags(~flags_ & RegExpFlag::AllFlags);
}
bool hasIndices() const { return flags_ & RegExpFlag::HasIndices; }
bool global() const { return flags_ & RegExpFlag::Global; }
bool ignoreCase() const { return flags_ & RegExpFlag::IgnoreCase; }
bool multiline() const { return flags_ & RegExpFlag::Multiline; }

View File

@ -212,9 +212,6 @@ struct UnusedZero {
static constexpr bool value = true;
static constexpr StorageType nullValue = 0;
static constexpr StorageType GetDefaultValue() {
return T::ErrorKind::Unspecified;
}
static constexpr void AssertValid(StorageType aValue) {}
static constexpr T Inspect(const StorageType& aValue) {

View File

@ -923,15 +923,22 @@ enum class AutoGCRooterKind : uint8_t {
Limit
};
// Our instantiations of Rooted<void*> and PersistentRooted<void*> require an
// instantiation of MapTypeToRootKind.
namespace detail {
// Dummy type to store root list entry pointers as. This code does not just use
// the actual type, because then eg JSObject* and JSFunction* would be assumed
// to never alias but they do (they are stored in the same list). Also, do not
// use `void*` so that `Rooted<void*>` is a compile error.
struct RootListEntry;
} // namespace detail
template <>
struct MapTypeToRootKind<void*> {
struct MapTypeToRootKind<detail::RootListEntry*> {
static const RootKind kind = RootKind::Traceable;
};
using RootedListHeads =
mozilla::EnumeratedArray<RootKind, RootKind::Limit, Rooted<void*>*>;
mozilla::EnumeratedArray<RootKind, RootKind::Limit,
Rooted<detail::RootListEntry*>*>;
using AutoRooterListHeads =
mozilla::EnumeratedArray<AutoGCRooterKind, AutoGCRooterKind::Limit,
@ -1071,7 +1078,7 @@ class MOZ_RAII Rooted : public js::RootedBase<T, Rooted<T>> {
inline void registerWithRootLists(RootedListHeads& roots) {
this->stack = &roots[JS::MapTypeToRootKind<T>::kind];
this->prev = *stack;
*stack = reinterpret_cast<Rooted<void*>*>(this);
*stack = reinterpret_cast<Rooted<detail::RootListEntry*>*>(this);
}
inline RootedListHeads& rootLists(RootingContext* cx) {
@ -1121,7 +1128,8 @@ class MOZ_RAII Rooted : public js::RootedBase<T, Rooted<T>> {
}
~Rooted() {
MOZ_ASSERT(*stack == reinterpret_cast<Rooted<void*>*>(this));
MOZ_ASSERT(*stack ==
reinterpret_cast<Rooted<detail::RootListEntry*>*>(this));
*stack = prev;
}
@ -1153,12 +1161,12 @@ class MOZ_RAII Rooted : public js::RootedBase<T, Rooted<T>> {
private:
/*
* These need to be templated on void* to avoid aliasing issues between, for
* example, Rooted<JSObject> and Rooted<JSFunction>, which use the same
* stack head pointer for different classes.
* These need to be templated on RootListEntry* to avoid aliasing issues
* between, for example, Rooted<JSObject*> and Rooted<JSFunction*>, which use
* the same stack head pointer for different classes.
*/
Rooted<void*>** stack;
Rooted<void*>* prev;
Rooted<detail::RootListEntry*>** stack;
Rooted<detail::RootListEntry*>* prev;
Ptr ptr;
@ -1287,11 +1295,13 @@ inline MutableHandle<T>::MutableHandle(PersistentRooted<T>* root) {
ptr = root->address();
}
JS_PUBLIC_API void AddPersistentRoot(RootingContext* cx, RootKind kind,
PersistentRooted<void*>* root);
JS_PUBLIC_API void AddPersistentRoot(
RootingContext* cx, RootKind kind,
PersistentRooted<detail::RootListEntry*>* root);
JS_PUBLIC_API void AddPersistentRoot(JSRuntime* rt, RootKind kind,
PersistentRooted<void*>* root);
JS_PUBLIC_API void AddPersistentRoot(
JSRuntime* rt, RootKind kind,
PersistentRooted<detail::RootListEntry*>* root);
/**
* A copyable, assignable global GC root type with arbitrary lifetime, an
@ -1340,15 +1350,17 @@ class PersistentRooted
void registerWithRootLists(RootingContext* cx) {
MOZ_ASSERT(!initialized());
JS::RootKind kind = JS::MapTypeToRootKind<T>::kind;
AddPersistentRoot(cx, kind,
reinterpret_cast<JS::PersistentRooted<void*>*>(this));
AddPersistentRoot(
cx, kind,
reinterpret_cast<JS::PersistentRooted<detail::RootListEntry*>*>(this));
}
void registerWithRootLists(JSRuntime* rt) {
MOZ_ASSERT(!initialized());
JS::RootKind kind = JS::MapTypeToRootKind<T>::kind;
AddPersistentRoot(rt, kind,
reinterpret_cast<JS::PersistentRooted<void*>*>(this));
AddPersistentRoot(
rt, kind,
reinterpret_cast<JS::PersistentRooted<detail::RootListEntry*>*>(this));
}
public:
@ -1476,7 +1488,7 @@ class MutableWrappedPtrOperations<UniquePtr<T, D>, Container>
UniquePtr<T, D>& uniquePtr() { return static_cast<Container*>(this)->get(); }
public:
MOZ_MUST_USE typename UniquePtr<T, D>::Pointer release() {
[[nodiscard]] typename UniquePtr<T, D>::Pointer release() {
return uniquePtr().release();
}
void reset(T* ptr = T()) { uniquePtr().reset(ptr); }

View File

@ -15,9 +15,8 @@ namespace js {
namespace Scalar {
// Scalar types that can appear in typed arrays and typed objects.
// Scalar types that can appear in typed arrays.
// The enum values must be kept in sync with:
// * the JS_SCALARTYPEREPR constants
// * the TYPEDARRAY_KIND constants
// * the SCTAG_TYPED_ARRAY constants
// * JS_FOR_EACH_TYPEDARRAY
@ -119,6 +118,42 @@ static inline bool isBigIntType(Type atype) {
MOZ_CRASH("invalid scalar type");
}
static inline const char* name(Type atype) {
switch (atype) {
case Int8:
return "Int8";
case Uint8:
return "Uint8";
case Int16:
return "Int16";
case Uint16:
return "Uint16";
case Int32:
return "Int32";
case Uint32:
return "Uint32";
case Float32:
return "Float32";
case Float64:
return "Float64";
case Uint8Clamped:
return "Uint8Clamped";
case BigInt64:
return "BigInt64";
case BigUint64:
return "BigUint64";
case MaxTypedArrayViewType:
return "MaxTypedArrayViewType";
case Int64:
return "Int64";
#ifdef ENABLE_WASM_SIMD
case Simd128:
return "Simd128";
#endif
}
MOZ_CRASH("invalid scalar type");
}
} // namespace Scalar
} // namespace js

View File

@ -8,7 +8,7 @@
#define js_SharedArrayBuffer_h
#include <stddef.h> // size_t
#include <stdint.h> // uint32_t
#include <stdint.h> // uint8_t
#include "jstypes.h" // JS_PUBLIC_API
@ -28,7 +28,7 @@ namespace JS {
* true.
*/
extern JS_PUBLIC_API JSObject* NewSharedArrayBuffer(JSContext* cx,
uint32_t nbytes);
size_t nbytes);
// TYPE TESTING
@ -44,7 +44,7 @@ extern JS_PUBLIC_API bool IsSharedArrayBufferObject(JSObject* obj);
extern JS_PUBLIC_API JSObject* UnwrapSharedArrayBuffer(JSObject* obj);
extern JS_PUBLIC_API uint32_t GetSharedArrayBufferByteLength(JSObject* obj);
extern JS_PUBLIC_API size_t GetSharedArrayBufferByteLength(JSObject* obj);
extern JS_PUBLIC_API uint8_t* GetSharedArrayBufferData(JSObject* obj,
bool* isSharedMemory,
@ -55,7 +55,7 @@ extern JS_PUBLIC_API uint8_t* GetSharedArrayBufferData(JSObject* obj,
// There is an isShared out argument for API consistency (eases use from DOM).
// It will always be set to true.
extern JS_PUBLIC_API void GetSharedArrayBufferLengthAndData(
JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data);
JSObject* obj, size_t* length, bool* isSharedMemory, uint8_t** data);
/**
* Returns true if there are any live SharedArrayBuffer objects, including those

View File

@ -5,7 +5,9 @@
#ifndef js_SliceBudget_h
#define js_SliceBudget_h
#include "mozilla/Assertions.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Variant.h"
#include <stdint.h>
@ -14,77 +16,69 @@
namespace js {
struct JS_PUBLIC_API TimeBudget {
int64_t budget;
const int64_t budget;
mozilla::TimeStamp deadline; // Calculated when SliceBudget is constructed.
explicit TimeBudget(int64_t milliseconds) { budget = milliseconds; }
explicit TimeBudget(int64_t milliseconds) : budget(milliseconds) {}
};
struct JS_PUBLIC_API WorkBudget {
int64_t budget;
const int64_t budget;
explicit WorkBudget(int64_t work) { budget = work; }
explicit WorkBudget(int64_t work) : budget(work) {}
};
struct UnlimitedBudget {};
/*
* This class records how much work has been done in a given collection slice,
* so that we can return before pausing for too long. Some slices are allowed
* to run for unlimited time, and others are bounded. To reduce the number of
* gettimeofday calls, we only check the time every 1000 operations.
* This class describes a limit to the amount of work to be performed in a GC
* slice, so that we can return to the mutator without pausing for too long. The
* budget may be based on a deadline time or an amount of work to be performed,
* or may be unlimited.
*
* To reduce the number of gettimeofday calls, we only check the time every 1000
* operations.
*/
class JS_PUBLIC_API SliceBudget {
static mozilla::TimeStamp unlimitedDeadline;
static const intptr_t unlimitedStartCounter = INTPTR_MAX;
static const intptr_t UnlimitedCounter = INTPTR_MAX;
mozilla::Variant<TimeBudget, WorkBudget, UnlimitedBudget> budget;
int64_t counter;
SliceBudget() : budget(UnlimitedBudget()), counter(UnlimitedCounter) {}
bool checkOverBudget();
SliceBudget();
public:
// Memory of the originally requested budget. If isUnlimited, neither of
// these are in use. If deadline==0, then workBudget is valid. Otherwise
// timeBudget is valid.
TimeBudget timeBudget;
WorkBudget workBudget;
static const intptr_t StepsPerTimeCheck = 1000;
mozilla::TimeStamp deadline;
intptr_t counter;
static const intptr_t CounterReset = 1000;
static const int64_t UnlimitedTimeBudget = -1;
static const int64_t UnlimitedWorkBudget = -1;
/* Use to create an unlimited budget. */
// Use to create an unlimited budget.
static SliceBudget unlimited() { return SliceBudget(); }
/* Instantiate as SliceBudget(TimeBudget(n)). */
// Instantiate as SliceBudget(TimeBudget(n)).
explicit SliceBudget(TimeBudget time);
/* Instantiate as SliceBudget(WorkBudget(n)). */
// Instantiate as SliceBudget(WorkBudget(n)).
explicit SliceBudget(WorkBudget work);
void makeUnlimited() {
MOZ_ASSERT(unlimitedDeadline);
deadline = unlimitedDeadline;
counter = unlimitedStartCounter;
explicit SliceBudget(mozilla::TimeDuration time)
: SliceBudget(TimeBudget(time.ToMilliseconds())) {}
void step(uint64_t steps = 1) {
MOZ_ASSERT(steps > 0);
counter -= steps;
}
void step(intptr_t amt = 1) { counter -= amt; }
bool isOverBudget() { return counter <= 0 && checkOverBudget(); }
bool isOverBudget() {
if (counter > 0) {
return false;
}
return checkOverBudget();
}
bool isWorkBudget() const { return budget.is<WorkBudget>(); }
bool isTimeBudget() const { return budget.is<TimeBudget>(); }
bool isUnlimited() const { return budget.is<UnlimitedBudget>(); }
bool isWorkBudget() const { return deadline.IsNull(); }
bool isTimeBudget() const { return !deadline.IsNull() && !isUnlimited(); }
bool isUnlimited() const { return deadline == unlimitedDeadline; }
int64_t timeBudget() const { return budget.as<TimeBudget>().budget; }
int64_t workBudget() const { return budget.as<WorkBudget>().budget; }
int describe(char* buffer, size_t maxlen) const;
static void Init();
};
} // namespace js

View File

@ -47,7 +47,7 @@
#define js_SourceText_h
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include "mozilla/Attributes.h" // MOZ_COLD, MOZ_IS_CLASS_INIT, MOZ_MUST_USE
#include "mozilla/Attributes.h" // MOZ_COLD, MOZ_IS_CLASS_INIT
#include "mozilla/Likely.h" // MOZ_UNLIKELY
#include "mozilla/Utf8.h" // mozilla::Utf8Unit
@ -137,9 +137,9 @@ class SourceText final {
* |units| may be null if |unitsLength == 0|; if so, this will silently be
* initialized using non-null, unowned units.
*/
MOZ_IS_CLASS_INIT MOZ_MUST_USE bool init(JSContext* cx, const Unit* units,
size_t unitsLength,
SourceOwnership ownership) {
[[nodiscard]] MOZ_IS_CLASS_INIT bool init(JSContext* cx, const Unit* units,
size_t unitsLength,
SourceOwnership ownership) {
MOZ_ASSERT_IF(units == nullptr, unitsLength == 0);
// Ideally we'd use |Unit| and not cast below, but the risk of a static
@ -181,9 +181,9 @@ class SourceText final {
template <typename Char,
typename = std::enable_if_t<std::is_same_v<Char, CharT> &&
!std::is_same_v<Char, Unit>>>
MOZ_IS_CLASS_INIT MOZ_MUST_USE bool init(JSContext* cx, const Char* chars,
size_t charsLength,
SourceOwnership ownership) {
[[nodiscard]] MOZ_IS_CLASS_INIT bool init(JSContext* cx, const Char* chars,
size_t charsLength,
SourceOwnership ownership) {
return init(cx, reinterpret_cast<const Unit*>(chars), charsLength,
ownership);
}
@ -191,9 +191,9 @@ class SourceText final {
/**
* Initialize this using source units transferred out of |data|.
*/
MOZ_MUST_USE bool init(JSContext* cx,
js::UniquePtr<Unit[], JS::FreePolicy> data,
size_t dataLength) {
[[nodiscard]] bool init(JSContext* cx,
js::UniquePtr<Unit[], JS::FreePolicy> data,
size_t dataLength) {
return init(cx, data.release(), dataLength, SourceOwnership::TakeOwnership);
}
@ -209,9 +209,9 @@ class SourceText final {
template <typename Char,
typename = std::enable_if_t<std::is_same_v<Char, CharT> &&
!std::is_same_v<Char, Unit>>>
MOZ_MUST_USE bool init(JSContext* cx,
js::UniquePtr<Char[], JS::FreePolicy> data,
size_t dataLength) {
[[nodiscard]] bool init(JSContext* cx,
js::UniquePtr<Char[], JS::FreePolicy> data,
size_t dataLength) {
return init(cx, data.release(), dataLength, SourceOwnership::TakeOwnership);
}

View File

@ -11,9 +11,9 @@
#define js_StableStringChars_h
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include "mozilla/Attributes.h" // MOZ_INIT_OUTSIDE_CTOR, MOZ_STACK_CLASS, MOZ_MUST_USE
#include "mozilla/Maybe.h" // mozilla::Maybe
#include "mozilla/Range.h" // mozilla::Range
#include "mozilla/Attributes.h" // MOZ_INIT_OUTSIDE_CTOR, MOZ_STACK_CLASS
#include "mozilla/Maybe.h" // mozilla::Maybe
#include "mozilla/Range.h" // mozilla::Range
#include <stddef.h> // size_t
#include <stdint.h> // uint8_t
@ -59,10 +59,10 @@ class MOZ_STACK_CLASS JS_FRIEND_API AutoStableStringChars final {
explicit AutoStableStringChars(JSContext* cx)
: s_(cx), state_(Uninitialized) {}
MOZ_MUST_USE bool init(JSContext* cx, JSString* s);
[[nodiscard]] bool init(JSContext* cx, JSString* s);
/* Like init(), but Latin1 chars are inflated to TwoByte. */
MOZ_MUST_USE bool initTwoByte(JSContext* cx, JSString* s);
[[nodiscard]] bool initTwoByte(JSContext* cx, JSString* s);
bool isLatin1() const { return state_ == Latin1; }
bool isTwoByte() const { return state_ == TwoByte; }

View File

@ -500,6 +500,8 @@ class JS_PUBLIC_API WritableStreamUnderlyingSink {
virtual void finalize() = 0;
};
// ReadableStream.prototype.pipeTo SUPPORT
/**
* The signature of a function that, when passed an |AbortSignal| instance, will
* return the value of its "aborted" flag.
@ -509,17 +511,18 @@ class JS_PUBLIC_API WritableStreamUnderlyingSink {
using AbortSignalIsAborted = bool (*)(JSObject* signal);
/**
* Dictate all details of handling of |AbortSignal| objects for SpiderMonkey to
* use. This should only be performed once, for a single context associated
* with a |JSRuntime|.
* Dictate embedder-specific details necessary to implement certain aspects of
* the |ReadableStream.prototype.pipeTo| function. This should be performed
* exactly once, for a single context associated with a |JSRuntime|.
*
* The |ReadableStream.prototype.pipeTo| function accepts a |signal| argument
* that may be used to abort the piping operation. This argument must be either
* |undefined| (in other words, the piping operation can't be aborted) or an
* |AbortSignal| instance. |AbortSignal| is defined by WebIDL and the DOM in
* the web embedding. Therefore, embedders must use this function to specify
* how such objects can be recognized and how to perform various essential
* actions upon them.
* |AbortSignal| instance (that may be aborted using the signal's associated
* |AbortController|). |AbortSignal| is defined by WebIDL and the DOM in the
* web embedding. Therefore, embedders must use this function to specify how
* such objects can be recognized and how to perform various essential actions
* upon them.
*
* The provided |isAborted| function will be called with an unwrapped
* |AbortSignal| instance, while that instance's realm has been entered.
@ -528,8 +531,9 @@ using AbortSignalIsAborted = bool (*)(JSObject* signal);
* |AbortSignal|?" question must be asked, that question will simply be answered
* "no".
*/
extern JS_PUBLIC_API void InitAbortSignalHandling(
const JSClass* clasp, AbortSignalIsAborted isAborted, JSContext* cx);
extern JS_PUBLIC_API void InitPipeToHandling(const JSClass* abortSignalClass,
AbortSignalIsAborted isAborted,
JSContext* cx);
} // namespace JS

View File

@ -10,7 +10,7 @@
#include "js/shadow/String.h" // JS::shadow::String
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include "mozilla/Attributes.h" // MOZ_ALWAYS_INLINE, MOZ_MUST_USE
#include "mozilla/Attributes.h" // MOZ_ALWAYS_INLINE
#include "mozilla/Likely.h" // MOZ_LIKELY
#include <algorithm> // std::copy_n
@ -191,9 +191,9 @@ MOZ_ALWAYS_INLINE void LossyCopyLinearStringChars(char* dest, JSLinearString* s,
* This function is fallible. If you already have a linear string, use the
* infallible |JS::CopyLinearStringChars| above instead.
*/
inline MOZ_MUST_USE bool CopyStringChars(JSContext* cx, char16_t* dest,
JSString* s, size_t len,
size_t start = 0) {
[[nodiscard]] inline bool CopyStringChars(JSContext* cx, char16_t* dest,
JSString* s, size_t len,
size_t start = 0) {
JSLinearString* linear = StringToLinearString(cx, s);
if (!linear) {
return false;
@ -210,9 +210,9 @@ inline MOZ_MUST_USE bool CopyStringChars(JSContext* cx, char16_t* dest,
* This function is fallible. If you already have a linear string, use the
* infallible |JS::LossyCopyLinearStringChars| above instead.
*/
inline MOZ_MUST_USE bool LossyCopyStringChars(JSContext* cx, char* dest,
JSString* s, size_t len,
size_t start = 0) {
[[nodiscard]] inline bool LossyCopyStringChars(JSContext* cx, char* dest,
JSString* s, size_t len,
size_t start = 0) {
JSLinearString* linear = StringToLinearString(cx, s);
if (!linear) {
return false;

View File

@ -379,9 +379,9 @@ class SharedArrayRawBufferRefs {
SharedArrayRawBufferRefs& operator=(SharedArrayRawBufferRefs&& other);
~SharedArrayRawBufferRefs();
MOZ_MUST_USE bool acquire(JSContext* cx, SharedArrayRawBuffer* rawbuf);
MOZ_MUST_USE bool acquireAll(JSContext* cx,
const SharedArrayRawBufferRefs& that);
[[nodiscard]] bool acquire(JSContext* cx, SharedArrayRawBuffer* rawbuf);
[[nodiscard]] bool acquireAll(JSContext* cx,
const SharedArrayRawBufferRefs& that);
void takeOwnership(SharedArrayRawBufferRefs&&);
void releaseAll();
@ -456,7 +456,7 @@ class MOZ_NON_MEMMOVABLE JS_PUBLIC_API JSStructuredCloneData {
ownTransferables_ = policy;
}
MOZ_MUST_USE bool Init(size_t initialCapacity = 0) {
[[nodiscard]] bool Init(size_t initialCapacity = 0) {
return bufList_.Init(0, initialCapacity);
}
@ -486,24 +486,25 @@ class MOZ_NON_MEMMOVABLE JS_PUBLIC_API JSStructuredCloneData {
const Iterator Start() const { return bufList_.Iter(); }
MOZ_MUST_USE bool Advance(Iterator& iter, size_t distance) const {
[[nodiscard]] bool Advance(Iterator& iter, size_t distance) const {
return iter.AdvanceAcrossSegments(bufList_, distance);
}
MOZ_MUST_USE bool ReadBytes(Iterator& iter, char* buffer, size_t size) const {
[[nodiscard]] bool ReadBytes(Iterator& iter, char* buffer,
size_t size) const {
return bufList_.ReadBytes(iter, buffer, size);
}
// Append new data to the end of the buffer.
MOZ_MUST_USE bool AppendBytes(const char* data, size_t size) {
[[nodiscard]] bool AppendBytes(const char* data, size_t size) {
MOZ_ASSERT(scope() != JS::StructuredCloneScope::Unassigned);
return bufList_.WriteBytes(data, size);
}
// Update data stored within the existing buffer. There must be at least
// 'size' bytes between the position of 'iter' and the end of the buffer.
MOZ_MUST_USE bool UpdateBytes(Iterator& iter, const char* data,
size_t size) const {
[[nodiscard]] bool UpdateBytes(Iterator& iter, const char* data,
size_t size) const {
MOZ_ASSERT(scope() != JS::StructuredCloneScope::Unassigned);
while (size > 0) {
size_t remaining = iter.RemainingInSegment();
@ -553,7 +554,7 @@ class MOZ_NON_MEMMOVABLE JS_PUBLIC_API JSStructuredCloneData {
}
// Append the entire contents of other's bufList_ to our own.
MOZ_MUST_USE bool Append(const JSStructuredCloneData& other) {
[[nodiscard]] bool Append(const JSStructuredCloneData& other) {
MOZ_ASSERT(scope() == other.scope());
return other.ForEachDataChunk(
[&](const char* data, size_t size) { return AppendBytes(data, size); });

View File

@ -27,14 +27,9 @@ JS_FRIEND_API size_t GCTraceKindSize(JS::TraceKind kind);
// Kinds of JSTracer.
enum class TracerKind {
// Marking path: a tracer used only for marking liveness of cells, not
// for moving them. The kind will transition to WeakMarking after
// everything reachable by regular edges has been marked.
// for moving them.
Marking,
// A tracer that traverses the graph for the purposes of moving objects
// from the nursery to the tenured heap.
Tenuring,
// Generic tracers: Internal tracers that have a different virtual method
// called for each edge kind.
//
@ -42,6 +37,7 @@ enum class TracerKind {
Generic,
// Specific kinds of generic tracer.
Tenuring,
Moving,
GrayBuffering,
ClearEdges,

View File

@ -41,24 +41,63 @@ struct TranscodeSource final {
using TranscodeSources = mozilla::Vector<TranscodeSource>;
enum TranscodeResult : uint8_t {
enum class TranscodeResult : uint8_t {
// Successful encoding / decoding.
TranscodeResult_Ok = 0,
Ok = 0,
// A warning message, is set to the message out-param.
TranscodeResult_Failure = 0x10,
TranscodeResult_Failure_BadBuildId = TranscodeResult_Failure | 0x1,
TranscodeResult_Failure_RunOnceNotSupported = TranscodeResult_Failure | 0x2,
TranscodeResult_Failure_AsmJSNotSupported = TranscodeResult_Failure | 0x3,
TranscodeResult_Failure_BadDecode = TranscodeResult_Failure | 0x4,
TranscodeResult_Failure_WrongCompileOption = TranscodeResult_Failure | 0x5,
TranscodeResult_Failure_NotInterpretedFun = TranscodeResult_Failure | 0x6,
Failure = 0x10,
Failure_BadBuildId = Failure | 0x1,
Failure_RunOnceNotSupported = Failure | 0x2,
Failure_AsmJSNotSupported = Failure | 0x3,
Failure_BadDecode = Failure | 0x4,
Failure_WrongCompileOption = Failure | 0x5,
Failure_NotInterpretedFun = Failure | 0x6,
// There is a pending exception on the context.
TranscodeResult_Throw = 0x20
Throw = 0x20
};
inline bool IsTranscodeFailureResult(const TranscodeResult result) {
uint8_t raw_result = static_cast<uint8_t>(result);
uint8_t raw_failure = static_cast<uint8_t>(TranscodeResult::Failure);
TranscodeResult masked =
static_cast<TranscodeResult>(raw_result & raw_failure);
return masked == TranscodeResult::Failure;
}
static constexpr size_t BytecodeOffsetAlignment = 4;
static_assert(BytecodeOffsetAlignment <= alignof(std::max_align_t),
"Alignment condition requires a custom allocator.");
// Align the bytecode offset for transcoding for the requirement.
inline size_t AlignTranscodingBytecodeOffset(size_t offset) {
size_t extra = offset % BytecodeOffsetAlignment;
if (extra == 0) {
return offset;
}
size_t padding = BytecodeOffsetAlignment - extra;
return offset + padding;
}
inline bool IsTranscodingBytecodeOffsetAligned(size_t offset) {
return offset % BytecodeOffsetAlignment == 0;
}
inline bool IsTranscodingBytecodeAligned(void* offset) {
return IsTranscodingBytecodeOffsetAligned(size_t(offset));
}
// Encode JSScript into the buffer.
//
// If the `buffer` isn't empty, the start of the `buffer` should meet
// IsTranscodingBytecodeAligned, and the length should meet
// IsTranscodingBytecodeOffsetAligned.
//
// NOTE: As long as IsTranscodingBytecodeOffsetAligned is met, that means
// there's JS::BytecodeOffsetAlignment+extra bytes in the buffer,
// IsTranscodingBytecodeAligned should be guaranteed to meet by
// malloc, used by MallocAllocPolicy in mozilla::Vector.
extern JS_PUBLIC_API TranscodeResult EncodeScript(JSContext* cx,
TranscodeBuffer& buffer,
Handle<JSScript*> script);
@ -67,11 +106,20 @@ extern JS_PUBLIC_API TranscodeResult EncodeInterpretedFunction(
JSContext* cx, TranscodeBuffer& buffer, Handle<JSObject*> funobj);
// Decode JSScript from the buffer.
//
// The start of `buffer` and `cursorIndex` should meet
// IsTranscodingBytecodeAligned and IsTranscodingBytecodeOffsetAligned.
// (This should be handled while encoding).
extern JS_PUBLIC_API TranscodeResult
DecodeScript(JSContext* cx, const ReadOnlyCompileOptions& options,
TranscodeBuffer& buffer, MutableHandle<JSScript*> scriptp,
size_t cursorIndex = 0);
// Decode JSScript from the range.
//
// The start of `range` should meet IsTranscodingBytecodeAligned and
// IsTranscodingBytecodeOffsetAligned.
// (This should be handled while encoding).
extern JS_PUBLIC_API TranscodeResult
DecodeScript(JSContext* cx, const ReadOnlyCompileOptions& options,
const TranscodeRange& range, MutableHandle<JSScript*> scriptp);
@ -87,6 +135,10 @@ extern JS_PUBLIC_API TranscodeResult DecodeInterpretedFunction(
// buffer and instantiate JSScript from it.
//
// options.useOffThreadParseGlobal should match JS::SetUseOffThreadParseGlobal.
//
// The start of `buffer` and `cursorIndex` should meet
// IsTranscodingBytecodeAligned and IsTranscodingBytecodeOffsetAligned.
// (This should be handled while encoding).
extern JS_PUBLIC_API TranscodeResult DecodeScriptMaybeStencil(
JSContext* cx, const ReadOnlyCompileOptions& options,
TranscodeBuffer& buffer, MutableHandle<JSScript*> scriptp,
@ -104,6 +156,10 @@ extern JS_PUBLIC_API TranscodeResult DecodeScriptMaybeStencil(
// See also JS::FinishIncrementalEncoding.
//
// options.useOffThreadParseGlobal should match JS::SetUseOffThreadParseGlobal.
//
// The start of `buffer` and `cursorIndex` should meet
// IsTranscodingBytecodeAligned and IsTranscodingBytecodeOffsetAligned.
// (This should be handled while encoding).
extern JS_PUBLIC_API TranscodeResult DecodeScriptAndStartIncrementalEncoding(
JSContext* cx, const ReadOnlyCompileOptions& options,
TranscodeBuffer& buffer, MutableHandle<JSScript*> scriptp,
@ -125,6 +181,15 @@ extern JS_PUBLIC_API TranscodeResult DecodeScriptAndStartIncrementalEncoding(
//
// If js::UseOffThreadParseGlobal is false, |buffer| contains encoded
// CompilationStencil.
//
// If the `buffer` isn't empty, the start of the `buffer` should meet
// IsTranscodingBytecodeAligned, and the length should meet
// IsTranscodingBytecodeOffsetAligned.
//
// NOTE: As long as IsTranscodingBytecodeOffsetAligned is met, that means
// there's JS::BytecodeOffsetAlignment+extra bytes in the buffer,
// IsTranscodingBytecodeAligned should be guaranteed to meet by
// malloc, used by MallocAllocPolicy in mozilla::Vector.
extern JS_PUBLIC_API bool FinishIncrementalEncoding(JSContext* cx,
Handle<JSScript*> script,
TranscodeBuffer& buffer);

View File

@ -292,7 +292,7 @@ class BaseStackFrame {
// simplifies the principals check into the boolean isSystem() state. This
// is fine because we only expose JS::ubi::Stack to devtools and chrome
// code, and not to the web platform.
virtual MOZ_MUST_USE bool constructSavedFrameStack(
[[nodiscard]] virtual bool constructSavedFrameStack(
JSContext* cx, MutableHandleObject outSavedFrameStack) const = 0;
// Trace the concrete implementation of JS::ubi::StackFrame.
@ -428,7 +428,7 @@ class StackFrame {
StackFrame parent() const { return base()->parent(); }
bool isSystem() const { return base()->isSystem(); }
bool isSelfHosted(JSContext* cx) const { return base()->isSelfHosted(cx); }
MOZ_MUST_USE bool constructSavedFrameStack(
[[nodiscard]] bool constructSavedFrameStack(
JSContext* cx, MutableHandleObject outSavedFrameStack) const {
return base()->constructSavedFrameStack(cx, outSavedFrameStack);
}
@ -461,7 +461,7 @@ class ConcreteStackFrame<void> : public BaseStackFrame {
uint64_t identifier() const override { return 0; }
void trace(JSTracer* trc) override {}
MOZ_MUST_USE bool constructSavedFrameStack(
[[nodiscard]] bool constructSavedFrameStack(
JSContext* cx, MutableHandleObject out) const override {
out.set(nullptr);
return true;
@ -483,7 +483,7 @@ class ConcreteStackFrame<void> : public BaseStackFrame {
}
};
MOZ_MUST_USE JS_PUBLIC_API bool ConstructSavedFrameStackSlow(
[[nodiscard]] JS_PUBLIC_API bool ConstructSavedFrameStackSlow(
JSContext* cx, JS::ubi::StackFrame& frame,
MutableHandleObject outSavedFrameStack);
@ -996,15 +996,15 @@ class MOZ_STACK_CLASS JS_PUBLIC_API RootList {
bool wantNames = false);
// Find all GC roots.
MOZ_MUST_USE bool init();
[[nodiscard]] bool init();
// Find only GC roots in the provided set of |JS::Compartment|s. Note: it's
// important to take a CompartmentSet and not a RealmSet: objects in
// same-compartment realms can reference each other directly, without going
// through CCWs, so if we used a RealmSet here we would miss edges.
MOZ_MUST_USE bool init(CompartmentSet& debuggees);
[[nodiscard]] bool init(CompartmentSet& debuggees);
// Find only GC roots in the given Debugger object's set of debuggee
// compartments.
MOZ_MUST_USE bool init(HandleObject debuggees);
[[nodiscard]] bool init(HandleObject debuggees);
// Returns true if the RootList has been initialized successfully, false
// otherwise.
@ -1013,7 +1013,7 @@ class MOZ_STACK_CLASS JS_PUBLIC_API RootList {
// Explicitly add the given Node as a root in this RootList. If wantNames is
// true, you must pass an edgeName. The RootList does not take ownership of
// edgeName.
MOZ_MUST_USE bool addRoot(Node node, const char16_t* edgeName = nullptr);
[[nodiscard]] bool addRoot(Node node, const char16_t* edgeName = nullptr);
};
/*** Concrete classes for ubi::Node referent types ****************************/

View File

@ -107,14 +107,14 @@ struct CountType {
// Implement the 'count' method for counts returned by this CountType
// instance's 'newCount' method.
virtual MOZ_MUST_USE bool count(CountBase& count,
mozilla::MallocSizeOf mallocSizeOf,
const Node& node) = 0;
[[nodiscard]] virtual bool count(CountBase& count,
mozilla::MallocSizeOf mallocSizeOf,
const Node& node) = 0;
// Implement the 'report' method for counts returned by this CountType
// instance's 'newCount' method.
virtual MOZ_MUST_USE bool report(JSContext* cx, CountBase& count,
MutableHandleValue report) = 0;
[[nodiscard]] virtual bool report(JSContext* cx, CountBase& count,
MutableHandleValue report) = 0;
};
using CountTypePtr = js::UniquePtr<CountType>;
@ -135,8 +135,8 @@ class CountBase {
: type(type), total_(0), smallestNodeIdCounted_(SIZE_MAX) {}
// Categorize and count |node| as appropriate for this count's type.
MOZ_MUST_USE bool count(mozilla::MallocSizeOf mallocSizeOf,
const Node& node) {
[[nodiscard]] bool count(mozilla::MallocSizeOf mallocSizeOf,
const Node& node) {
total_++;
auto id = node.identifier();
@ -160,7 +160,7 @@ class CountBase {
// Construct a JavaScript object reporting the counts recorded in this
// count, and store it in |report|. Return true on success, or false on
// failure.
MOZ_MUST_USE bool report(JSContext* cx, MutableHandleValue report) {
[[nodiscard]] bool report(JSContext* cx, MutableHandleValue report) {
return type.report(cx, *this, report);
}
@ -203,14 +203,14 @@ class CensusHandler {
mozilla::MallocSizeOf mallocSizeOf)
: census(census), rootCount(rootCount), mallocSizeOf(mallocSizeOf) {}
MOZ_MUST_USE bool report(JSContext* cx, MutableHandleValue report) {
[[nodiscard]] bool report(JSContext* cx, MutableHandleValue report) {
return rootCount->report(cx, report);
}
// This class needs to retain no per-node data.
class NodeData {};
MOZ_MUST_USE JS_PUBLIC_API bool operator()(
[[nodiscard]] JS_PUBLIC_API bool operator()(
BreadthFirst<CensusHandler>& traversal, Node origin, const Edge& edge,
NodeData* referentData, bool first);
};
@ -219,10 +219,10 @@ using CensusTraversal = BreadthFirst<CensusHandler>;
// Examine the census options supplied by the API consumer, and (among other
// things) use that to build a CountType tree.
MOZ_MUST_USE JS_PUBLIC_API bool ParseCensusOptions(JSContext* cx,
Census& census,
HandleObject options,
CountTypePtr& outResult);
[[nodiscard]] JS_PUBLIC_API bool ParseCensusOptions(JSContext* cx,
Census& census,
HandleObject options,
CountTypePtr& outResult);
// Parse the breakdown language (as described in
// js/src/doc/Debugger/Debugger.Memory.md) into a CountTypePtr. A null pointer

View File

@ -320,10 +320,10 @@ class JS_PUBLIC_API DominatorTree {
// Do the post order traversal of the heap graph and populate our
// predecessor sets.
static MOZ_MUST_USE bool doTraversal(JSContext* cx, AutoCheckCannotGC& noGC,
const Node& root,
JS::ubi::Vector<Node>& postOrder,
PredecessorSets& predecessorSets) {
[[nodiscard]] static bool doTraversal(JSContext* cx, AutoCheckCannotGC& noGC,
const Node& root,
JS::ubi::Vector<Node>& postOrder,
PredecessorSets& predecessorSets) {
uint32_t nodeCount = 0;
auto onNode = [&](const Node& node) {
nodeCount++;
@ -352,7 +352,7 @@ class JS_PUBLIC_API DominatorTree {
// Populates the given `map` with an entry for each node to its index in
// `postOrder`.
static MOZ_MUST_USE bool mapNodesToTheirIndices(
[[nodiscard]] static bool mapNodesToTheirIndices(
JS::ubi::Vector<Node>& postOrder, NodeToIndexMap& map) {
MOZ_ASSERT(map.empty());
MOZ_ASSERT(postOrder.length() < UINT32_MAX);
@ -368,7 +368,7 @@ class JS_PUBLIC_API DominatorTree {
// Convert the Node -> NodeSet predecessorSets to a index -> Vector<index>
// form.
static MOZ_MUST_USE bool convertPredecessorSetsToVectors(
[[nodiscard]] static bool convertPredecessorSetsToVectors(
const Node& root, JS::ubi::Vector<Node>& postOrder,
PredecessorSets& predecessorSets, NodeToIndexMap& nodeToPostOrderIndex,
JS::ubi::Vector<JS::ubi::Vector<uint32_t>>& predecessorVectors) {
@ -408,8 +408,8 @@ class JS_PUBLIC_API DominatorTree {
// Initialize `doms` such that the immediate dominator of the `root` is the
// `root` itself and all others are `UNDEFINED`.
static MOZ_MUST_USE bool initializeDominators(JS::ubi::Vector<uint32_t>& doms,
uint32_t length) {
[[nodiscard]] static bool initializeDominators(
JS::ubi::Vector<uint32_t>& doms, uint32_t length) {
MOZ_ASSERT(doms.length() == 0);
if (!doms.growByUninitialized(length)) {
return false;
@ -428,7 +428,7 @@ class JS_PUBLIC_API DominatorTree {
postOrder.length() == retainedSizes->length());
}
MOZ_MUST_USE bool computeRetainedSizes(mozilla::MallocSizeOf mallocSizeOf) {
[[nodiscard]] bool computeRetainedSizes(mozilla::MallocSizeOf mallocSizeOf) {
MOZ_ASSERT(retainedSizes.isNothing());
auto length = postOrder.length();
@ -662,9 +662,9 @@ class JS_PUBLIC_API DominatorTree {
* `outSize`, or 0 if `node` is not a member of the dominator tree. Returns
* false on OOM failure, leaving `outSize` unchanged.
*/
MOZ_MUST_USE bool getRetainedSize(const Node& node,
mozilla::MallocSizeOf mallocSizeOf,
Node::Size& outSize) {
[[nodiscard]] bool getRetainedSize(const Node& node,
mozilla::MallocSizeOf mallocSizeOf,
Node::Size& outSize) {
assertSanity();
auto ptr = nodeToPostOrderIndex.lookup(node);
if (!ptr) {

View File

@ -85,8 +85,8 @@ struct PostOrder {
#endif
private:
MOZ_MUST_USE bool fillEdgesFromRange(EdgeVector& edges,
js::UniquePtr<EdgeRange>& range) {
[[nodiscard]] bool fillEdgesFromRange(EdgeVector& edges,
js::UniquePtr<EdgeRange>& range) {
MOZ_ASSERT(range);
for (; !range->empty(); range->popFront()) {
if (!edges.append(std::move(range->front()))) {
@ -96,7 +96,7 @@ struct PostOrder {
return true;
}
MOZ_MUST_USE bool pushForTraversing(const Node& node) {
[[nodiscard]] bool pushForTraversing(const Node& node) {
EdgeVector edges;
auto range = node.edges(cx, /* wantNames */ false);
return range && fillEdgesFromRange(edges, range) &&
@ -122,7 +122,7 @@ struct PostOrder {
// Add `node` as a starting point for the traversal. You may add
// as many starting points as you like. Returns false on OOM.
MOZ_MUST_USE bool addStart(const Node& node) {
[[nodiscard]] bool addStart(const Node& node) {
if (!seen.put(node)) {
return false;
}
@ -139,7 +139,7 @@ struct PostOrder {
// Return false on OOM or error return from `onNode::operator()` or
// `onEdge::operator()`.
template <typename NodeVisitor, typename EdgeVisitor>
MOZ_MUST_USE bool traverse(NodeVisitor onNode, EdgeVisitor onEdge) {
[[nodiscard]] bool traverse(NodeVisitor onNode, EdgeVisitor onEdge) {
#ifdef DEBUG
MOZ_ASSERT(!traversed, "Can only traverse() once!");
traversed = true;

View File

@ -31,7 +31,7 @@ struct JS_PUBLIC_API BackEdge {
BackEdge() : predecessor_(), name_(nullptr) {}
MOZ_MUST_USE bool init(const Node& predecessor, Edge& edge) {
[[nodiscard]] bool init(const Node& predecessor, Edge& edge) {
MOZ_ASSERT(!predecessor_);
MOZ_ASSERT(!name_);
@ -279,7 +279,7 @@ struct JS_PUBLIC_API ShortestPaths {
* the given target, in which case `func` will not be invoked.
*/
template <class Func>
MOZ_MUST_USE bool forEachPath(const Node& target, Func func) {
[[nodiscard]] bool forEachPath(const Node& target, Func func) {
MOZ_ASSERT(targets_.has(target));
auto ptr = paths_.lookup(target);

View File

@ -544,7 +544,8 @@ namespace js {
* instances of type |T|. Return false if the calculation overflowed.
*/
template <typename T>
MOZ_MUST_USE inline bool CalculateAllocSize(size_t numElems, size_t* bytesOut) {
[[nodiscard]] inline bool CalculateAllocSize(size_t numElems,
size_t* bytesOut) {
*bytesOut = numElems * sizeof(T);
return (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) == 0;
}
@ -555,8 +556,8 @@ MOZ_MUST_USE inline bool CalculateAllocSize(size_t numElems, size_t* bytesOut) {
* false if the calculation overflowed.
*/
template <typename T, typename Extra>
MOZ_MUST_USE inline bool CalculateAllocSizeWithExtra(size_t numExtra,
size_t* bytesOut) {
[[nodiscard]] inline bool CalculateAllocSizeWithExtra(size_t numExtra,
size_t* bytesOut) {
*bytesOut = sizeof(T) + numExtra * sizeof(Extra);
return (numExtra & mozilla::tl::MulOverflowMask<sizeof(Extra)>::value) == 0 &&
*bytesOut >= sizeof(T);

View File

@ -9,8 +9,6 @@
#include "mozilla/Attributes.h"
#include "mozilla/Casting.h"
#include "mozilla/Compiler.h"
#include "mozilla/EndianUtils.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/Likely.h"
#include "mozilla/Maybe.h"
@ -20,9 +18,9 @@
#include "js-config.h"
#include "jstypes.h"
#include "js/GCAPI.h"
#include "js/HeapAPI.h"
#include "js/RootingAPI.h"
#include "js/Utility.h"
#include "js/TypeDecls.h"
namespace JS {
class JS_PUBLIC_API Value;
@ -245,9 +243,6 @@ enum JSWhyMagic {
/** standard constructors are not created for off-thread parsing. */
JS_OFF_THREAD_CONSTRUCTOR,
/** used in jit::TrySkipAwait */
JS_CANNOT_SKIP_AWAIT,
/** for local use */
JS_GENERIC_MAGIC,
@ -519,13 +514,14 @@ class alignas(8) Value {
MOZ_ASSERT(magicUint32() == payload);
}
void setNumber(uint32_t ui) {
if (ui > JSVAL_INT_MAX) {
setDouble((double)ui);
void setNumber(float f) {
int32_t i;
if (mozilla::NumberIsInt32(f, &i)) {
setInt32(i);
return;
}
setInt32((int32_t)ui);
setDouble(double(f));
}
void setNumber(double d) {
@ -538,6 +534,34 @@ class alignas(8) Value {
setDouble(d);
}
template <typename T>
void setNumber(const T t) {
static_assert(std::is_integral<T>::value, "must be integral type");
MOZ_ASSERT(isNumberRepresentable(t), "value creation would be lossy");
if constexpr (std::numeric_limits<T>::is_signed) {
if constexpr (sizeof(t) <= sizeof(int32_t)) {
setInt32(int32_t(t));
} else {
if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX) {
setInt32(int32_t(t));
} else {
setDouble(double(t));
}
}
} else {
if constexpr (sizeof(t) <= sizeof(uint16_t)) {
setInt32(int32_t(t));
} else {
if (t <= JSVAL_INT_MAX) {
setInt32(int32_t(t));
} else {
setDouble(double(t));
}
}
}
}
void setObjectOrNull(JSObject* arg) {
if (arg) {
setObject(*arg);
@ -905,7 +929,7 @@ static MOZ_ALWAYS_INLINE void ExposeValueToActiveJS(const Value& v) {
MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&tmp));
#endif
if (v.isGCThing()) {
js::gc::ExposeGCThingToActiveJS(GCCellPtr(v));
js::gc::ExposeGCThingToActiveJS(v.toGCCellPtr());
}
}
@ -999,71 +1023,16 @@ static inline Value MagicValueUint32(uint32_t payload) {
return v;
}
static inline Value NumberValue(float f) {
Value v;
v.setNumber(f);
return v;
}
static inline Value NumberValue(double dbl) {
Value v;
v.setNumber(dbl);
return v;
}
static inline Value NumberValue(int8_t i) { return Int32Value(i); }
static inline Value NumberValue(uint8_t i) { return Int32Value(i); }
static inline Value NumberValue(int16_t i) { return Int32Value(i); }
static inline Value NumberValue(uint16_t i) { return Int32Value(i); }
static inline Value NumberValue(int32_t i) { return Int32Value(i); }
static constexpr Value NumberValue(uint32_t i) {
return i <= JSVAL_INT_MAX ? Int32Value(int32_t(i))
: Value::fromDouble(double(i));
}
namespace detail {
template <bool Signed>
class MakeNumberValue {
public:
template <typename T>
static inline Value create(const T t) {
Value v;
if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX) {
v.setInt32(int32_t(t));
} else {
v.setDouble(double(t));
}
return v;
}
};
template <>
class MakeNumberValue<false> {
public:
template <typename T>
static inline Value create(const T t) {
Value v;
if (t <= JSVAL_INT_MAX) {
v.setInt32(int32_t(t));
} else {
v.setDouble(double(t));
}
return v;
}
};
} // namespace detail
template <typename T>
static inline Value NumberValue(const T t) {
MOZ_ASSERT(Value::isNumberRepresentable(t), "value creation would be lossy");
return detail::MakeNumberValue<std::numeric_limits<T>::is_signed>::create(t);
Value v;
v.setNumber(t);
return v;
}
static inline Value ObjectOrNullValue(JSObject* obj) {
@ -1192,6 +1161,7 @@ class WrappedPtrOperations<JS::Value, Wrapper> {
JS::BigInt* toBigInt() const { return value().toBigInt(); }
JSObject& toObject() const { return value().toObject(); }
JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
JS::GCCellPtr toGCCellPtr() const { return value().toGCCellPtr(); }
gc::Cell* toGCThing() const { return value().toGCThing(); }
JS::TraceKind traceKind() const { return value().traceKind(); }
void* toPrivate() const { return value().toPrivate(); }
@ -1253,29 +1223,7 @@ class MutableWrappedPtrOperations<JS::Value, Wrapper>
*/
template <typename Wrapper>
class HeapBase<JS::Value, Wrapper>
: public MutableWrappedPtrOperations<JS::Value, Wrapper> {
public:
void setMagic(JSWhyMagic why) { this->set(JS::MagicValueUint32(why)); }
void setNumber(uint32_t ui) {
if (ui > JSVAL_INT_MAX) {
this->setDouble((double)ui);
return;
}
this->setInt32((int32_t)ui);
}
void setNumber(double d) {
int32_t i;
if (mozilla::NumberIsInt32(d, &i)) {
this->setInt32(i);
return;
}
this->setDouble(d);
}
};
: public MutableWrappedPtrOperations<JS::Value, Wrapper> {};
MOZ_HAVE_NORETURN MOZ_COLD MOZ_NEVER_INLINE void ReportBadValueTypeAndCrash(
const JS::Value& val);

View File

@ -157,10 +157,6 @@ class JS_FRIEND_API Wrapper : public ForwardingProxyHandler {
static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler,
const WrapperOptions& options = WrapperOptions());
static JSObject* NewSingleton(
JSContext* cx, JSObject* obj, const Wrapper* handler,
const WrapperOptions& options = WrapperOptions());
static JSObject* Renew(JSObject* existing, JSObject* obj,
const Wrapper* handler);

View File

@ -46,17 +46,6 @@ extern JS_FRIEND_API bool AddMozDateTimeFormatConstructor(
extern JS_FRIEND_API bool AddMozDisplayNamesConstructor(JSContext* cx,
Handle<JSObject*> intl);
/**
* Create and add the Intl.DisplayNames constructor function to the provided
* object, implementing standardized behavior (that isn't yet shippable because
* we're not *quite* comfortable with the spec's progress yet).
*
* If JS was built without JS_HAS_INTL_API, this function will throw an
* exception.
*/
extern JS_FRIEND_API bool AddDisplayNamesConstructor(JSContext* cx,
Handle<JSObject*> intl);
} // namespace JS
#endif // js_experimental_Intl_h

View File

@ -0,0 +1,79 @@
/* 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/. */
#ifndef js_experimental_JSStencil_h
#define js_experimental_JSStencil_h
/* The `JS::Stencil` type holds the output of the JS Parser before it is
* allocated on the GC heap as a `JSScript`. This form may be serialized as
* part of building a bytecode cache. This `Stencil` is not associated with any
* particular Realm and may be generated off-main-thread, making it useful for
* building script loaders.
*/
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h" // mozilla::UniquePtr
#include "mozilla/Utf8.h" // mozilla::Utf8Unit
#include <stddef.h> // size_t
#include "jstypes.h" // JS_FRIEND_API
#include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions
#include "js/SourceText.h" // JS::SourceText
#include "js/Transcoding.h"
struct JS_PUBLIC_API JSContext;
// Underlying opaque type.
namespace js::frontend {
struct CompilationStencil;
};
namespace JS {
using Stencil = js::frontend::CompilationStencil;
// These non-member functions let us manipulate the ref counts of the opaque
// Stencil type. The RefPtrTraits below calls these for use when using the
// RefPtr type.
JS_PUBLIC_API void StencilAddRef(Stencil* stencil);
JS_PUBLIC_API void StencilRelease(Stencil* stencil);
// Compile the source text into a JS::Stencil using the provided options. The
// resulting stencil may be instantiated into any Realm on the current runtime
// and may be used multiple times.
//
// NOTE: On error, a null will be returned and an exception will be set on the
// JSContext.
extern JS_PUBLIC_API already_AddRefed<Stencil> CompileGlobalScriptToStencil(
JSContext* cx, const ReadOnlyCompileOptions& options,
SourceText<mozilla::Utf8Unit>& srcBuf);
// Instantiate the Stencil into current Realm and return the JSScript.
extern JS_PUBLIC_API JSScript* InstantiateGlobalStencil(
JSContext* cx, const ReadOnlyCompileOptions& options,
RefPtr<Stencil> stencil);
// Serialize the Stencil into the transcode buffer.
extern JS_PUBLIC_API TranscodeResult
EncodeStencil(JSContext* cx, const JS::ReadOnlyCompileOptions& options,
RefPtr<Stencil> stencil, TranscodeBuffer& buffer);
// Deserialize data and create a new Stencil.
extern JS_PUBLIC_API TranscodeResult
DecodeStencil(JSContext* cx, const ReadOnlyCompileOptions& options,
const TranscodeRange& range, RefPtr<Stencil>& stencilOut);
} // namespace JS
namespace mozilla {
template <>
struct RefPtrTraits<JS::Stencil> {
static void AddRef(JS::Stencil* stencil) { JS::StencilAddRef(stencil); }
static void Release(JS::Stencil* stencil) { JS::StencilRelease(stencil); }
};
} // namespace mozilla
#endif // js_experimental_JSStencil_h

View File

@ -38,24 +38,23 @@ class JS_PUBLIC_API AutoRequireNoGC;
* zeros.
*/
extern JS_FRIEND_API JSObject* JS_NewInt8Array(JSContext* cx,
uint32_t nelements);
extern JS_FRIEND_API JSObject* JS_NewInt8Array(JSContext* cx, size_t nelements);
extern JS_FRIEND_API JSObject* JS_NewUint8Array(JSContext* cx,
uint32_t nelements);
size_t nelements);
extern JS_FRIEND_API JSObject* JS_NewUint8ClampedArray(JSContext* cx,
uint32_t nelements);
size_t nelements);
extern JS_FRIEND_API JSObject* JS_NewInt16Array(JSContext* cx,
uint32_t nelements);
size_t nelements);
extern JS_FRIEND_API JSObject* JS_NewUint16Array(JSContext* cx,
uint32_t nelements);
size_t nelements);
extern JS_FRIEND_API JSObject* JS_NewInt32Array(JSContext* cx,
uint32_t nelements);
size_t nelements);
extern JS_FRIEND_API JSObject* JS_NewUint32Array(JSContext* cx,
uint32_t nelements);
size_t nelements);
extern JS_FRIEND_API JSObject* JS_NewFloat32Array(JSContext* cx,
uint32_t nelements);
size_t nelements);
extern JS_FRIEND_API JSObject* JS_NewFloat64Array(JSContext* cx,
uint32_t nelements);
size_t nelements);
/*
* Create a new typed array and copy in values from the given object. The
@ -92,38 +91,38 @@ extern JS_FRIEND_API JSObject* JS_NewFloat64ArrayFromArray(
*/
extern JS_FRIEND_API JSObject* JS_NewInt8ArrayWithBuffer(
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, uint32_t byteOffset,
int32_t length);
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, size_t byteOffset,
int64_t length);
extern JS_FRIEND_API JSObject* JS_NewUint8ArrayWithBuffer(
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, uint32_t byteOffset,
int32_t length);
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, size_t byteOffset,
int64_t length);
extern JS_FRIEND_API JSObject* JS_NewUint8ClampedArrayWithBuffer(
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, uint32_t byteOffset,
int32_t length);
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, size_t byteOffset,
int64_t length);
extern JS_FRIEND_API JSObject* JS_NewInt16ArrayWithBuffer(
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, uint32_t byteOffset,
int32_t length);
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, size_t byteOffset,
int64_t length);
extern JS_FRIEND_API JSObject* JS_NewUint16ArrayWithBuffer(
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, uint32_t byteOffset,
int32_t length);
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, size_t byteOffset,
int64_t length);
extern JS_FRIEND_API JSObject* JS_NewInt32ArrayWithBuffer(
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, uint32_t byteOffset,
int32_t length);
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, size_t byteOffset,
int64_t length);
extern JS_FRIEND_API JSObject* JS_NewUint32ArrayWithBuffer(
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, uint32_t byteOffset,
int32_t length);
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, size_t byteOffset,
int64_t length);
extern JS_FRIEND_API JSObject* JS_NewBigInt64ArrayWithBuffer(
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, uint32_t byteOffset,
int32_t length);
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, size_t byteOffset,
int64_t length);
extern JS_FRIEND_API JSObject* JS_NewBigUint64ArrayWithBuffer(
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, uint32_t byteOffset,
int32_t length);
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, size_t byteOffset,
int64_t length);
extern JS_FRIEND_API JSObject* JS_NewFloat32ArrayWithBuffer(
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, uint32_t byteOffset,
int32_t length);
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, size_t byteOffset,
int64_t length);
extern JS_FRIEND_API JSObject* JS_NewFloat64ArrayWithBuffer(
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, uint32_t byteOffset,
int32_t length);
JSContext* cx, JS::Handle<JSObject*> arrayBuffer, size_t byteOffset,
int64_t length);
/**
* Check whether obj supports JS_GetTypedArray* APIs. Note that this may return
@ -207,15 +206,15 @@ const size_t TypedArrayLengthSlot = 1;
} // namespace detail
#define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \
inline void Get##Type##ArrayLengthAndData( \
JSObject* obj, uint32_t* length, bool* isSharedMemory, type** data) { \
MOZ_ASSERT(JS::GetClass(obj) == detail::Type##ArrayClassPtr); \
const JS::Value& lenSlot = \
JS::GetReservedSlot(obj, detail::TypedArrayLengthSlot); \
*length = mozilla::AssertedCast<uint32_t>(size_t(lenSlot.toPrivate())); \
*isSharedMemory = JS_GetTypedArraySharedness(obj); \
*data = static_cast<type*>(JS::GetPrivate(obj)); \
#define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \
inline void Get##Type##ArrayLengthAndData( \
JSObject* obj, size_t* length, bool* isSharedMemory, type** data) { \
MOZ_ASSERT(JS::GetClass(obj) == detail::Type##ArrayClassPtr); \
const JS::Value& lenSlot = \
JS::GetReservedSlot(obj, detail::TypedArrayLengthSlot); \
*length = size_t(lenSlot.toPrivate()); \
*isSharedMemory = JS_GetTypedArraySharedness(obj); \
*data = static_cast<type*>(JS::GetPrivate(obj)); \
}
JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int8, int8_t)
@ -233,7 +232,7 @@ JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float64, double)
// This one isn't inlined because it's rather tricky (by dint of having to deal
// with a dozen-plus classes and varying slot layouts.
extern JS_FRIEND_API void GetArrayBufferViewLengthAndData(JSObject* obj,
uint32_t* length,
size_t* length,
bool* isSharedMemory,
uint8_t** data);
@ -245,41 +244,41 @@ extern JS_FRIEND_API void GetArrayBufferViewLengthAndData(JSObject* obj,
* object on success, filling both outparameters.
*/
extern JS_FRIEND_API JSObject* JS_GetObjectAsInt8Array(JSObject* obj,
uint32_t* length,
size_t* length,
bool* isSharedMemory,
int8_t** data);
extern JS_FRIEND_API JSObject* JS_GetObjectAsUint8Array(JSObject* obj,
uint32_t* length,
size_t* length,
bool* isSharedMemory,
uint8_t** data);
extern JS_FRIEND_API JSObject* JS_GetObjectAsUint8ClampedArray(
JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data);
JSObject* obj, size_t* length, bool* isSharedMemory, uint8_t** data);
extern JS_FRIEND_API JSObject* JS_GetObjectAsInt16Array(JSObject* obj,
uint32_t* length,
size_t* length,
bool* isSharedMemory,
int16_t** data);
extern JS_FRIEND_API JSObject* JS_GetObjectAsUint16Array(JSObject* obj,
uint32_t* length,
size_t* length,
bool* isSharedMemory,
uint16_t** data);
extern JS_FRIEND_API JSObject* JS_GetObjectAsInt32Array(JSObject* obj,
uint32_t* length,
size_t* length,
bool* isSharedMemory,
int32_t** data);
extern JS_FRIEND_API JSObject* JS_GetObjectAsUint32Array(JSObject* obj,
uint32_t* length,
size_t* length,
bool* isSharedMemory,
uint32_t** data);
extern JS_FRIEND_API JSObject* JS_GetObjectAsFloat32Array(JSObject* obj,
uint32_t* length,
size_t* length,
bool* isSharedMemory,
float** data);
extern JS_FRIEND_API JSObject* JS_GetObjectAsFloat64Array(JSObject* obj,
uint32_t* length,
size_t* length,
bool* isSharedMemory,
double** data);
extern JS_FRIEND_API JSObject* JS_GetObjectAsArrayBufferView(
JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data);
JSObject* obj, size_t* length, bool* isSharedMemory, uint8_t** data);
/*
* Get the type of elements in a typed array, or MaxTypedArrayViewType if a
@ -298,7 +297,7 @@ extern JS_FRIEND_API js::Scalar::Type JS_GetArrayBufferViewType(JSObject* obj);
* be known that it would pass such a test: it is a typed array or a wrapper of
* a typed array, and the unwrapping will succeed.
*/
extern JS_FRIEND_API uint32_t JS_GetTypedArrayLength(JSObject* obj);
extern JS_FRIEND_API size_t JS_GetTypedArrayLength(JSObject* obj);
/**
* Return the byte offset from the start of an ArrayBuffer to the start of a
@ -308,7 +307,7 @@ extern JS_FRIEND_API uint32_t JS_GetTypedArrayLength(JSObject* obj);
* be known that it would pass such a test: it is a typed array or a wrapper of
* a typed array, and the unwrapping will succeed.
*/
extern JS_FRIEND_API uint32_t JS_GetTypedArrayByteOffset(JSObject* obj);
extern JS_FRIEND_API size_t JS_GetTypedArrayByteOffset(JSObject* obj);
/**
* Return the byte length of a typed array.
@ -317,17 +316,17 @@ extern JS_FRIEND_API uint32_t JS_GetTypedArrayByteOffset(JSObject* obj);
* be known that it would pass such a test: it is a typed array or a wrapper of
* a typed array, and the unwrapping will succeed.
*/
extern JS_FRIEND_API uint32_t JS_GetTypedArrayByteLength(JSObject* obj);
extern JS_FRIEND_API size_t JS_GetTypedArrayByteLength(JSObject* obj);
/**
* More generic name for JS_GetTypedArrayByteLength to cover DataViews as well
*/
extern JS_FRIEND_API uint32_t JS_GetArrayBufferViewByteLength(JSObject* obj);
extern JS_FRIEND_API size_t JS_GetArrayBufferViewByteLength(JSObject* obj);
/**
* More generic name for JS_GetTypedArrayByteOffset to cover DataViews as well
*/
extern JS_FRIEND_API uint32_t JS_GetArrayBufferViewByteOffset(JSObject* obj);
extern JS_FRIEND_API size_t JS_GetArrayBufferViewByteOffset(JSObject* obj);
/*
* Return a pointer to the start of the data referenced by a typed array. The
@ -376,6 +375,28 @@ extern JS_FRIEND_API double* JS_GetFloat64ArrayData(JSObject* obj,
extern JS_FRIEND_API void* JS_GetArrayBufferViewData(
JSObject* obj, bool* isSharedMemory, const JS::AutoRequireNoGC&);
/**
* Return a "fixed" pointer (one that will not move during a GC) to the
* ArrayBufferView's data. Note that this will not keep the object alive; the
* holding object should be rooted or traced. If the view is storing the data
* inline, this will copy the data to the provided buffer, returning nullptr if
* bufSize is inadequate.
*
* Avoid using this unless necessary. JS_GetArrayBufferViewData is simpler and
* more efficient because it requires the caller to ensure that a GC will not
* occur and thus does not need to handle movable data.
*/
extern JS_FRIEND_API uint8_t* JS_GetArrayBufferViewFixedData(JSObject* obj,
uint8_t* buffer,
size_t bufSize);
/**
* If the bufSize passed to JS_GetArrayBufferViewFixedData is at least this
* many bytes, then any copied data is guaranteed to fit into the provided
* buffer.
*/
extern JS_FRIEND_API size_t JS_MaxMovableTypedArraySize();
/**
* Return the ArrayBuffer or SharedArrayBuffer underlying an ArrayBufferView.
* This may return a detached buffer. |obj| must be an object that would
@ -393,6 +414,18 @@ extern JS_FRIEND_API JSObject* JS_GetArrayBufferViewBuffer(
*/
JS_FRIEND_API JSObject* JS_NewDataView(JSContext* cx,
JS::Handle<JSObject*> buffer,
uint32_t byteOffset, int32_t byteLength);
size_t byteOffset, size_t byteLength);
namespace JS {
/*
* Returns whether the passed array buffer view is 'large': its byteLength >= 2
* GB. See also SetLargeArrayBuffersEnabled.
*
* |obj| must pass a JS_IsArrayBufferViewObject test.
*/
JS_FRIEND_API bool IsLargeArrayBufferView(JSObject* obj);
} // namespace JS
#endif // js_experimental_TypedData_h

View File

@ -80,7 +80,8 @@ MSG_DEF(JSMSG_SOURCE_ARRAY_TOO_LONG, 0, JSEXN_RANGEERR, "source array is too l
MSG_DEF(JSMSG_REDECLARED_PREV, 2, JSEXN_NOTE, "Previously declared at line {0}, column {1}")
MSG_DEF(JSMSG_REDECLARED_VAR, 2, JSEXN_SYNTAXERR, "redeclaration of {0} {1}")
MSG_DEF(JSMSG_UNDECLARED_VAR, 1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}")
MSG_DEF(JSMSG_UNDECLARED_PRIVATE, 0, JSEXN_TYPEERR, "Trying to read undeclared field")
MSG_DEF(JSMSG_GET_MISSING_PRIVATE, 0, JSEXN_TYPEERR, "can't access private field or method: object is not the right class")
MSG_DEF(JSMSG_SET_MISSING_PRIVATE, 0, JSEXN_TYPEERR, "can't set private field: object is not the right class")
MSG_DEF(JSMSG_GETTER_ONLY, 1, JSEXN_TYPEERR, "setting getter-only property {0}")
MSG_DEF(JSMSG_PRIVATE_SETTER_ONLY, 0, JSEXN_TYPEERR, "getting private setter-only property")
MSG_DEF(JSMSG_OVERWRITING_ACCESSOR, 1, JSEXN_TYPEERR, "can't overwrite accessor property {0}")
@ -208,8 +209,11 @@ MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS, 3, JSEXN_SYNTAXERR, "{0} functions must h
MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 0, JSEXN_INTERNALERR, "array initializer too large")
MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as' after import *")
MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
MSG_DEF(JSMSG_AS_AFTER_STRING, 0, JSEXN_SYNTAXERR, "missing keyword 'as' after string literal")
MSG_DEF(JSMSG_AWAIT_IN_PARAMETER, 0, JSEXN_SYNTAXERR, "await expression can't be used in parameter")
MSG_DEF(JSMSG_AWAIT_OUTSIDE_ASYNC, 0, JSEXN_SYNTAXERR, "await is only valid in async functions and async generators")
MSG_DEF(JSMSG_AWAIT_OUTSIDE_ASYNC_OR_MODULE, 0, JSEXN_SYNTAXERR, "await is only valid in async functions, async generators and modules")
MSG_DEF(JSMSG_TOP_LEVEL_AWAIT_NOT_SUPPORTED, 0, JSEXN_SYNTAXERR, "top level await is not currently supported")
MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated")
MSG_DEF(JSMSG_BAD_COALESCE_MIXING, 0, JSEXN_SYNTAXERR, "cannot use `??` unparenthesized within `||` and `&&` expressions")
@ -223,9 +227,10 @@ MSG_DEF(JSMSG_BAD_DUP_ARGS, 0, JSEXN_SYNTAXERR, "duplicate argument n
MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 0, JSEXN_SYNTAXERR, "invalid for each loop")
MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for-in/of left-hand side")
MSG_DEF(JSMSG_LEXICAL_DECL_DEFINES_LET,0, JSEXN_SYNTAXERR, "a lexical declaration can't define a 'let' binding")
MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS, 0, JSEXN_SYNTAXERR, "an expression X in 'for (X of Y)' must not start with 'let'")
MSG_DEF(JSMSG_BAD_STARTING_FOROF_LHS, 1, JSEXN_SYNTAXERR, "an expression X in 'for (X of Y)' must not start with '{0}'")
MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand")
MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS, 0, JSEXN_SYNTAXERR, "invalid assignment left-hand side")
MSG_DEF(JSMSG_BAD_LOCAL_STRING_EXPORT, 0, JSEXN_SYNTAXERR, "string exports can't be used without 'from'")
MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition")
MSG_DEF(JSMSG_BAD_POW_LEFTSIDE, 0, JSEXN_SYNTAXERR, "unparenthesized unary expression can't appear on the left-hand side of '**'")
MSG_DEF(JSMSG_BAD_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id")
@ -266,7 +271,9 @@ MSG_DEF(JSMSG_CURLY_IN_COMPOUND, 0, JSEXN_SYNTAXERR, "missing } in compoun
MSG_DEF(JSMSG_DECLARATION_AFTER_EXPORT,0, JSEXN_SYNTAXERR, "missing declaration after 'export' keyword")
MSG_DEF(JSMSG_DECLARATION_AFTER_IMPORT,0, JSEXN_SYNTAXERR, "missing declaration after 'import' keyword")
MSG_DEF(JSMSG_DEPRECATED_DELETE_OPERAND, 0, JSEXN_SYNTAXERR, "applying the 'delete' operator to an unqualified name is deprecated")
MSG_DEF(JSMSG_DEPRECATED_OCTAL, 0, JSEXN_SYNTAXERR, "\"0\"-prefixed octal literals and octal escape sequences are deprecated; for octal literals use the \"0o\" prefix instead")
MSG_DEF(JSMSG_DEPRECATED_OCTAL_LITERAL,0, JSEXN_SYNTAXERR, "\"0\"-prefixed octal literals are deprecated; use the \"0o\" prefix instead")
MSG_DEF(JSMSG_DEPRECATED_OCTAL_ESCAPE ,0, JSEXN_SYNTAXERR, "octal escape sequences can't be used in untagged template literals or in strict mode code")
MSG_DEF(JSMSG_DEPRECATED_EIGHT_OR_NINE_ESCAPE, 0, JSEXN_SYNTAXERR, "the escapes \\8 and \\9 can't be used in untagged template literals or in strict mode code")
MSG_DEF(JSMSG_DEPRECATED_PRAGMA, 1, JSEXN_WARN, "Using //@ to indicate {0} pragmas is deprecated. Use //# instead")
MSG_DEF(JSMSG_DUPLICATE_EXPORT_NAME, 1, JSEXN_SYNTAXERR, "duplicate export name '{0}'")
MSG_DEF(JSMSG_DUPLICATE_FORMAL, 1, JSEXN_SYNTAXERR, "duplicate formal argument {0}")
@ -362,6 +369,7 @@ MSG_DEF(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT, 1, JSEXN_SYNTAXERR, "unexpected token
MSG_DEF(JSMSG_UNEXPECTED_PARAMLIST_END,0, JSEXN_SYNTAXERR, "unexpected end of function parameter list")
MSG_DEF(JSMSG_UNNAMED_CLASS_STMT, 0, JSEXN_SYNTAXERR, "class statement requires a name")
MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 0, JSEXN_SYNTAXERR, "function statement requires a name")
MSG_DEF(JSMSG_UNPAIRED_SURROGATE_EXPORT, 0, JSEXN_SYNTAXERR, "module export name contains unpaired surrogate")
MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 0, JSEXN_SYNTAXERR, "unterminated comment")
MSG_DEF(JSMSG_UNTERMINATED_REGEXP, 0, JSEXN_SYNTAXERR, "unterminated regular expression literal")
MSG_DEF(JSMSG_EOF_BEFORE_END_OF_LITERAL,1,JSEXN_SYNTAXERR, "{0} literal not terminated before end of script")
@ -405,6 +413,7 @@ MSG_DEF(JSMSG_WASM_COMPILE_ERROR, 1, JSEXN_WASMCOMPILEERROR, "{0}")
MSG_DEF(JSMSG_WASM_NO_SHMEM_COMPILE, 0, JSEXN_WASMCOMPILEERROR, "shared memory is disabled")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_TYPE, 2, JSEXN_WASMLINKERROR, "import object field '{0}' is not a {1}")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_SIG, 2, JSEXN_WASMLINKERROR, "imported function '{0}.{1}' signature mismatch")
MSG_DEF(JSMSG_WASM_BAD_EXN_SIG, 2, JSEXN_WASMLINKERROR, "imported exception '{0}.{1}' signature mismatch")
MSG_DEF(JSMSG_WASM_BAD_IMP_SIZE, 1, JSEXN_WASMLINKERROR, "imported {0} with incompatible size")
MSG_DEF(JSMSG_WASM_BAD_IMP_MAX, 1, JSEXN_WASMLINKERROR, "imported {0} with incompatible maximum size")
MSG_DEF(JSMSG_WASM_IMP_SHARED_REQD, 0, JSEXN_WASMLINKERROR, "imported unshared memory but shared required")
@ -441,19 +450,18 @@ MSG_DEF(JSMSG_WASM_BAD_IMPORT_FIELD, 1, JSEXN_TYPEERR, "import object fiel
MSG_DEF(JSMSG_WASM_BAD_REF_NONNULLABLE_VALUE, 0, JSEXN_TYPEERR, "cannot pass null to non-nullable WebAssembly reference")
MSG_DEF(JSMSG_WASM_BAD_FUNCREF_VALUE, 0, JSEXN_TYPEERR, "can only pass WebAssembly exported functions to funcref")
MSG_DEF(JSMSG_WASM_BAD_EQREF_VALUE, 0, JSEXN_TYPEERR, "can only pass a TypedObject to an eqref")
MSG_DEF(JSMSG_WASM_BAD_I64_TYPE, 0, JSEXN_TYPEERR, "cannot pass v128 to or from JS")
MSG_DEF(JSMSG_WASM_BAD_VAL_TYPE, 0, JSEXN_TYPEERR, "cannot pass v128 to or from JS")
MSG_DEF(JSMSG_WASM_BAD_GLOBAL_TYPE, 0, JSEXN_TYPEERR, "bad type for a WebAssembly.Global")
MSG_DEF(JSMSG_WASM_NO_TRANSFER, 0, JSEXN_TYPEERR, "cannot transfer WebAssembly/asm.js ArrayBuffer")
MSG_DEF(JSMSG_WASM_TEXT_FAIL, 1, JSEXN_SYNTAXERR, "wasm text error: {0}")
MSG_DEF(JSMSG_WASM_MISSING_MAXIMUM, 0, JSEXN_TYPEERR, "'shared' is true but maximum is not specified")
MSG_DEF(JSMSG_WASM_GLOBAL_IMMUTABLE, 0, JSEXN_TYPEERR, "can't set value of immutable global")
MSG_DEF(JSMSG_WASM_TYPEREF_FROM_JS, 0, JSEXN_TYPEERR, "conversion from JavaScript value to WebAssembly typed ref unimplemented")
MSG_DEF(JSMSG_WASM_TYPEREF_TO_JS, 0, JSEXN_TYPEERR, "conversion from WebAssembly typed ref to JavaScript value unimplemented")
MSG_DEF(JSMSG_WASM_WRONG_NUMBER_OF_VALUES, 2, JSEXN_TYPEERR, "wrong number of values returned by JavaScript to WebAssembly (expected {0}, got {1})")
MSG_DEF(JSMSG_WASM_NONSHARED_WAIT , 0, JSEXN_WASMRUNTIMEERROR, "atomic wait on non-shared memory")
MSG_DEF(JSMSG_WASM_NULL_REQUIRED, 0, JSEXN_TYPEERR, "nullref requires a null value")
MSG_DEF(JSMSG_WASM_SUPPLY_ONLY_ONE, 2, JSEXN_TYPEERR, "exactly one of {0} and {1} must be supplied")
MSG_DEF(JSMSG_WASM_MISSING_REQUIRED, 1, JSEXN_TYPEERR, "Missing required argument {0}")
MSG_DEF(JSMSG_WASM_EXN_CONSTRUCTOR, 1, JSEXN_WASMRUNTIMEERROR, "cannot call {0}")
// Proxy
MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE, 2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value")
@ -600,25 +608,21 @@ MSG_DEF(JSMSG_INVALID_CAPTURE_NAME, 0, JSEXN_SYNTAXERR, "invalid capture
MSG_DEF(JSMSG_DUPLICATE_CAPTURE_NAME, 0, JSEXN_SYNTAXERR, "duplicate capture group name in regular expression")
MSG_DEF(JSMSG_INVALID_NAMED_REF, 0, JSEXN_SYNTAXERR, "invalid named reference in regular expression")
MSG_DEF(JSMSG_INVALID_NAMED_CAPTURE_REF, 0, JSEXN_SYNTAXERR, "invalid named capture reference in regular expression")
MSG_DEF(JSMSG_INCOMPATIBLE_REGEXP_GETTER, 2, JSEXN_TYPEERR, "RegExp.prototype.{0} getter called on non-RegExp object: {1}")
// Self-hosting
MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR, 0, JSEXN_ERR, "internal error getting the default locale")
MSG_DEF(JSMSG_NO_SUCH_SELF_HOSTED_PROP,1, JSEXN_ERR, "No such property on self-hosted object: {0}")
// Typed object
MSG_DEF(JSMSG_INVALID_PROTOTYPE, 0, JSEXN_TYPEERR, "prototype field is not an object")
MSG_DEF(JSMSG_TYPEDOBJECT_BAD_ARGS, 0, JSEXN_TYPEERR, "invalid arguments")
MSG_DEF(JSMSG_TYPEDOBJECT_BINARYARRAY_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED, 0, JSEXN_TYPEERR, "handle unattached")
MSG_DEF(JSMSG_TYPEDOBJECT_TOO_BIG, 0, JSEXN_ERR, "Type is too large to allocate")
MSG_DEF(JSMSG_TYPEDOBJECT_SETTING_IMMUTABLE, 0, JSEXN_ERR, "setting immutable field")
MSG_DEF(JSMSG_TYPEDOBJECT_NOT_CONSTRUCTIBLE, 0, JSEXN_TYPEERR, "not constructible")
// Array
MSG_DEF(JSMSG_TOO_LONG_ARRAY, 0, JSEXN_TYPEERR, "Too long array")
// Typed array
MSG_DEF(JSMSG_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
MSG_DEF(JSMSG_DEFINE_BAD_INDEX, 0, JSEXN_TYPEERR, "can't define element for invalid or out-of-range index")
MSG_DEF(JSMSG_NON_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected ArrayBuffer, but species constructor returned non-ArrayBuffer")
MSG_DEF(JSMSG_SAME_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different ArrayBuffer, but species constructor returned same ArrayBuffer")
MSG_DEF(JSMSG_SHORT_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected ArrayBuffer with at least {0} bytes, but species constructor returns ArrayBuffer with {1} bytes")
@ -701,7 +705,7 @@ MSG_DEF(JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.asyn
MSG_DEF(JSMSG_READABLESTREAM_UNDERLYINGSOURCE_TYPE_WRONG,0, JSEXN_RANGEERR,"'underlyingSource.type' must be \"bytes\" or undefined.")
MSG_DEF(JSMSG_READABLESTREAM_BYTES_TYPE_NOT_IMPLEMENTED, 0, JSEXN_RANGEERR,"support for 'new ReadableStream({ type: \"bytes\" })' is not yet implemented")
MSG_DEF(JSMSG_READABLESTREAM_BYOB_READER_FOR_NON_BYTE_STREAM,0,JSEXN_TYPEERR,"can't get a BYOB reader for a non-byte stream")
MSG_DEF(JSMSG_READABLESTREAM_INVALID_READER_MODE, 0, JSEXN_RANGEERR,"'mode' must be \"byob\" or undefined.")
MSG_DEF(JSMSG_READABLESTREAM_INVALID_READER_MODE, 0, JSEXN_TYPEERR,"'mode' must be \"byob\" or undefined.")
MSG_DEF(JSMSG_NUMBER_MUST_BE_FINITE_NON_NEGATIVE, 1, JSEXN_RANGEERR, "'{0}' must be a finite, non-negative number.")
MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_BYTESWRITTEN, 0, JSEXN_RANGEERR, "'bytesWritten' exceeds remaining length.")
MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_VIEW_SIZE, 0, JSEXN_RANGEERR, "view size does not match requested data.")
@ -738,16 +742,17 @@ MSG_DEF(JSMSG_WRITABLESTREAM_ALREADY_LOCKED, 0, JSEXN_TYPEERR, "writ
MSG_DEF(JSMSG_READABLESTREAM_NYI, 0, JSEXN_ERR, "full WritableStream support is not yet implemented")
// Other Stream-related
MSG_DEF(JSMSG_STREAM_MISSING_HIGHWATERMARK, 0, JSEXN_TYPEERR, "'highWaterMark' must not be undefined.")
MSG_DEF(JSMSG_STREAM_INVALID_HIGHWATERMARK, 0, JSEXN_RANGEERR, "'highWaterMark' must be a non-negative, non-NaN number.")
MSG_DEF(JSMSG_STREAM_CONSUME_ERROR, 0, JSEXN_TYPEERR, "error consuming stream body")
// Response-related
MSG_DEF(JSMSG_ERROR_CONSUMING_RESPONSE, 0, JSEXN_TYPEERR, "there was an error consuming the Response")
MSG_DEF(JSMSG_BAD_RESPONSE_VALUE, 0, JSEXN_TYPEERR, "expected Response or Promise resolving to Response")
MSG_DEF(JSMSG_BAD_RESPONSE_MIME_TYPE, 0, JSEXN_TYPEERR, "Response has unsupported MIME type")
MSG_DEF(JSMSG_BAD_RESPONSE_CORS_SAME_ORIGIN, 0, JSEXN_TYPEERR, "Response.type must be 'basic', 'cors' or 'default'")
MSG_DEF(JSMSG_BAD_RESPONSE_STATUS, 0, JSEXN_TYPEERR, "Response does not have ok status")
MSG_DEF(JSMSG_RESPONSE_ALREADY_CONSUMED, 0, JSEXN_TYPEERR, "Response already consumed")
// (wasm) Response-related
MSG_DEF(JSMSG_WASM_ERROR_CONSUMING_RESPONSE, 0, JSEXN_TYPEERR, "WebAssembly: There was an error consuming the Response")
MSG_DEF(JSMSG_WASM_BAD_RESPONSE_VALUE, 0, JSEXN_TYPEERR, "WebAssembly: Expected Response or Promise resolving to Response")
MSG_DEF(JSMSG_WASM_BAD_RESPONSE_MIME_TYPE, 2, JSEXN_TYPEERR, "WebAssembly: Response has unsupported MIME type '{0}' expected '{1}'")
MSG_DEF(JSMSG_WASM_BAD_RESPONSE_CORS_SAME_ORIGIN, 0, JSEXN_TYPEERR, "WebAssembly: Response.type must be 'basic', 'cors' or 'default'")
MSG_DEF(JSMSG_WASM_BAD_RESPONSE_STATUS, 0, JSEXN_TYPEERR, "WebAssembly: Response does not have ok status")
MSG_DEF(JSMSG_WASM_RESPONSE_ALREADY_CONSUMED, 0, JSEXN_TYPEERR, "WebAssembly: Response already consumed")
// BigInt
MSG_DEF(JSMSG_BIGINT_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert BigInt to number")

View File

@ -31,17 +31,17 @@ struct Zone {
Compact
};
enum Kind : uint8_t { NormalZone, AtomsZone, SelfHostingZone, SystemZone };
protected:
JSRuntime* const runtime_;
JSTracer* const barrierTracer_; // A pointer to the JSRuntime's |gcMarker|.
uint32_t needsIncrementalBarrier_;
GCState gcState_;
uint32_t needsIncrementalBarrier_ = 0;
GCState gcState_ = NoGC;
const Kind kind_;
Zone(JSRuntime* runtime, JSTracer* barrierTracerArg)
: runtime_(runtime),
barrierTracer_(barrierTracerArg),
needsIncrementalBarrier_(0),
gcState_(NoGC) {}
Zone(JSRuntime* runtime, JSTracer* barrierTracerArg, Kind kind)
: runtime_(runtime), barrierTracer_(barrierTracerArg), kind_(kind) {}
public:
bool needsIncrementalBarrier() const { return needsIncrementalBarrier_; }
@ -72,10 +72,17 @@ struct Zone {
bool isGCMarking() const {
return isGCMarkingBlackOnly() || isGCMarkingBlackAndGray();
}
bool isGCMarkingOrSweeping() const {
return gcState_ >= MarkBlackOnly && gcState_ <= Sweep;
}
bool isGCSweepingOrCompacting() const {
return gcState_ == Sweep || gcState_ == Compact;
}
bool isAtomsZone() const { return kind_ == AtomsZone; }
bool isSelfHostingZone() const { return kind_ == SelfHostingZone; }
bool isSystemZone() const { return kind_ == SystemZone; }
static shadow::Zone* from(JS::Zone* zone) {
return reinterpret_cast<shadow::Zone*>(zone);
}

View File

@ -215,6 +215,7 @@ const WHITELIST_TYPES: &'static [&'static str] = &[
"JS::Compartment",
"JS::Latin1Char",
"JS::detail::RootedPtr",
"JS::detail::RootListEntry",
"JS::MutableHandle",
"JS::MutableHandleObject",
"JS::MutableHandleValue",
@ -387,7 +388,6 @@ const WHITELIST_FUNCTIONS: &'static [&'static str] = &[
"JS_NewObject",
"JS_NewObjectWithGivenProto",
"JS_NewObjectWithoutMetadata",
"JS_NewObjectWithUniqueType",
"JS_NewPlainObject",
"JS::NewPromiseObject",
"JS_NewStringCopyN",

View File

@ -301,12 +301,6 @@ extern "C" {
aHandler: *const ::libc::c_void,
aClass: *const JSClass,
) -> *mut JSObject;
pub fn WrapperNewSingleton(
aCx: *mut JSContext,
aObj: JS::HandleObject,
aHandler: *const ::libc::c_void,
aClass: *const JSClass,
) -> *mut JSObject;
pub fn NewWindowProxy(
aCx: *mut JSContext,
aObj: JS::HandleObject,
@ -394,55 +388,55 @@ extern "C" {
pub fn GetInt8ArrayLengthAndData(
obj: *mut JSObject,
length: *mut u32,
length: *mut usize,
isSharedMemory: *mut bool,
data: *mut *mut i8,
);
pub fn GetUint8ArrayLengthAndData(
obj: *mut JSObject,
length: *mut u32,
length: *mut usize,
isSharedMemory: *mut bool,
data: *mut *mut u8,
);
pub fn GetUint8ClampedArrayLengthAndData(
obj: *mut JSObject,
length: *mut u32,
length: *mut usize,
isSharedMemory: *mut bool,
data: *mut *mut u8,
);
pub fn GetInt16ArrayLengthAndData(
obj: *mut JSObject,
length: *mut u32,
length: *mut usize,
isSharedMemory: *mut bool,
data: *mut *mut i16,
);
pub fn GetUint16ArrayLengthAndData(
obj: *mut JSObject,
length: *mut u32,
length: *mut usize,
isSharedMemory: *mut bool,
data: *mut *mut u16,
);
pub fn GetInt32ArrayLengthAndData(
obj: *mut JSObject,
length: *mut u32,
length: *mut usize,
isSharedMemory: *mut bool,
data: *mut *mut i32,
);
pub fn GetUint32ArrayLengthAndData(
obj: *mut JSObject,
length: *mut u32,
length: *mut usize,
isSharedMemory: *mut bool,
data: *mut *mut u32,
);
pub fn GetFloat32ArrayLengthAndData(
obj: *mut JSObject,
length: *mut u32,
length: *mut usize,
isSharedMemory: *mut bool,
data: *mut *mut f32,
);
pub fn GetFloat64ArrayLengthAndData(
obj: *mut JSObject,
length: *mut u32,
length: *mut usize,
isSharedMemory: *mut bool,
data: *mut *mut f64,
);

View File

@ -465,16 +465,6 @@ JSObject* WrapperNew(JSContext* aCx, JS::HandleObject aObj,
return js::Wrapper::New(aCx, aObj, (const js::Wrapper*)aHandler, options);
}
JSObject* WrapperNewSingleton(JSContext* aCx, JS::HandleObject aObj,
const void* aHandler, const JSClass* aClass) {
js::WrapperOptions options;
if (aClass) {
options.setClass(aClass);
}
return js::Wrapper::NewSingleton(aCx, aObj, (const js::Wrapper*)aHandler,
options);
}
const JSClass WindowProxyClass = PROXY_CLASS_DEF(
"Proxy", JSCLASS_HAS_RESERVED_SLOTS(1)); /* additional class flags */
@ -490,7 +480,7 @@ void SetProxyReservedSlot(JSObject* obj, uint32_t slot, const JS::Value* val) {
JSObject* NewWindowProxy(JSContext* aCx, JS::HandleObject aObj,
const void* aHandler) {
return WrapperNewSingleton(aCx, aObj, aHandler, &WindowProxyClass);
return WrapperNew(aCx, aObj, aHandler, &WindowProxyClass);
}
JS::Value GetProxyPrivate(JSObject* obj) { return js::GetProxyPrivate(obj); }
@ -677,7 +667,7 @@ bool IsDebugBuild() {
}
#define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \
void Get##Type##ArrayLengthAndData(JSObject* obj, uint32_t* length, \
void Get##Type##ArrayLengthAndData(JSObject* obj, size_t* length, \
bool* isSharedMemory, type** data) { \
js::Get##Type##ArrayLengthAndData(obj, length, isSharedMemory, data); \
}

View File

@ -366,7 +366,7 @@ impl<T> JS::Rooted<T> {
unsafe fn get_root_stack(
cx: *mut JSContext,
) -> *mut *mut JS::Rooted<*mut ::std::os::raw::c_void>
) -> *mut *mut JS::Rooted<*mut JS::detail::RootListEntry>
where
T: RootKind,
{

View File

@ -23,14 +23,14 @@ use std::ptr;
use std::slice;
pub enum CreateWith<'a, T: 'a> {
Length(u32),
Length(usize),
Slice(&'a [T]),
}
/// A rooted typed array.
pub struct TypedArray<'a, T: 'a + TypedArrayElement> {
object: RootedGuard<'a, *mut JSObject>,
computed: Option<(*mut T::Element, u32)>,
computed: Option<(*mut T::Element, usize)>,
}
impl<'a, T: TypedArrayElement> TypedArray<'a, T> {
@ -60,7 +60,7 @@ impl<'a, T: TypedArrayElement> TypedArray<'a, T> {
}
}
fn data(&mut self) -> (*mut T::Element, u32) {
fn data(&mut self) -> (*mut T::Element, usize) {
if let Some(data) = self.computed {
return data;
}
@ -102,7 +102,7 @@ impl<'a, T: TypedArrayElementCreator + TypedArrayElement> TypedArray<'a, T> {
) -> Result<(), ()> {
let length = match with {
CreateWith::Length(len) => len,
CreateWith::Slice(slice) => slice.len() as u32,
CreateWith::Slice(slice) => slice.len(),
};
result.set(T::create_new(cx, length));
@ -137,13 +137,13 @@ pub trait TypedArrayElement {
/// Unwrap a typed array JS reflector for this element type.
unsafe fn unwrap_array(obj: *mut JSObject) -> *mut JSObject;
/// Retrieve the length and data of a typed array's buffer for this element type.
unsafe fn length_and_data(obj: *mut JSObject) -> (*mut Self::Element, u32);
unsafe fn length_and_data(obj: *mut JSObject) -> (*mut Self::Element, usize);
}
/// Internal trait for creating new typed arrays.
pub trait TypedArrayElementCreator: TypedArrayElement {
/// Create a new typed array.
unsafe fn create_new(cx: *mut JSContext, length: u32) -> *mut JSObject;
unsafe fn create_new(cx: *mut JSContext, length: usize) -> *mut JSObject;
/// Get the data.
unsafe fn get_data(obj: *mut JSObject) -> *mut Self::Element;
}
@ -162,7 +162,7 @@ macro_rules! typed_array_element {
$unwrap(obj)
}
unsafe fn length_and_data(obj: *mut JSObject) -> (*mut Self::Element, u32) {
unsafe fn length_and_data(obj: *mut JSObject) -> (*mut Self::Element, usize) {
let mut len = 0;
let mut shared = false;
let mut data = ptr::null_mut();
@ -182,7 +182,7 @@ macro_rules! typed_array_element {
typed_array_element!($t, $element, $unwrap, $length_and_data);
impl TypedArrayElementCreator for $t {
unsafe fn create_new(cx: *mut JSContext, length: u32) -> *mut JSObject {
unsafe fn create_new(cx: *mut JSContext, length: usize) -> *mut JSObject {
$create_new(cx, length)
}

View File

@ -31,7 +31,7 @@ fn rooting() {
&c_option));
let _ar = js::ar::AutoRealm::with_obj(cx, global.get());
rooted!(in(cx) let prototype_proto = JS::GetRealmObjectPrototype(cx));
rooted!(in(cx) let proto = JS_NewObjectWithUniqueType(cx,
rooted!(in(cx) let proto = JS_NewObjectWithGivenProto(cx,
&CLASS as *const _,
prototype_proto.handle()));
define_methods(cx, proto.handle(), &METHODS[..]).unwrap();

View File

@ -72,7 +72,8 @@ ifndef HAVE_DTRACE
endif
endif
DIST_GARBAGE = config.cache config.log config.status* \
GARBAGE_DIRS += config.statusd
DIST_GARBAGE = config.cache config.log config.status \
config/autoconf.mk config/emptyvars.mk \
js-config.h js-confdefs.h \
backend.mk config/backend.mk devtools/backend.mk editline/backend.mk \

5
js/src/aclocal.m4 vendored
View File

@ -8,8 +8,6 @@ builtin(include, ../../build/autoconf/hooks.m4)dnl
builtin(include, ../../build/autoconf/config.status.m4)dnl
builtin(include, ../../build/autoconf/toolchain.m4)dnl
builtin(include, ../../build/autoconf/pkg.m4)dnl
builtin(include, ../../build/autoconf/nspr.m4)dnl
builtin(include, ../../build/autoconf/nspr-build.m4)dnl
builtin(include, ../../build/autoconf/codeset.m4)dnl
builtin(include, ../../build/autoconf/altoptions.m4)dnl
builtin(include, ../../build/autoconf/mozprog.m4)dnl
@ -18,12 +16,9 @@ builtin(include, ../../build/autoconf/compiler-opts.m4)dnl
builtin(include, ../../build/autoconf/expandlibs.m4)dnl
builtin(include, ../../build/autoconf/arch.m4)dnl
builtin(include, ../../build/autoconf/android.m4)dnl
builtin(include, ../../build/autoconf/zlib.m4)dnl
builtin(include, ../../build/autoconf/icu.m4)dnl
builtin(include, ../../build/autoconf/clang-plugin.m4)dnl
builtin(include, ../../build/autoconf/alloc.m4)dnl
builtin(include, ../../build/autoconf/sanitize.m4)dnl
builtin(include, ../../build/autoconf/ios.m4)dnl
define([__MOZ_AC_INIT_PREPARE], defn([AC_INIT_PREPARE]))
define([AC_INIT_PREPARE],

View File

@ -3,14 +3,14 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
CONFIGURE_SUBST_FILES += [
'js-config',
'js.pc',
"js-config",
"js.pc",
]
LIBRARY_DEFINES['EXPORT_JS_API'] = True
LIBRARY_DEFINES["EXPORT_JS_API"] = True
if not CONFIG['JS_STANDALONE']:
LIBRARY_DEFINES['MOZ_HAS_MOZGLUE'] = True
if not CONFIG["JS_STANDALONE"]:
LIBRARY_DEFINES["MOZ_HAS_MOZGLUE"] = True
# JavaScript must be built shared, even for static builds, as it is used by
# other modules which are always built shared. Failure to do so results in
@ -20,60 +20,63 @@ if not CONFIG['JS_STANDALONE']:
# In fact, we now build both a static and a shared library, as the
# JS shell would like to link to the static library.
if CONFIG['JS_SHARED_LIBRARY']:
GeckoSharedLibrary('js', linkage=None)
SHARED_LIBRARY_NAME = CONFIG['JS_LIBRARY_NAME']
if CONFIG["JS_SHARED_LIBRARY"]:
GeckoSharedLibrary("js", linkage=None)
SHARED_LIBRARY_NAME = CONFIG["JS_LIBRARY_NAME"]
# Ensure symbol versions of shared library on Linux do not conflict
# with those in libxul.
if CONFIG['OS_TARGET'] == 'Linux':
GeneratedFile('symverscript', script='/build/gen_symverscript.py',
inputs=['symverscript.in'],
flags=[CONFIG['JS_LIBRARY_NAME'].replace('-', '_')])
SYMBOLS_FILE = '!symverscript'
if CONFIG["OS_TARGET"] == "Linux":
GeneratedFile(
"symverscript",
script="/build/gen_symverscript.py",
inputs=["symverscript.in"],
flags=[CONFIG["JS_LIBRARY_NAME"].replace("-", "_")],
)
SYMBOLS_FILE = "!symverscript"
else:
Library('js')
Library("js")
FORCE_STATIC_LIB = True
STATIC_LIBRARY_NAME = 'js_static'
STATIC_LIBRARY_NAME = "js_static"
if CONFIG['JS_HAS_INTL_API']:
if CONFIG["JS_HAS_INTL_API"]:
USE_LIBS += [
'icu',
"icu",
]
USE_LIBS += [
'nspr',
'zlib',
"nspr",
"zlib",
]
if CONFIG['OS_ARCH'] not in ('WINNT', 'HP-UX'):
if CONFIG["OS_ARCH"] not in ("WINNT", "HP-UX"):
OS_LIBS += [
'm',
"m",
]
if CONFIG['OS_ARCH'] == 'FreeBSD':
if CONFIG["OS_ARCH"] == "FreeBSD":
OS_LIBS += [
'-pthread',
"-pthread",
]
if CONFIG['OS_ARCH'] == 'Linux':
if CONFIG["OS_ARCH"] == "Linux":
OS_LIBS += [
'dl',
"dl",
]
if CONFIG['OS_ARCH'] == 'SunOS':
if CONFIG["OS_ARCH"] == "SunOS":
OS_LIBS += [
'posix4',
'dl',
'nsl',
'socket',
"posix4",
"dl",
"nsl",
"socket",
]
if CONFIG['MOZ_NEEDS_LIBATOMIC']:
OS_LIBS += ['atomic']
if CONFIG["MOZ_NEEDS_LIBATOMIC"]:
OS_LIBS += ["atomic"]
OS_LIBS += CONFIG['REALTIME_LIBS']
OS_LIBS += CONFIG["REALTIME_LIBS"]
NO_EXPAND_LIBS = True
@ -82,10 +85,12 @@ DIST_INSTALL = True
# Run SpiderMonkey style checker after linking the static library. This avoids
# running the script for no-op builds.
GeneratedFile(
'spidermonkey_checks', script='/config/run_spidermonkey_checks.py',
"spidermonkey_checks",
script="/config/run_spidermonkey_checks.py",
inputs=[
'!%sjs_static.%s' % (CONFIG['LIB_PREFIX'], CONFIG['LIB_SUFFIX']),
'/config/check_spidermonkey_style.py',
'/config/check_macroassembler_style.py',
'/config/check_js_opcode.py'
])
"!%sjs_static.%s" % (CONFIG["LIB_PREFIX"], CONFIG["LIB_SUFFIX"]),
"/config/check_spidermonkey_style.py",
#"/config/check_macroassembler_style.py",
"/config/check_js_opcode.py",
],
)

View File

@ -16,7 +16,7 @@ namespace js {
inline bool GetElement(JSContext* cx, HandleObject obj, uint32_t index,
MutableHandleValue vp) {
if (obj->isNative() &&
if (obj->is<NativeObject>() &&
index < obj->as<NativeObject>().getDenseInitializedLength()) {
vp.set(obj->as<NativeObject>().getDenseElement(index));
if (!vp.isMagic(JS_ELEMENTS_HOLE)) {

View File

@ -4,7 +4,6 @@
#include "builtin/Array-inl.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/MathAlgorithms.h"
@ -12,6 +11,7 @@
#include "mozilla/TextUtils.h"
#include <algorithm>
#include <iterator>
#include "jsapi.h"
#include "jsfriendapi.h"
@ -42,6 +42,7 @@
#include "vm/Shape.h"
#include "vm/ToSource.h" // js::ValueToSource
#include "vm/TypedArrayObject.h"
#include "vm/WellKnownAtom.h" // js_*_str
#include "vm/WrapperObject.h"
#include "vm/ArgumentsObject-inl.h"
@ -52,12 +53,10 @@
#include "vm/IsGivenTypeObject-inl.h"
#include "vm/JSAtom-inl.h"
#include "vm/NativeObject-inl.h"
#include "vm/ObjectGroup-inl.h" // JSObject::setSingleton
using namespace js;
using mozilla::Abs;
using mozilla::ArrayLength;
using mozilla::CeilingLog2;
using mozilla::CheckedInt;
using mozilla::DebugOnly;
@ -304,7 +303,7 @@ template <typename T>
static bool HasAndGetElement(JSContext* cx, HandleObject obj,
HandleObject receiver, T index, bool* hole,
MutableHandleValue vp) {
if (obj->isNative()) {
if (obj->is<NativeObject>()) {
NativeObject* nobj = &obj->as<NativeObject>();
if (index < nobj->getDenseInitializedLength()) {
vp.set(nobj->getDenseElement(size_t(index)));
@ -452,7 +451,7 @@ bool js::GetElements(JSContext* cx, HandleObject aobj, uint32_t length,
if (aobj->is<TypedArrayObject>()) {
Handle<TypedArrayObject*> typedArray = aobj.as<TypedArrayObject>();
if (typedArray->length().deprecatedGetUint32() == length) {
if (typedArray->length().get() == length) {
return TypedArrayObject::getElements(cx, typedArray, vp);
}
}
@ -474,7 +473,7 @@ bool js::GetElements(JSContext* cx, HandleObject aobj, uint32_t length,
static inline bool GetArrayElement(JSContext* cx, HandleObject obj,
uint64_t index, MutableHandleValue vp) {
if (obj->isNative()) {
if (obj->is<NativeObject>()) {
NativeObject* nobj = &obj->as<NativeObject>();
if (index < nobj->getDenseInitializedLength()) {
vp.set(nobj->getDenseElement(size_t(index)));
@ -537,13 +536,10 @@ static bool DeleteArrayElement(JSContext* cx, HandleObject obj, uint64_t index,
if (index <= UINT32_MAX) {
uint32_t idx = uint32_t(index);
if (idx < aobj->getDenseInitializedLength()) {
if (!aobj->maybeCopyElementsForWrite(cx)) {
return false;
}
if (idx + 1 == aobj->getDenseInitializedLength()) {
aobj->setDenseInitializedLengthMaybeNonExtensible(cx, idx);
} else {
aobj->setDenseElementHole(cx, idx);
aobj->setDenseElementHole(idx);
}
if (!SuppressDeletedElement(cx, obj, idx)) {
return false;
@ -672,10 +668,6 @@ bool js::ArraySetLength(JSContext* cx, Handle<ArrayObject*> arr, HandleId id,
ObjectOpResult& result) {
MOZ_ASSERT(id == NameToId(cx->names().length));
if (!arr->maybeCopyElementsForWrite(cx)) {
return false;
}
// Step 1.
uint32_t newLen;
if (attrs & JSPROP_IGNORE_VALUE) {
@ -770,10 +762,6 @@ bool js::ArraySetLength(JSContext* cx, Handle<ArrayObject*> arr, HandleId id,
// (non-configurable) elements.
if (!arr->isIndexed() && !arr->denseElementsMaybeInIteration() &&
!arr->denseElementsAreSealed()) {
if (!arr->maybeCopyElementsForWrite(cx)) {
return false;
}
uint32_t oldCapacity = arr->getDenseCapacity();
uint32_t oldInitializedLength = arr->getDenseInitializedLength();
MOZ_ASSERT(oldCapacity >= oldInitializedLength);
@ -906,7 +894,7 @@ bool js::ArraySetLength(JSContext* cx, Handle<ArrayObject*> arr, HandleId id,
// Update array length. Technically we should have been doing this
// throughout the loop, in step 19.d.iii.
arr->setLength(cx, newLen);
arr->setLength(newLen);
// Step 20.
if (attrs & JSPROP_READONLY) {
@ -959,13 +947,13 @@ static bool array_addProperty(JSContext* cx, HandleObject obj, HandleId id,
if (index >= length) {
MOZ_ASSERT(arr->lengthIsWritable(),
"how'd this element get added if length is non-writable?");
arr->setLength(cx, index + 1);
arr->setLength(index + 1);
}
return true;
}
static inline bool ObjectMayHaveExtraIndexedOwnProperties(JSObject* obj) {
if (!obj->isNative()) {
if (!obj->is<NativeObject>()) {
return true;
}
@ -987,7 +975,7 @@ static inline bool ObjectMayHaveExtraIndexedOwnProperties(JSObject* obj) {
* indexed properties or elements along its prototype chain.
*/
bool js::ObjectMayHaveExtraIndexedProperties(JSObject* obj) {
MOZ_ASSERT_IF(obj->hasDynamicPrototype(), !obj->isNative());
MOZ_ASSERT_IF(obj->hasDynamicPrototype(), !obj->is<NativeObject>());
if (ObjectMayHaveExtraIndexedOwnProperties(obj)) {
return true;
@ -1402,7 +1390,7 @@ bool js::array_join(JSContext* cx, unsigned argc, Value* vp) {
// An optimized version of a special case of steps 5-8: when length==1 and
// the 0th element is a string, ToString() of that element is a no-op and
// so it can be immediately returned as the result.
if (length == 1 && obj->isNative()) {
if (length == 1 && obj->is<NativeObject>()) {
NativeObject* nobj = &obj->as<NativeObject>();
if (nobj->getDenseInitializedLength() == 1) {
Value elem0 = nobj->getDenseElement(0);
@ -1520,10 +1508,8 @@ static bool array_toLocaleString(JSContext* cx, unsigned argc, Value* vp) {
}
/* vector must point to rooted memory. */
static bool SetArrayElements(
JSContext* cx, HandleObject obj, uint64_t start, uint32_t count,
const Value* vector,
ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update) {
static bool SetArrayElements(JSContext* cx, HandleObject obj, uint64_t start,
uint32_t count, const Value* vector) {
MOZ_ASSERT(count <= MAX_ARRAY_INDEX);
MOZ_ASSERT(start + count < uint64_t(DOUBLE_INTEGRAL_PRECISION_LIMIT));
@ -1533,8 +1519,8 @@ static bool SetArrayElements(
if (!ObjectMayHaveExtraIndexedProperties(obj) && start <= UINT32_MAX) {
NativeObject* nobj = &obj->as<NativeObject>();
DenseElementResult result = nobj->setOrExtendDenseElements(
cx, uint32_t(start), vector, count, updateTypes);
DenseElementResult result =
nobj->setOrExtendDenseElements(cx, uint32_t(start), vector, count);
if (result != DenseElementResult::Incomplete) {
return result == DenseElementResult::Success;
}
@ -1590,11 +1576,7 @@ static DenseElementResult ArrayReverseDenseKernel(JSContext* cx,
}
/* Fill out the array's initialized length to its proper length. */
obj->ensureDenseInitializedLength(cx, length, 0);
} else {
if (!obj->maybeCopyElementsForWrite(cx)) {
return DenseElementResult::Failure;
}
obj->ensureDenseInitializedLength(length, 0);
}
if (!obj->denseElementsMaybeInIteration() &&
@ -1610,7 +1592,7 @@ static DenseElementResult ArrayReverseDenseKernel(JSContext* cx,
return true;
}
obj->setDenseElementHole(cx, index);
obj->setDenseElementHole(index);
return SuppressDeletedProperty(cx, obj, INT_TO_JSID(index));
};
@ -1777,11 +1759,11 @@ static inline bool CompareLexicographicInt32(const Value& a, const Value& b,
if (digitsa == digitsb) {
*lessOrEqualp = (auint <= buint);
} else if (digitsa > digitsb) {
MOZ_ASSERT((digitsa - digitsb) < ArrayLength(powersOf10));
MOZ_ASSERT((digitsa - digitsb) < std::size(powersOf10));
*lessOrEqualp =
(uint64_t(auint) < uint64_t(buint) * powersOf10[digitsa - digitsb]);
} else { /* if (digitsb > digitsa) */
MOZ_ASSERT((digitsb - digitsa) < ArrayLength(powersOf10));
MOZ_ASSERT((digitsb - digitsa) < std::size(powersOf10));
*lessOrEqualp =
(uint64_t(auint) * powersOf10[digitsb - digitsa] <= uint64_t(buint));
}
@ -2117,11 +2099,11 @@ static bool FillWithUndefined(JSContext* cx, HandleObject obj, uint32_t start,
if (obj->is<ArrayObject>() &&
start + count >= obj->as<ArrayObject>().length()) {
obj->as<ArrayObject>().setLengthInt32(start + count);
obj->as<ArrayObject>().setLength(start + count);
}
for (uint32_t i = 0; i < count; i++) {
nobj->setDenseElementWithType(cx, start + i, UndefinedHandleValue);
nobj->setDenseElement(start + i, UndefinedHandleValue);
}
return true;
@ -2213,11 +2195,9 @@ bool js::intrinsic_ArrayNativeSort(JSContext* cx, unsigned argc, Value* vp) {
undefs = 0;
bool allStrings = true;
bool allInts = true;
bool extraIndexed;
RootedValue v(cx);
if (IsPackedArray(obj)) {
HandleArrayObject array = obj.as<ArrayObject>();
extraIndexed = false;
for (uint32_t i = 0; i < len; i++) {
if (!CheckForInterrupt(cx)) {
@ -2235,8 +2215,6 @@ bool js::intrinsic_ArrayNativeSort(JSContext* cx, unsigned argc, Value* vp) {
allInts = allInts && v.isInt32();
}
} else {
extraIndexed = ObjectMayHaveExtraIndexedProperties(obj);
for (uint32_t i = 0; i < len; i++) {
if (!CheckForInterrupt(cx)) {
return false;
@ -2306,13 +2284,7 @@ bool js::intrinsic_ArrayNativeSort(JSContext* cx, unsigned argc, Value* vp) {
}
}
// We can omit the type update when neither collecting the elements
// nor calling the default comparator can execute a (getter) function
// that might run user code.
ShouldUpdateTypes updateTypes = !extraIndexed && (allStrings || allInts)
? ShouldUpdateTypes::DontUpdate
: ShouldUpdateTypes::Update;
if (!SetArrayElements(cx, obj, 0, uint32_t(n), vec.begin(), updateTypes)) {
if (!SetArrayElements(cx, obj, 0, uint32_t(n), vec.begin())) {
return false;
}
}
@ -2349,8 +2321,8 @@ bool js::NewbornArrayPush(JSContext* cx, HandleObject obj, const Value& v) {
}
arr->setDenseInitializedLength(length + 1);
arr->setLengthInt32(length + 1);
arr->initDenseElementWithType(cx, length, v);
arr->setLength(length + 1);
arr->initDenseElement(length, v);
return true;
}
@ -2462,8 +2434,7 @@ void js::ArrayShiftMoveElements(ArrayObject* arr) {
AutoUnsafeCallWithABI unsafe;
MOZ_ASSERT(arr->isExtensible());
MOZ_ASSERT(arr->lengthIsWritable());
MOZ_ASSERT_IF(jit::JitOptions.warpBuilder, IsPackedArray(arr));
MOZ_ASSERT(!arr->denseElementsAreCopyOnWrite());
MOZ_ASSERT(IsPackedArray(arr));
MOZ_ASSERT(!arr->denseElementsHaveMaybeInIterationFlag());
size_t initlen = arr->getDenseInitializedLength();
@ -2485,19 +2456,6 @@ static inline void SetInitializedLength(JSContext* cx, NativeObject* obj,
}
}
static MOZ_MUST_USE bool MoveDenseElements(JSContext* cx, NativeObject* obj,
uint32_t dstStart, uint32_t srcStart,
uint32_t length) {
MOZ_ASSERT(obj->isExtensible());
if (!obj->maybeCopyElementsForWrite(cx)) {
return false;
}
obj->moveDenseElements(dstStart, srcStart, length);
return true;
}
static DenseElementResult ArrayShiftDenseKernel(JSContext* cx, HandleObject obj,
MutableHandleValue rval) {
if (!IsPackedArray(obj) && ObjectMayHaveExtraIndexedProperties(obj)) {
@ -2527,9 +2485,7 @@ static DenseElementResult ArrayShiftDenseKernel(JSContext* cx, HandleObject obj,
return DenseElementResult::Success;
}
if (!MoveDenseElements(cx, nobj, 0, 1, initlen - 1)) {
return DenseElementResult::Failure;
}
nobj->moveDenseElements(0, 1, initlen - 1);
SetInitializedLength(cx, nobj, initlen - 1);
return DenseElementResult::Success;
@ -2677,7 +2633,7 @@ static bool array_unshift(JSContext* cx, unsigned argc, Value* vp) {
}
}
for (uint32_t i = 0; i < args.length(); i++) {
nobj->setDenseElementWithType(cx, i, args[i]);
nobj->setDenseElement(i, args[i]);
}
optimized = true;
} while (false);
@ -2813,16 +2769,16 @@ static ArrayObject* CopyDenseArrayElements(JSContext* cx,
newlength = std::min<uint32_t>(initlen - begin, count);
}
ArrayObject* narr = NewFullyAllocatedArrayTryReuseGroup(cx, obj, newlength);
ArrayObject* narr = NewDenseFullyAllocatedArray(cx, newlength);
if (!narr) {
return nullptr;
}
MOZ_ASSERT(count >= narr->length());
narr->setLength(cx, count);
narr->setLength(count);
if (newlength > 0) {
narr->initDenseElements(cx, obj, begin, newlength);
narr->initDenseElements(obj, begin, newlength);
}
return narr;
@ -2860,7 +2816,7 @@ static bool CopyArrayElements(JSContext* cx, HandleObject obj, uint64_t begin,
break;
}
result->setDenseElementWithType(cx, index, value);
result->setDenseElement(index, value);
}
}
startIndex = index + 1;
@ -2969,7 +2925,7 @@ static bool array_splice_impl(JSContext* cx, unsigned argc, Value* vp,
}
} else {
/* Step 9. */
arr = NewFullyAllocatedArrayTryReuseGroup(cx, obj, count);
arr = NewDenseFullyAllocatedArray(cx, count);
if (!arr) {
return false;
}
@ -3031,16 +2987,13 @@ static bool array_splice_impl(JSContext* cx, unsigned argc, Value* vp,
MOZ_ASSERT(sourceIndex <= len && targetIndex <= len && len <= UINT32_MAX,
"sourceIndex and targetIndex are uint32 array indices");
MOZ_ASSERT(finalLength < len, "finalLength is strictly less than len");
MOZ_ASSERT(obj->isNative());
MOZ_ASSERT(obj->is<NativeObject>());
/* Steps 15.a-b. */
HandleArrayObject arr = obj.as<ArrayObject>();
if (targetIndex != 0 || !arr->tryShiftDenseElements(sourceIndex)) {
if (!MoveDenseElements(cx, arr, uint32_t(targetIndex),
uint32_t(sourceIndex),
uint32_t(len - sourceIndex))) {
return false;
}
arr->moveDenseElements(uint32_t(targetIndex), uint32_t(sourceIndex),
uint32_t(len - sourceIndex));
}
/* Steps 15.c-d. */
@ -3244,7 +3197,7 @@ static bool GetIndexedPropertiesInRange(JSContext* cx, HandleObject obj,
// properties.
JSObject* pobj = obj;
do {
if (!pobj->isNative() || pobj->getClass()->getResolve() ||
if (!pobj->is<NativeObject>() || pobj->getClass()->getResolve() ||
pobj->getOpsLookupProperty()) {
return true;
}
@ -3267,8 +3220,7 @@ static bool GetIndexedPropertiesInRange(JSContext* cx, HandleObject obj,
// Append typed array elements.
if (nativeObj->is<TypedArrayObject>()) {
uint32_t len =
nativeObj->as<TypedArrayObject>().length().deprecatedGetUint32();
size_t len = nativeObj->as<TypedArrayObject>().length().get();
for (uint32_t i = begin; i < len && i < end; i++) {
if (!indexes.append(i)) {
return false;
@ -3440,8 +3392,7 @@ static bool ArraySliceOrdinary(JSContext* cx, HandleObject obj, uint64_t begin,
}
}
RootedArrayObject narr(cx,
NewPartlyAllocatedArrayTryReuseGroup(cx, obj, count));
RootedArrayObject narr(cx, NewDensePartlyAllocatedArray(cx, count));
if (!narr) {
return false;
}
@ -3459,7 +3410,8 @@ static bool ArraySliceOrdinary(JSContext* cx, HandleObject obj, uint64_t begin,
}
}
if (obj->isNative() && obj->as<NativeObject>().isIndexed() && count > 1000) {
if (obj->is<NativeObject>() && obj->as<NativeObject>().isIndexed() &&
count > 1000) {
if (!SliceSparse(cx, obj, begin, end, narr)) {
return false;
}
@ -3589,19 +3541,19 @@ static bool ArraySliceDenseKernel(JSContext* cx, ArrayObject* arr,
if (!result->ensureElements(cx, newlength)) {
return false;
}
result->initDenseElements(cx, arr, begin, newlength);
result->initDenseElements(arr, begin, newlength);
}
}
MOZ_ASSERT(count >= result->length());
result->setLength(cx, count);
result->setLength(count);
return true;
}
JSObject* js::ArraySliceDense(JSContext* cx, HandleObject obj, int32_t begin,
int32_t end, HandleObject result) {
MOZ_ASSERT_IF(jit::JitOptions.warpBuilder, IsPackedArray(obj));
MOZ_ASSERT(IsPackedArray(obj));
if (result && IsArraySpecies(cx, obj)) {
if (!ArraySliceDenseKernel(cx, &obj->as<ArrayObject>(), begin, end,
@ -3638,8 +3590,8 @@ static bool array_isArray(JSContext* cx, unsigned argc, Value* vp) {
static bool ArrayFromCallArgs(JSContext* cx, CallArgs& args,
HandleObject proto = nullptr) {
ArrayObject* obj = NewCopiedArrayForCallingAllocationSite(
cx, args.array(), args.length(), proto);
ArrayObject* obj =
NewDenseCopiedArray(cx, args.length(), args.array(), proto);
if (!obj) {
return false;
}
@ -3800,8 +3752,7 @@ static inline bool ArrayConstructorImpl(JSContext* cx, CallArgs& args,
}
}
ArrayObject* obj =
NewPartlyAllocatedArrayForCallingAllocationSite(cx, length, proto);
ArrayObject* obj = NewDensePartlyAllocatedArray(cx, length, proto);
if (!obj) {
return false;
}
@ -3842,9 +3793,8 @@ ArrayObject* js::ArrayConstructorOneArg(JSContext* cx,
}
uint32_t length = uint32_t(lengthInt);
RootedObjectGroup group(cx, templateObject->group());
ArrayObject* res = NewPartlyAllocatedArrayTryUseGroup(cx, group, length);
MOZ_ASSERT_IF(res, res->realm() == group->realm());
ArrayObject* res = NewDensePartlyAllocatedArray(cx, length);
MOZ_ASSERT_IF(res, res->realm() == templateObject->realm());
return res;
}
@ -3874,8 +3824,7 @@ static JSObject* CreateArrayPrototype(JSContext* cx, JSProtoKey key) {
RootedArrayObject arrayProto(
cx, ArrayObject::createArray(cx, gc::AllocKind::OBJECT4, gc::TenuredHeap,
shape, group, 0, metadata));
if (!arrayProto || !JSObject::setSingleton(cx, arrayProto) ||
!JSObject::setDelegate(cx, arrayProto) ||
if (!arrayProto || !JSObject::setDelegate(cx, arrayProto) ||
!AddLengthProperty(cx, arrayProto)) {
return nullptr;
}
@ -3887,7 +3836,7 @@ static bool array_proto_finish(JSContext* cx, JS::HandleObject ctor,
JS::HandleObject proto) {
// Add Array.prototype[@@unscopables]. ECMA-262 draft (2016 Mar 19) 22.1.3.32.
RootedObject unscopables(
cx, NewSingletonObjectWithGivenProto<PlainObject>(cx, nullptr));
cx, NewTenuredObjectWithGivenProto<PlainObject>(cx, nullptr));
if (!unscopables) {
return false;
}
@ -3993,7 +3942,7 @@ static MOZ_ALWAYS_INLINE ArrayObject* NewArray(JSContext* cx, uint32_t length,
/* Fixup the elements pointer and length, which may be incorrect. */
ArrayObject* arr = &obj->as<ArrayObject>();
arr->setFixedElements();
arr->setLength(cx, length);
arr->setLength(length);
if (maxLength > 0 &&
!EnsureNewArrayElements(cx, arr, std::min(maxLength, length))) {
return nullptr;
@ -4037,10 +3986,6 @@ static MOZ_ALWAYS_INLINE ArrayObject* NewArray(JSContext* cx, uint32_t length,
EmptyShape::insertInitialShape(cx, shape, proto);
}
if (newKind == SingletonObject && !JSObject::setSingleton(cx, arr)) {
return nullptr;
}
if (isCachable) {
NewObjectCache& cache = cx->caches().newObjectCache;
NewObjectCache::EntryIndex entry = -1;
@ -4073,6 +4018,13 @@ ArrayObject* JS_FASTCALL js::NewDenseFullyAllocatedArray(
return NewArray<UINT32_MAX>(cx, length, proto, newKind);
}
ArrayObject* js::NewDensePartlyAllocatedArray(
JSContext* cx, uint32_t length, HandleObject proto /* = nullptr */,
NewObjectKind newKind /* = GenericObject */) {
return NewArray<ArrayObject::EagerAllocationMaxLength>(cx, length, proto,
newKind);
}
ArrayObject* JS_FASTCALL js::NewDenseUnallocatedArray(
JSContext* cx, uint32_t length, HandleObject proto /* = nullptr */,
NewObjectKind newKind /* = GenericObject */) {
@ -4126,166 +4078,9 @@ ArrayObject* js::NewDenseFullyAllocatedArrayWithTemplate(
return arr;
}
ArrayObject* js::NewDenseCopyOnWriteArray(JSContext* cx,
HandleArrayObject templateObject) {
MOZ_ASSERT(!gc::IsInsideNursery(templateObject));
gc::InitialHeap heap = GetInitialHeap(GenericObject, templateObject->group());
ArrayObject* arr =
ArrayObject::createCopyOnWriteArray(cx, heap, templateObject);
if (!arr) {
return nullptr;
}
probes::CreateObject(cx, arr);
return arr;
}
// Return a new array with the specified length and allocated capacity (up to
// maxLength), using the specified group if possible. If the specified group
// cannot be used, ensure that the created array at least has the given
// [[Prototype]].
template <uint32_t maxLength>
static inline ArrayObject* NewArrayTryUseGroup(
JSContext* cx, HandleObjectGroup group, size_t length,
NewObjectKind newKind = GenericObject) {
MOZ_ASSERT(newKind != SingletonObject);
RootedObject proto(cx, group->proto().toObject());
ArrayObject* res = NewArray<maxLength>(cx, length, proto, newKind);
if (!res) {
return nullptr;
}
res->setGroup(group);
// If the length calculation overflowed, make sure that is marked for the
// new group.
if (res->length() > INT32_MAX) {
res->setLength(cx, res->length());
}
return res;
}
ArrayObject* js::NewFullyAllocatedArrayTryUseGroup(JSContext* cx,
HandleObjectGroup group,
size_t length,
NewObjectKind newKind) {
return NewArrayTryUseGroup<UINT32_MAX>(cx, group, length, newKind);
}
ArrayObject* js::NewPartlyAllocatedArrayTryUseGroup(JSContext* cx,
HandleObjectGroup group,
size_t length) {
return NewArrayTryUseGroup<ArrayObject::EagerAllocationMaxLength>(cx, group,
length);
}
static bool CanReuseGroupForNewArray(JSObject* obj, JSContext* cx) {
if (!obj->is<ArrayObject>()) {
return false;
}
if (obj->as<ArrayObject>().realm() != cx->realm()) {
return false;
}
if (obj->staticPrototype() != cx->global()->maybeGetArrayPrototype()) {
return false;
}
return true;
}
// Return a new array with the default prototype and specified allocated
// capacity and length. If possible, try to reuse the group of the input
// object. The resulting array will either reuse the input object's group or
// will have unknown property types.
template <uint32_t maxLength>
static inline ArrayObject* NewArrayTryReuseGroup(
JSContext* cx, HandleObject obj, size_t length,
NewObjectKind newKind = GenericObject) {
if (!CanReuseGroupForNewArray(obj, cx)) {
return NewArray<maxLength>(cx, length, nullptr, newKind);
}
RootedObjectGroup group(cx, JSObject::getGroup(cx, obj));
if (!group) {
return nullptr;
}
return NewArrayTryUseGroup<maxLength>(cx, group, length, newKind);
}
ArrayObject* js::NewFullyAllocatedArrayTryReuseGroup(JSContext* cx,
HandleObject obj,
size_t length,
NewObjectKind newKind) {
return NewArrayTryReuseGroup<UINT32_MAX>(cx, obj, length, newKind);
}
ArrayObject* js::NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx,
HandleObject obj,
size_t length) {
return NewArrayTryReuseGroup<ArrayObject::EagerAllocationMaxLength>(cx, obj,
length);
}
ArrayObject* js::NewFullyAllocatedArrayForCallingAllocationSite(
JSContext* cx, size_t length, NewObjectKind newKind) {
RootedObjectGroup group(
cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array));
if (!group) {
return nullptr;
}
return NewArrayTryUseGroup<UINT32_MAX>(cx, group, length, newKind);
}
ArrayObject* js::NewPartlyAllocatedArrayForCallingAllocationSite(
JSContext* cx, size_t length, HandleObject proto) {
RootedObjectGroup group(
cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array, proto));
if (!group) {
return nullptr;
}
return NewArrayTryUseGroup<ArrayObject::EagerAllocationMaxLength>(cx, group,
length);
}
ArrayObject* js::NewCopiedArrayTryUseGroup(JSContext* cx,
HandleObjectGroup group,
const Value* vp, size_t length,
NewObjectKind newKind,
ShouldUpdateTypes updateTypes) {
ArrayObject* obj =
NewFullyAllocatedArrayTryUseGroup(cx, group, length, newKind);
if (!obj) {
return nullptr;
}
DenseElementResult result =
obj->setOrExtendDenseElements(cx, 0, vp, length, updateTypes);
if (result == DenseElementResult::Failure) {
return nullptr;
}
MOZ_ASSERT(result == DenseElementResult::Success);
return obj;
}
ArrayObject* js::NewCopiedArrayForCallingAllocationSite(
JSContext* cx, const Value* vp, size_t length,
HandleObject proto /* = nullptr */) {
RootedObjectGroup group(
cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array, proto));
if (!group) {
return nullptr;
}
return NewCopiedArrayTryUseGroup(cx, group, vp, length);
}
// TODO(no-TI): clean up.
ArrayObject* js::NewArrayWithGroup(JSContext* cx, uint32_t length,
HandleObjectGroup group,
bool convertDoubleElements) {
HandleObjectGroup group) {
// Ion can call this with a group from a different realm when calling
// another realm's Array constructor.
Maybe<AutoRealm> ar;
@ -4294,16 +4089,7 @@ ArrayObject* js::NewArrayWithGroup(JSContext* cx, uint32_t length,
ar.emplace(cx, group);
}
ArrayObject* res = NewFullyAllocatedArrayTryUseGroup(cx, group, length);
if (!res) {
return nullptr;
}
if (convertDoubleElements) {
res->setShouldConvertDoubleElements();
}
return res;
return NewDenseFullyAllocatedArray(cx, length);
}
#ifdef DEBUG

View File

@ -67,6 +67,12 @@ extern ArrayObject* JS_FASTCALL NewDenseFullyAllocatedArray(
JSContext* cx, uint32_t length, HandleObject proto = nullptr,
NewObjectKind newKind = GenericObject);
// Create a dense array with length == 'length', initialized length set to 0,
// and capacity == 'length' clamped to EagerAllocationMaxLength.
extern ArrayObject* NewDensePartlyAllocatedArray(
JSContext* cx, uint32_t length, HandleObject proto = nullptr,
NewObjectKind newKind = GenericObject);
// Create a dense array from the given array values, which must be rooted.
extern ArrayObject* NewDenseCopiedArray(JSContext* cx, uint32_t length,
const Value* values,
@ -77,44 +83,8 @@ extern ArrayObject* NewDenseCopiedArray(JSContext* cx, uint32_t length,
extern ArrayObject* NewDenseFullyAllocatedArrayWithTemplate(
JSContext* cx, uint32_t length, ArrayObject* templateObject);
// Create a dense array with the same copy-on-write elements as another object.
extern ArrayObject* NewDenseCopyOnWriteArray(JSContext* cx,
HandleArrayObject templateObject);
extern ArrayObject* NewFullyAllocatedArrayTryUseGroup(
JSContext* cx, HandleObjectGroup group, size_t length,
NewObjectKind newKind = GenericObject);
extern ArrayObject* NewPartlyAllocatedArrayTryUseGroup(JSContext* cx,
HandleObjectGroup group,
size_t length);
extern ArrayObject* NewFullyAllocatedArrayTryReuseGroup(
JSContext* cx, HandleObject obj, size_t length,
NewObjectKind newKind = GenericObject);
extern ArrayObject* NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx,
HandleObject obj,
size_t length);
extern ArrayObject* NewFullyAllocatedArrayForCallingAllocationSite(
JSContext* cx, size_t length, NewObjectKind newKind = GenericObject);
extern ArrayObject* NewPartlyAllocatedArrayForCallingAllocationSite(
JSContext* cx, size_t length, HandleObject proto);
extern ArrayObject* NewCopiedArrayTryUseGroup(
JSContext* cx, HandleObjectGroup group, const Value* vp, size_t length,
NewObjectKind newKind = GenericObject,
ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update);
extern ArrayObject* NewCopiedArrayForCallingAllocationSite(
JSContext* cx, const Value* vp, size_t length,
HandleObject proto = nullptr);
extern ArrayObject* NewArrayWithGroup(JSContext* cx, uint32_t length,
HandleObjectGroup group,
bool convertDoubleElements);
HandleObjectGroup group);
extern bool ToLength(JSContext* cx, HandleValue v, uint64_t* out);

View File

@ -1169,3 +1169,5 @@ function ArrayAt(index) {
// Step 7.
return O[k];
}
// This function is only barely too long for normal inlining.
_SetIsInlinableLargeFunction(ArrayAt);

View File

@ -1072,7 +1072,7 @@ static JSObject* CreateAtomicsObject(JSContext* cx, JSProtoKey key) {
if (!proto) {
return nullptr;
}
return NewSingletonObjectWithGivenProto(cx, &AtomicsObject::class_, proto);
return NewTenuredObjectWithGivenProto(cx, &AtomicsObject::class_, proto);
}
static const ClassSpec AtomicsClassSpec = {CreateAtomicsObject, nullptr,

View File

@ -27,14 +27,14 @@ class FutexThread {
friend class AutoLockFutexAPI;
public:
static MOZ_MUST_USE bool initialize();
[[nodiscard]] static bool initialize();
static void destroy();
static void lock();
static void unlock();
FutexThread();
MOZ_MUST_USE bool initInstance();
[[nodiscard]] bool initInstance();
void destroyInstance();
// Parameters to notify().
@ -60,9 +60,9 @@ class FutexThread {
// wait.
//
// wait() will not wake up spuriously.
MOZ_MUST_USE WaitResult
wait(JSContext* cx, js::UniqueLock<js::Mutex>& locked,
const mozilla::Maybe<mozilla::TimeDuration>& timeout);
[[nodiscard]] WaitResult wait(
JSContext* cx, js::UniqueLock<js::Mutex>& locked,
const mozilla::Maybe<mozilla::TimeDuration>& timeout);
// Notify the thread this is associated with.
//
@ -120,12 +120,12 @@ class FutexThread {
};
// Go to sleep if the int32_t value at the given address equals `value`.
MOZ_MUST_USE FutexThread::WaitResult atomics_wait_impl(
[[nodiscard]] FutexThread::WaitResult atomics_wait_impl(
JSContext* cx, SharedArrayRawBuffer* sarb, size_t byteOffset, int32_t value,
const mozilla::Maybe<mozilla::TimeDuration>& timeout);
// Go to sleep if the int64_t value at the given address equals `value`.
MOZ_MUST_USE FutexThread::WaitResult atomics_wait_impl(
[[nodiscard]] FutexThread::WaitResult atomics_wait_impl(
JSContext* cx, SharedArrayRawBuffer* sarb, size_t byteOffset, int64_t value,
const mozilla::Maybe<mozilla::TimeDuration>& timeout);
@ -133,8 +133,8 @@ MOZ_MUST_USE FutexThread::WaitResult atomics_wait_impl(
// all. The return value is nonnegative and is the number of waiters woken. If
// the number of waiters woken exceeds INT64_MAX then this never returns. If
// `count` is nonnegative then the return value is never greater than `count`.
MOZ_MUST_USE int64_t atomics_notify_impl(SharedArrayRawBuffer* sarb,
size_t byteOffset, int64_t count);
[[nodiscard]] int64_t atomics_notify_impl(SharedArrayRawBuffer* sarb,
size_t byteOffset, int64_t count);
} /* namespace js */

View File

@ -7,6 +7,7 @@
#include "jsapi.h"
#include "gc/Tracer.h"
#include "jit/InlinableNatives.h"
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
#include "js/PropertySpec.h"
#include "js/TracingAPI.h"
@ -229,4 +230,5 @@ const JSFunctionSpec BigIntObject::methods[] = {
JS_FS_END};
const JSFunctionSpec BigIntObject::staticMethods[] = {
JS_FN("asUintN", asUintN, 2, 0), JS_FN("asIntN", asIntN, 2, 0), JS_FS_END};
JS_INLINABLE_FN("asUintN", asUintN, 2, 0, BigIntAsUintN),
JS_INLINABLE_FN("asIntN", asIntN, 2, 0, BigIntAsIntN), JS_FS_END};

View File

@ -20,6 +20,7 @@
#include "vm/JSContext.h"
#include "vm/JSObject.h"
#include "vm/ProxyObject.h"
#include "vm/WellKnownAtom.h" // js_*_str
#include "vm/BooleanObject-inl.h"

View File

@ -1,13 +0,0 @@
/* 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/. */
// Give a builtin constructor that we can use as the default. When we give
// it to our newly made class, we will be sure to set it up with the correct name
// and .prototype, so that everything works properly.
var DefaultDerivedClassConstructor =
class extends null { constructor(...args) { super(...allowContentIter(args)); } };
var DefaultBaseClassConstructor =
class { constructor() { } };

View File

@ -24,6 +24,7 @@
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
#include "js/PropertySpec.h"
#include "js/Wrapper.h"
#include "util/DifferentialTesting.h"
#include "util/Windows.h"
#include "vm/ArrayBufferObject.h"
#include "vm/GlobalObject.h"
@ -72,14 +73,13 @@ bool DataViewObject::getAndCheckConstructorArgs(JSContext* cx,
BufferSize* byteOffsetPtr,
BufferSize* byteLengthPtr) {
// Step 3.
if (!IsArrayBufferMaybeShared(bufobj)) {
if (!bufobj->is<ArrayBufferObjectMaybeShared>()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_NOT_EXPECTED_TYPE, "DataView",
"ArrayBuffer", bufobj->getClass()->name);
return false;
}
Rooted<ArrayBufferObjectMaybeShared*> buffer(
cx, &AsArrayBufferMaybeShared(bufobj));
auto buffer = bufobj.as<ArrayBufferObjectMaybeShared>();
// Step 4.
uint64_t offset;
@ -148,8 +148,7 @@ bool DataViewObject::constructSameCompartment(JSContext* cx,
return false;
}
Rooted<ArrayBufferObjectMaybeShared*> buffer(
cx, &AsArrayBufferMaybeShared(bufobj));
auto buffer = bufobj.as<ArrayBufferObjectMaybeShared>();
JSObject* obj =
DataViewObject::create(cx, byteOffset, byteLength, buffer, proto);
if (!obj) {
@ -453,12 +452,10 @@ bool DataViewObject::write(JSContext* cx, Handle<DataViewObject*> obj,
return false;
}
#ifdef JS_MORE_DETERMINISTIC
// See the comment in ElementSpecific::doubleToNative.
if (TypeIsFloatingPoint<NativeType>()) {
if (js::SupportDifferentialTesting() && TypeIsFloatingPoint<NativeType>()) {
value = JS::CanonicalizeNaN(value);
}
#endif
// Step 6.
bool isLittleEndian = args.length() >= 3 && ToBoolean(args[2]);
@ -1026,8 +1023,7 @@ const JSPropertySpec DataViewObject::properties[] = {
JS_STRING_SYM_PS(toStringTag, "DataView", JSPROP_READONLY), JS_PS_END};
JS_FRIEND_API JSObject* JS_NewDataView(JSContext* cx, HandleObject buffer,
uint32_t byteOffset,
int32_t byteLength) {
size_t byteOffset, size_t byteLength) {
JSProtoKey key = JSProto_DataView;
RootedObject constructor(cx, GlobalObject::getOrCreateConstructor(cx, key));
if (!constructor) {
@ -1038,7 +1034,7 @@ JS_FRIEND_API JSObject* JS_NewDataView(JSContext* cx, HandleObject buffer,
cargs[0].setObject(*buffer);
cargs[1].setNumber(byteOffset);
cargs[2].setInt32(byteLength);
cargs[2].setNumber(byteLength);
RootedValue fun(cx, ObjectValue(*constructor));
RootedObject obj(cx);

View File

@ -5,7 +5,6 @@
#ifndef vm_DataViewObject_h
#define vm_DataViewObject_h
#include "mozilla/Attributes.h"
#include "mozilla/CheckedInt.h"
#include "gc/Barrier.h"

View File

@ -78,8 +78,8 @@ function GetCachedFormat(format, required, defaults) {
* Spec: ECMAScript Internationalization API Specification, 13.3.1.
*/
function Date_toLocaleString() {
// Steps 1-2. Note that valueOf enforces "this time value" restrictions.
var x = callFunction(std_Date_valueOf, this);
// Steps 1-2.
var x = callFunction(ThisTimeValue, this, DATE_METHOD_LOCALE_STRING);
if (Number_isNaN(x))
return "Invalid Date";
@ -111,8 +111,8 @@ function Date_toLocaleString() {
* Spec: ECMAScript Internationalization API Specification, 13.3.2.
*/
function Date_toLocaleDateString() {
// Steps 1-2. Note that valueOf enforces "this time value" restrictions.
var x = callFunction(std_Date_valueOf, this);
// Steps 1-2.
var x = callFunction(ThisTimeValue, this, DATE_METHOD_LOCALE_DATE_STRING);
if (Number_isNaN(x))
return "Invalid Date";
@ -144,8 +144,8 @@ function Date_toLocaleDateString() {
* Spec: ECMAScript Internationalization API Specification, 13.3.3.
*/
function Date_toLocaleTimeString() {
// Steps 1-2. Note that valueOf enforces "this time value" restrictions.
var x = callFunction(std_Date_valueOf, this);
// Steps 1-2.
var x = callFunction(ThisTimeValue, this, DATE_METHOD_LOCALE_TIME_STRING);
if (Number_isNaN(x))
return "Invalid Date";

View File

@ -9,7 +9,6 @@
#include "ds/LifoAlloc.h"
#include "frontend/BytecodeCompilation.h"
#include "frontend/CompilationInfo.h"
#include "gc/HashUtil.h"
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
#include "js/friend/JSMEnvironment.h" // JS::NewJSMEnvironment, JS::ExecuteInJSMEnvironment, JS::GetJSMEnvironmentOfScriptedCaller, JS::IsJSMEnvironment
@ -349,97 +348,6 @@ static bool EvalKernel(JSContext* cx, HandleValue v, EvalType evalType,
NullFramePtr() /* evalInFrame */, vp);
}
bool js::DirectEvalStringFromIon(JSContext* cx, HandleObject env,
HandleScript callerScript,
HandleValue newTargetValue, HandleString str,
jsbytecode* pc, MutableHandleValue vp) {
AssertInnerizedEnvironmentChain(cx, *env);
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, str, cx->global())) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_EVAL);
return false;
}
// ES5 15.1.2.1 steps 2-8.
RootedLinearString linearStr(cx, str->ensureLinear(cx));
if (!linearStr) {
return false;
}
EvalJSONResult ejr = TryEvalJSON(cx, linearStr, vp);
if (ejr != EvalJSONResult::NotJSON) {
return ejr == EvalJSONResult::Success;
}
EvalScriptGuard esg(cx);
esg.lookupInEvalCache(linearStr, callerScript, pc);
if (!esg.foundScript()) {
const char* filename;
unsigned lineno;
bool mutedErrors;
uint32_t pcOffset;
DescribeScriptedCallerForDirectEval(cx, callerScript, pc, &filename,
&lineno, &pcOffset, &mutedErrors);
const char* introducerFilename = filename;
if (callerScript->scriptSource()->introducerFilename()) {
introducerFilename = callerScript->scriptSource()->introducerFilename();
}
RootedScope enclosing(cx, callerScript->innermostScope(pc));
CompileOptions options(cx);
options.setIsRunOnce(true);
options.setNoScriptRval(false);
options.setMutedErrors(mutedErrors);
if (IsStrictEvalPC(pc)) {
options.setForceStrictMode();
}
if (introducerFilename) {
options.setFileAndLine(filename, 1);
options.setIntroductionInfo(introducerFilename, "eval", lineno,
callerScript, pcOffset);
} else {
options.setFileAndLine("eval", 1);
options.setIntroductionType("eval");
}
options.setNonSyntacticScope(
enclosing->hasOnChain(ScopeKind::NonSyntactic));
AutoStableStringChars linearChars(cx);
if (!linearChars.initTwoByte(cx, linearStr)) {
return false;
}
SourceText<char16_t> srcBuf;
const char16_t* chars = linearChars.twoByteRange().begin().get();
SourceOwnership ownership = linearChars.maybeGiveOwnershipToCaller()
? SourceOwnership::TakeOwnership
: SourceOwnership::Borrowed;
if (!srcBuf.init(cx, chars, linearStr->length(), ownership)) {
return false;
}
JSScript* script =
frontend::CompileEvalScript(cx, options, srcBuf, enclosing, env);
if (!script) {
return false;
}
esg.setNewScript(script);
}
return ExecuteKernel(cx, esg.script(), env, newTargetValue,
NullFramePtr() /* evalInFrame */, vp);
}
bool js::IndirectEval(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
@ -480,7 +388,7 @@ static bool ExecuteInExtensibleLexicalEnvironment(JSContext* cx,
RootedScript script(cx, scriptArg);
if (script->realm() != cx->realm()) {
script = CloneGlobalScript(cx, ScopeKind::NonSyntactic, script);
script = CloneGlobalScript(cx, script);
if (!script) {
return false;
}

View File

@ -16,19 +16,13 @@ namespace js {
// JSOp::Eval which in turn calls DirectEval. Thus, even though IndirectEval is
// the callee function object for *all* calls to eval, it is by construction
// only ever called in the case indirect eval.
extern MOZ_MUST_USE bool IndirectEval(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] extern bool IndirectEval(JSContext* cx, unsigned argc, Value* vp);
// Performs a direct eval of |v| (a string containing code, or another value
// that will be vacuously returned), which must correspond to the currently-
// executing stack frame, which must be a script frame.
extern MOZ_MUST_USE bool DirectEval(JSContext* cx, HandleValue v,
MutableHandleValue vp);
// Performs a direct eval called from Ion code.
extern MOZ_MUST_USE bool DirectEvalStringFromIon(
JSContext* cx, HandleObject scopeObj, HandleScript callerScript,
HandleValue newTargetValue, HandleString str, jsbytecode* pc,
MutableHandleValue vp);
[[nodiscard]] extern bool DirectEval(JSContext* cx, HandleValue v,
MutableHandleValue vp);
// True iff fun is a built-in eval function.
extern bool IsAnyBuiltinEval(JSFunction* fun);

View File

@ -11,7 +11,8 @@
#include "gc/Zone.h"
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
#include "vm/GlobalObject.h"
#include "vm/PlainObject.h" // js::PlainObject
#include "vm/PlainObject.h" // js::PlainObject
#include "vm/WellKnownAtom.h" // js_*_str
#include "vm/JSObject-inl.h"
#include "vm/NativeObject-inl.h"

View File

@ -3,14 +3,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Stream handler for operations that act on a target object, and possibly upon
* Handler for operations that act on a target object, and possibly upon
* an extra value.
*/
#ifndef builtin_streams_HandlerFunction_inl_h
#define builtin_streams_HandlerFunction_inl_h
#include "mozilla/Attributes.h" // MOZ_MUST_USE
#ifndef builtin_HandlerFunction_inl_h
#define builtin_HandlerFunction_inl_h
#include <stddef.h> // size_t
@ -31,16 +29,15 @@ namespace js {
// Handler functions are extended functions, that close over a target object and
// (optionally) over an extra object, storing those objects in the function's
// extended slots.
constexpr size_t StreamHandlerFunctionSlot_Target = 0;
constexpr size_t StreamHandlerFunctionSlot_Extra = 1;
constexpr size_t HandlerFunctionSlot_Target = 0;
constexpr size_t HandlerFunctionSlot_Extra = 1;
static_assert(StreamHandlerFunctionSlot_Extra <
FunctionExtended::NUM_EXTENDED_SLOTS,
static_assert(HandlerFunctionSlot_Extra < FunctionExtended::NUM_EXTENDED_SLOTS,
"handler function slots shouldn't exceed available extended "
"slots");
inline MOZ_MUST_USE JSFunction* NewHandler(JSContext* cx, Native handler,
JS::Handle<JSObject*> target) {
[[nodiscard]] inline JSFunction* NewHandler(JSContext* cx, Native handler,
JS::Handle<JSObject*> target) {
cx->check(target);
JS::Handle<PropertyName*> funName = cx->names().empty;
@ -50,30 +47,30 @@ inline MOZ_MUST_USE JSFunction* NewHandler(JSContext* cx, Native handler,
if (!handlerFun) {
return nullptr;
}
handlerFun->setExtendedSlot(StreamHandlerFunctionSlot_Target,
handlerFun->setExtendedSlot(HandlerFunctionSlot_Target,
JS::ObjectValue(*target));
return handlerFun;
}
inline MOZ_MUST_USE JSFunction* NewHandlerWithExtra(
[[nodiscard]] inline JSFunction* NewHandlerWithExtra(
JSContext* cx, Native handler, JS::Handle<JSObject*> target,
JS::Handle<JSObject*> extra) {
cx->check(extra);
JSFunction* handlerFun = NewHandler(cx, handler, target);
if (handlerFun) {
handlerFun->setExtendedSlot(StreamHandlerFunctionSlot_Extra,
handlerFun->setExtendedSlot(HandlerFunctionSlot_Extra,
JS::ObjectValue(*extra));
}
return handlerFun;
}
inline MOZ_MUST_USE JSFunction* NewHandlerWithExtraValue(
[[nodiscard]] inline JSFunction* NewHandlerWithExtraValue(
JSContext* cx, Native handler, JS::Handle<JSObject*> target,
JS::Handle<JS::Value> extra) {
cx->check(extra);
JSFunction* handlerFun = NewHandler(cx, handler, target);
if (handlerFun) {
handlerFun->setExtendedSlot(StreamHandlerFunctionSlot_Extra, extra);
handlerFun->setExtendedSlot(HandlerFunctionSlot_Extra, extra);
}
return handlerFun;
}
@ -83,20 +80,18 @@ inline MOZ_MUST_USE JSFunction* NewHandlerWithExtraValue(
* is always a |T*| object (and never a wrapper around one), return that |T*|.
*/
template <class T>
inline MOZ_MUST_USE T* TargetFromHandler(const JS::CallArgs& args) {
[[nodiscard]] inline T* TargetFromHandler(const JS::CallArgs& args) {
JSFunction& func = args.callee().as<JSFunction>();
return &func.getExtendedSlot(StreamHandlerFunctionSlot_Target)
.toObject()
.as<T>();
return &func.getExtendedSlot(HandlerFunctionSlot_Target).toObject().as<T>();
}
/**
* Within the call of a handler function that "closes over" a target value and
* an extra value, return that extra value.
*/
inline MOZ_MUST_USE JS::Value ExtraValueFromHandler(const JS::CallArgs& args) {
[[nodiscard]] inline JS::Value ExtraValueFromHandler(const JS::CallArgs& args) {
JSFunction& func = args.callee().as<JSFunction>();
return func.getExtendedSlot(StreamHandlerFunctionSlot_Extra);
return func.getExtendedSlot(HandlerFunctionSlot_Extra);
}
/**
@ -105,10 +100,10 @@ inline MOZ_MUST_USE JS::Value ExtraValueFromHandler(const JS::CallArgs& args) {
* wrapper around one), return that |T*|.
*/
template <class T>
inline MOZ_MUST_USE T* ExtraFromHandler(const JS::CallArgs& args) {
[[nodiscard]] inline T* ExtraFromHandler(const JS::CallArgs& args) {
return &ExtraValueFromHandler(args).toObject().as<T>();
}
} // namespace js
#endif // builtin_streams_HandlerFunction_inl_h
#endif // builtin_HandlerFunction_inl_h

View File

@ -27,7 +27,8 @@
#include "vm/JSContext.h"
#include "vm/JSObject.h"
#include "vm/JSONParser.h"
#include "vm/PlainObject.h" // js::PlainObject
#include "vm/PlainObject.h" // js::PlainObject
#include "vm/WellKnownAtom.h" // js_*_str
#include "builtin/Array-inl.h"
#include "builtin/Boolean-inl.h"
@ -1119,7 +1120,7 @@ static JSObject* CreateJSONObject(JSContext* cx, JSProtoKey key) {
if (!proto) {
return nullptr;
}
return NewSingletonObjectWithGivenProto(cx, &JSONClass, proto);
return NewTenuredObjectWithGivenProto(cx, &JSONClass, proto);
}
static const ClassSpec JSONClassSpec = {

View File

@ -330,8 +330,6 @@ bool MapIteratorObject::next(MapIteratorObject* mapIterator,
return true;
}
// Note: we don't need to call setDenseElementWithType because
// MapIteratorObject::createResultPair gave the elements unknown-types.
switch (mapIterator->kind()) {
case MapObject::Keys:
resultPairObj->setDenseElement(0, range->front().key.get());
@ -359,14 +357,6 @@ JSObject* MapIteratorObject::createResultPair(JSContext* cx) {
return nullptr;
}
Rooted<TaggedProto> proto(cx, resultPairObj->taggedProto());
ObjectGroup* group = ObjectGroupRealm::makeGroup(
cx, resultPairObj->realm(), resultPairObj->getClass(), proto);
if (!group) {
return nullptr;
}
resultPairObj->setGroup(group);
resultPairObj->setDenseInitializedLength(2);
resultPairObj->initDenseElement(0, NullValue());
resultPairObj->initDenseElement(1, NullValue());
@ -544,8 +534,8 @@ class js::OrderedHashTableRef : public gc::BufferableRef {
};
template <typename ObjectT>
inline static MOZ_MUST_USE bool PostWriteBarrierImpl(ObjectT* obj,
const Value& keyValue) {
[[nodiscard]] inline static bool PostWriteBarrierImpl(ObjectT* obj,
const Value& keyValue) {
if (MOZ_LIKELY(!keyValue.isObject() && !keyValue.isBigInt())) {
MOZ_ASSERT_IF(keyValue.isGCThing(), !IsInsideNursery(keyValue.toGCThing()));
return true;
@ -573,13 +563,13 @@ inline static MOZ_MUST_USE bool PostWriteBarrierImpl(ObjectT* obj,
return keys->append(keyValue);
}
inline static MOZ_MUST_USE bool PostWriteBarrier(MapObject* map,
const Value& key) {
[[nodiscard]] inline static bool PostWriteBarrier(MapObject* map,
const Value& key) {
return PostWriteBarrierImpl(map, key);
}
inline static MOZ_MUST_USE bool PostWriteBarrier(SetObject* set,
const Value& key) {
[[nodiscard]] inline static bool PostWriteBarrier(SetObject* set,
const Value& key) {
return PostWriteBarrierImpl(set, key);
}
@ -1128,8 +1118,6 @@ bool SetIteratorObject::next(SetIteratorObject* setIterator,
return true;
}
// Note: we don't need to call setDenseElementWithType because
// SetIteratorObject::createResult gave the elements unknown-types.
resultObj->setDenseElement(0, range->front().get());
range->popFront();
return false;
@ -1143,14 +1131,6 @@ JSObject* SetIteratorObject::createResult(JSContext* cx) {
return nullptr;
}
Rooted<TaggedProto> proto(cx, resultObj->taggedProto());
ObjectGroup* group = ObjectGroupRealm::makeGroup(
cx, resultObj->realm(), resultObj->getClass(), proto);
if (!group) {
return nullptr;
}
resultObj->setGroup(group);
resultObj->setDenseInitializedLength(1);
resultObj->initDenseElement(0, NullValue());

View File

@ -47,7 +47,7 @@ class HashableValue {
HashableValue() : value(UndefinedValue()) {}
MOZ_MUST_USE bool setValue(JSContext* cx, HandleValue v);
[[nodiscard]] bool setValue(JSContext* cx, HandleValue v);
HashNumber hash(const mozilla::HashCodeScrambler& hcs) const;
bool operator==(const HashableValue& other) const;
HashableValue trace(JSTracer* trc) const;
@ -69,7 +69,7 @@ template <typename Wrapper>
class MutableWrappedPtrOperations<HashableValue, Wrapper>
: public WrappedPtrOperations<HashableValue, Wrapper> {
public:
MOZ_MUST_USE bool setValue(JSContext* cx, HandleValue v) {
[[nodiscard]] bool setValue(JSContext* cx, HandleValue v) {
return static_cast<Wrapper*>(this)->get().setValue(cx, v);
}
};
@ -111,29 +111,29 @@ class MapObject : public NativeObject {
enum { NurseryKeysSlot, HasNurseryMemorySlot, SlotCount };
static MOZ_MUST_USE bool getKeysAndValuesInterleaved(
[[nodiscard]] static bool getKeysAndValuesInterleaved(
HandleObject obj, JS::MutableHandle<GCVector<JS::Value>> entries);
static MOZ_MUST_USE bool entries(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool entries(JSContext* cx, unsigned argc, Value* vp);
static MapObject* create(JSContext* cx, HandleObject proto = nullptr);
// Publicly exposed Map calls for JSAPI access (webidl maplike/setlike
// interfaces, etc.)
static uint32_t size(JSContext* cx, HandleObject obj);
static MOZ_MUST_USE bool get(JSContext* cx, HandleObject obj, HandleValue key,
MutableHandleValue rval);
static MOZ_MUST_USE bool has(JSContext* cx, HandleObject obj, HandleValue key,
bool* rval);
static MOZ_MUST_USE bool delete_(JSContext* cx, HandleObject obj,
HandleValue key, bool* rval);
[[nodiscard]] static bool get(JSContext* cx, HandleObject obj,
HandleValue key, MutableHandleValue rval);
[[nodiscard]] static bool has(JSContext* cx, HandleObject obj,
HandleValue key, bool* rval);
[[nodiscard]] static bool delete_(JSContext* cx, HandleObject obj,
HandleValue key, bool* rval);
// Set call for public JSAPI exposure. Does not actually return map object
// as stated in spec, expects caller to return a value. for instance, with
// webidl maplike/setlike, should return interface object.
static MOZ_MUST_USE bool set(JSContext* cx, HandleObject obj, HandleValue key,
HandleValue val);
static MOZ_MUST_USE bool clear(JSContext* cx, HandleObject obj);
static MOZ_MUST_USE bool iterator(JSContext* cx, IteratorKind kind,
HandleObject obj, MutableHandleValue iter);
[[nodiscard]] static bool set(JSContext* cx, HandleObject obj,
HandleValue key, HandleValue val);
[[nodiscard]] static bool clear(JSContext* cx, HandleObject obj);
[[nodiscard]] static bool iterator(JSContext* cx, IteratorKind kind,
HandleObject obj, MutableHandleValue iter);
using UnbarrieredTable =
OrderedHashMap<Value, Value, UnbarrieredHashPolicy, ZoneAllocPolicy>;
@ -156,31 +156,31 @@ class MapObject : public NativeObject {
static ValueMap& extract(const CallArgs& args);
static void trace(JSTracer* trc, JSObject* obj);
static void finalize(JSFreeOp* fop, JSObject* obj);
static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
static bool is(HandleValue v);
static bool is(HandleObject o);
static MOZ_MUST_USE bool iterator_impl(JSContext* cx, const CallArgs& args,
IteratorKind kind);
[[nodiscard]] static bool iterator_impl(JSContext* cx, const CallArgs& args,
IteratorKind kind);
static MOZ_MUST_USE bool size_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool size(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool get_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool get(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool has_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool has(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool set_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool set(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool delete_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool delete_(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool keys_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool keys(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool values_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool values(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool entries_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool clear_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool clear(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool size_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool size(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool get_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool get(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool has_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool has(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool set_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool set(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool delete_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool delete_(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool keys_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool keys(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool values_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool values(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool entries_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool clear_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool clear(JSContext* cx, unsigned argc, Value* vp);
};
class MapIteratorObject : public NativeObject {
@ -211,8 +211,8 @@ class MapIteratorObject : public NativeObject {
initFixedSlot(KindSlot, JS::Int32Value(int32_t(kind)));
}
static MOZ_MUST_USE bool next(MapIteratorObject* mapIterator,
ArrayObject* resultPairObj);
[[nodiscard]] static bool next(MapIteratorObject* mapIterator,
ArrayObject* resultPairObj);
static JSObject* createResultPair(JSContext* cx);
@ -240,23 +240,23 @@ class SetObject : public NativeObject {
enum { NurseryKeysSlot, HasNurseryMemorySlot, SlotCount };
static MOZ_MUST_USE bool keys(JSContext* cx, HandleObject obj,
JS::MutableHandle<GCVector<JS::Value>> keys);
static MOZ_MUST_USE bool values(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool add(JSContext* cx, HandleObject obj,
HandleValue key);
[[nodiscard]] static bool keys(JSContext* cx, HandleObject obj,
JS::MutableHandle<GCVector<JS::Value>> keys);
[[nodiscard]] static bool values(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool add(JSContext* cx, HandleObject obj,
HandleValue key);
// Publicly exposed Set calls for JSAPI access (webidl maplike/setlike
// interfaces, etc.)
static SetObject* create(JSContext* cx, HandleObject proto = nullptr);
static uint32_t size(JSContext* cx, HandleObject obj);
static MOZ_MUST_USE bool has(JSContext* cx, HandleObject obj, HandleValue key,
bool* rval);
static MOZ_MUST_USE bool clear(JSContext* cx, HandleObject obj);
static MOZ_MUST_USE bool iterator(JSContext* cx, IteratorKind kind,
HandleObject obj, MutableHandleValue iter);
static MOZ_MUST_USE bool delete_(JSContext* cx, HandleObject obj,
HandleValue key, bool* rval);
[[nodiscard]] static bool has(JSContext* cx, HandleObject obj,
HandleValue key, bool* rval);
[[nodiscard]] static bool clear(JSContext* cx, HandleObject obj);
[[nodiscard]] static bool iterator(JSContext* cx, IteratorKind kind,
HandleObject obj, MutableHandleValue iter);
[[nodiscard]] static bool delete_(JSContext* cx, HandleObject obj,
HandleValue key, bool* rval);
using UnbarrieredTable =
OrderedHashSet<Value, UnbarrieredHashPolicy, ZoneAllocPolicy>;
@ -286,22 +286,22 @@ class SetObject : public NativeObject {
static bool isBuiltinAdd(HandleValue add);
static MOZ_MUST_USE bool iterator_impl(JSContext* cx, const CallArgs& args,
IteratorKind kind);
[[nodiscard]] static bool iterator_impl(JSContext* cx, const CallArgs& args,
IteratorKind kind);
static MOZ_MUST_USE bool size_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool size(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool has_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool has(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool add_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool add(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool delete_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool delete_(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool values_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool entries_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool entries(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool clear_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool clear(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool size_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool size(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool has_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool has(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool add_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool add(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool delete_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool delete_(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool values_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool entries_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool entries(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool clear_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool clear(JSContext* cx, unsigned argc, Value* vp);
};
class SetIteratorObject : public NativeObject {
@ -332,8 +332,8 @@ class SetIteratorObject : public NativeObject {
initFixedSlot(KindSlot, JS::Int32Value(int32_t(kind)));
}
static MOZ_MUST_USE bool next(SetIteratorObject* setIterator,
ArrayObject* resultObj);
[[nodiscard]] static bool next(SetIteratorObject* setIterator,
ArrayObject* resultObj);
static JSObject* createResult(JSContext* cx);
@ -346,10 +346,10 @@ using SetInitGetPrototypeOp = NativeObject* (*)(JSContext*,
using SetInitIsBuiltinOp = bool (*)(HandleValue);
template <SetInitGetPrototypeOp getPrototypeOp, SetInitIsBuiltinOp isBuiltinOp>
static MOZ_MUST_USE bool IsOptimizableInitForSet(JSContext* cx,
HandleObject setObject,
HandleValue iterable,
bool* optimized) {
[[nodiscard]] static bool IsOptimizableInitForSet(JSContext* cx,
HandleObject setObject,
HandleValue iterable,
bool* optimized) {
MOZ_ASSERT(!*optimized);
if (!iterable.isObject()) {

View File

@ -100,6 +100,8 @@ function ModuleSetStatus(module, newStatus)
//
function ModuleResolveExport(exportName, resolveSet = [])
{
assert(typeof exportName === "string", "ModuleResolveExport");
if (!IsObject(this) || !IsModule(this)) {
return callFunction(CallModuleMethodIfWrapped, this, exportName, resolveSet,
"ModuleResolveExport");
@ -135,7 +137,7 @@ function ModuleResolveExport(exportName, resolveSet = [])
if (exportName === e.exportName) {
let importedModule = CallModuleResolveHook(module, e.moduleRequest,
MODULE_STATUS_UNLINKED);
if (e.importName === "*") {
if (e.importName === null) {
return {module: importedModule, bindingName: "*namespace*"};
}
return callFunction(importedModule.resolveExport, importedModule, e.importName,
@ -475,7 +477,7 @@ function InitializeEnvironment()
let importedModule = CallModuleResolveHook(module, imp.moduleRequest,
MODULE_STATUS_LINKING);
// Step 9.c-9.d
if (imp.importName === "*") {
if (imp.importName === null) {
let namespace = GetModuleNamespace(importedModule);
CreateNamespaceBinding(env, imp.localName, namespace);
} else {
@ -574,6 +576,8 @@ function ModuleEvaluate()
if (!IsObject(this) || !IsModule(this))
return callFunction(CallModuleMethodIfWrapped, this, "ModuleEvaluate");
const isTopLevelAwaitEnabled = IsTopLevelAwaitEnabled();
// Step 2
let module = this;
@ -585,12 +589,37 @@ function ModuleEvaluate()
ThrowInternalError(JSMSG_BAD_MODULE_STATUS);
}
let capability = undefined;
if (isTopLevelAwaitEnabled) {
// Top-level Await Step 4
if (module.status === MODULE_STATUS_EVALUATED) {
module = GetAsyncCycleRoot(module);
}
// Top-level Await Step 5
if (module.topLevelCapability) {
return module.topLevelCapability;
}
capability = CreateTopLevelCapability(module);
}
// Step 4
let stack = [];
// Steps 5-6
try {
InnerModuleEvaluation(module, stack, 0);
if (isTopLevelAwaitEnabled) {
if (!module.asyncEvaluating) {
ModuleTopLevelCapabilityResolve(module);
}
// Steps 7-8
assert(module.status === MODULE_STATUS_EVALUATED,
"Bad module status after successful evaluation");
assert(stack.length === 0,
"Stack should be empty after successful evaluation");
}
} catch (error) {
for (let i = 0; i < stack.length; i++) {
let m = stack[i];
@ -606,23 +635,23 @@ function ModuleEvaluate()
assert(module.status === MODULE_STATUS_EVALUATED_ERROR,
"Bad module status after failed evaluation");
throw error;
if (isTopLevelAwaitEnabled) {
ModuleTopLevelCapabilityReject(module, error);
} else {
throw error;
}
}
// Steps 7-8
assert(module.status === MODULE_STATUS_EVALUATED,
"Bad module status after successful evaluation");
assert(stack.length === 0,
"Stack should be empty after successful evaluation");
// Step 9
return undefined;
return capability;
}
// https://tc39.es/ecma262/#sec-innermoduleevaluation
// ES2020 15.2.1.16.2.1 InnerModuleEvaluation
function InnerModuleEvaluation(module, stack, index)
{
const isTopLevelAwaitEnabled = IsTopLevelAwaitEnabled();
// Step 1
// TODO: Support module records other than Cyclic Module Records.
@ -647,6 +676,11 @@ function InnerModuleEvaluation(module, stack, index)
// Steps 6-8
UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_INDEX_SLOT, index);
UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT, index);
if (isTopLevelAwaitEnabled) {
UnsafeSetReservedSlot(module, MODULE_OBJECT_PENDING_ASYNC_DEPENDENCIES_SLOT, 0);
}
index++;
// Step 9
@ -676,11 +710,41 @@ function InnerModuleEvaluation(module, stack, index)
UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT,
std_Math_min(module.dfsAncestorIndex,
requiredModule.dfsAncestorIndex));
} else {
if (isTopLevelAwaitEnabled) {
requiredModule = GetAsyncCycleRoot(requiredModule);
assert(requiredModule.status === MODULE_STATUS_EVALUATED,
`Bad module status in InnerModuleEvaluation: ${requiredModule.status}`);
if (requiredModule.evaluationError) {
throw GetModuleEvaluationError(module);
}
}
}
if (isTopLevelAwaitEnabled) {
if (requiredModule.asyncEvaluating) {
UnsafeSetReservedSlot(module,
MODULE_OBJECT_PENDING_ASYNC_DEPENDENCIES_SLOT,
module.pendingAsyncDependencies + 1);
AppendAsyncParentModule(requiredModule, module);
}
}
}
// Step 11
ExecuteModule(module);
if (isTopLevelAwaitEnabled) {
if (module.pendingAsyncDependencies > 0) {
UnsafeSetReservedSlot(module, MODULE_OBJECT_ASYNC_EVALUATING_SLOT, true);
} else {
if (module.async) {
ExecuteAsyncModule(module);
} else {
// Step 11
ExecuteModule(module);
}
}
} else {
// Step 11
ExecuteModule(module);
}
// Step 12
assert(CountArrayValues(stack, module) === 1,
@ -702,3 +766,16 @@ function InnerModuleEvaluation(module, stack, index)
// Step 15
return index;
}
// https://tc39.es/proposal-top-level-await/#sec-execute-async-module
function ExecuteAsyncModule(module) {
// Steps 1-3.
assert(module.status == MODULE_STATUS_EVALUATING ||
module.status == MODULE_STATUS_EVALUATED, "bad status for async module");
assert(module.async, "module is not async");
UnsafeSetReservedSlot(module, MODULE_OBJECT_ASYNC_EVALUATING_SLOT, true);
// Step 4-11 done in AsyncAwait opcode
ExecuteModule(module);
}

File diff suppressed because it is too large Load Diff

View File

@ -5,23 +5,45 @@
#ifndef builtin_ModuleObject_h
#define builtin_ModuleObject_h
#include "mozilla/Maybe.h"
#include "mozilla/HashTable.h" // mozilla::{HashMap, DefaultHasher}
#include "mozilla/Maybe.h" // mozilla::Maybe
#include "jsapi.h"
#include <stddef.h> // size_t
#include <stdint.h> // int32_t, uint32_t
#include "builtin/SelfHostingDefines.h"
#include "frontend/Stencil.h"
#include "gc/ZoneAllocator.h"
#include "js/GCVector.h"
#include "js/Id.h"
#include "js/Modules.h"
#include "js/UniquePtr.h"
#include "vm/JSAtom.h"
#include "vm/NativeObject.h"
#include "vm/ProxyObject.h"
#include "builtin/SelfHostingDefines.h" // MODULE_OBJECT_*
#include "gc/Barrier.h" // HeapPtr, PreBarrieredId
#include "gc/Rooting.h" // HandleAtom, HandleArrayObject
#include "gc/ZoneAllocator.h" // ZoneAllocPolicy
#include "js/Class.h" // JSClass, ObjectOpResult
#include "js/GCVector.h" // GCVector
#include "js/Id.h" // jsid
#include "js/Modules.h" // JS::DynamicImportStatus
#include "js/PropertyDescriptor.h" // PropertyDescriptor
#include "js/Proxy.h" // BaseProxyHandler
#include "js/RootingAPI.h" // Rooted, Handle, MutableHandle
#include "js/TypeDecls.h" // HandleValue, HandleId, HandleObject, HandleScript, MutableHandleValue, MutableHandleIdVector, MutableHandleObject
#include "js/UniquePtr.h" // UniquePtr
#include "js/Value.h" // JS::Value
#include "vm/JSAtom.h" // JSAtom
#include "vm/JSObject.h" // JSObject
#include "vm/List.h" // ListObject
#include "vm/NativeObject.h" // NativeObject
#include "vm/PromiseObject.h" // js::PromiseObject
#include "vm/ProxyObject.h" // ProxyObject
#include "vm/Xdr.h" // XDRMode, XDRResult, XDRState
class JSFreeOp;
class JSScript;
class JSTracer;
namespace js {
class ArrayObject;
class Shape;
class Scope;
class ScriptSourceObject;
class ModuleEnvironmentObject;
class ModuleObject;
@ -44,8 +66,9 @@ class ImportEntryObject : public NativeObject {
static const JSClass class_;
static bool isInstance(HandleValue value);
static ImportEntryObject* create(JSContext* cx, HandleAtom moduleRequest,
HandleAtom importName, HandleAtom localName,
uint32_t lineNumber, uint32_t columnNumber);
HandleAtom maybeImportName,
HandleAtom localName, uint32_t lineNumber,
uint32_t columnNumber);
JSAtom* moduleRequest() const;
JSAtom* importName() const;
JSAtom* localName() const;
@ -152,8 +175,9 @@ class IndirectBindingMap {
HeapPtr<Shape*> shape;
};
using Map = HashMap<PreBarrieredId, Binding, DefaultHasher<PreBarrieredId>,
ZoneAllocPolicy>;
using Map =
mozilla::HashMap<PreBarrieredId, Binding,
mozilla::DefaultHasher<PreBarrieredId>, ZoneAllocPolicy>;
mozilla::Maybe<Map> map_;
};
@ -246,6 +270,11 @@ class ModuleObject : public NativeObject {
FunctionDeclarationsSlot,
DFSIndexSlot,
DFSAncestorIndexSlot,
AsyncSlot,
AsyncEvaluatingSlot,
TopLevelCapabilitySlot,
AsyncParentModulesSlot,
PendingAsyncDependenciesSlot,
SlotCount
};
@ -259,6 +288,14 @@ class ModuleObject : public NativeObject {
"DFSIndexSlot must match self-hosting define");
static_assert(DFSAncestorIndexSlot == MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT,
"DFSAncestorIndexSlot must match self-hosting define");
static_assert(AsyncEvaluatingSlot == MODULE_OBJECT_ASYNC_EVALUATING_SLOT,
"AsyncEvaluatingSlot must match self-hosting define");
static_assert(TopLevelCapabilitySlot ==
MODULE_OBJECT_TOP_LEVEL_CAPABILITY_SLOT,
"topLevelCapabilitySlot must match self-hosting define");
static_assert(PendingAsyncDependenciesSlot ==
MODULE_OBJECT_PENDING_ASYNC_DEPENDENCIES_SLOT,
"PendingAsyncDependenciesSlot must match self-hosting define");
static const JSClass class_;
@ -291,6 +328,8 @@ class ModuleObject : public NativeObject {
ModuleEnvironmentObject* environment() const;
ModuleNamespaceObject* namespace_();
ModuleStatus status() const;
uint32_t dfsIndex() const;
uint32_t dfsAncestorIndex() const;
bool hadEvaluationError() const;
Value evaluationError() const;
JSObject* metaObject() const;
@ -302,8 +341,33 @@ class ModuleObject : public NativeObject {
ArrayObject& starExportEntries() const;
IndirectBindingMap& importBindings();
static PromiseObject* createTopLevelCapability(JSContext* cx,
HandleModuleObject module);
bool isAsync() const;
void setAsync(bool isAsync);
bool isAsyncEvaluating() const;
void setAsyncEvaluating(bool isEvaluating);
void setEvaluationError(HandleValue newValue);
void setPendingAsyncDependencies(uint32_t newValue);
void setInitialTopLevelCapability(HandleObject promiseObj);
bool hasTopLevelCapability() const;
JSObject* topLevelCapability() const;
ListObject* asyncParentModules() const;
uint32_t pendingAsyncDependencies() const;
static bool appendAsyncParentModule(JSContext* cx, HandleModuleObject self,
HandleModuleObject parent);
static bool topLevelCapabilityResolve(JSContext* cx,
HandleModuleObject module);
static bool topLevelCapabilityReject(JSContext* cx, HandleModuleObject module,
HandleValue error);
static bool Instantiate(JSContext* cx, HandleModuleObject self);
static bool Evaluate(JSContext* cx, HandleModuleObject self);
// Start evaluating the module. If TLA is enabled, rval will be a promise
static bool Evaluate(JSContext* cx, HandleModuleObject self,
MutableHandleValue rval);
static ModuleNamespaceObject* GetOrCreateModuleNamespace(
JSContext* cx, HandleModuleObject self);
@ -325,8 +389,11 @@ class ModuleObject : public NativeObject {
static bool createEnvironment(JSContext* cx, HandleModuleObject self);
frontend::FunctionDeclarationVector* functionDeclarations();
void initFunctionDeclarations(frontend::FunctionDeclarationVector&& decls);
bool initAsyncSlots(JSContext* cx, bool isAsync,
HandleObject asyncParentModulesList);
// NOTE: accessor for FunctionDeclarationsSlot is defined inside
// ModuleObject.cpp as static function.
private:
static const JSClassOps classOps_;
@ -342,13 +409,41 @@ JSObject* GetOrCreateModuleMetaObject(JSContext* cx, HandleObject module);
JSObject* CallModuleResolveHook(JSContext* cx, HandleValue referencingPrivate,
HandleString specifier);
// https://tc39.es/proposal-top-level-await/#sec-getasynccycleroot
ModuleObject* GetAsyncCycleRoot(ModuleObject* module);
// https://tc39.es/proposal-top-level-await/#sec-asyncmodulexecutionfulfilled
void AsyncModuleExecutionFulfilled(JSContext* cx, HandleModuleObject module);
// https://tc39.es/proposal-top-level-await/#sec-asyncmodulexecutionrejected
void AsyncModuleExecutionRejected(JSContext* cx, HandleModuleObject module,
HandleValue error);
// https://tc39.es/proposal-top-level-await/#sec-asyncmodulexecutionfulfilled
bool AsyncModuleExecutionFulfilledHandler(JSContext* cx, unsigned argc,
Value* vp);
// https://tc39.es/proposal-top-level-await/#sec-asyncmodulexecutionrejected
bool AsyncModuleExecutionRejectedHandler(JSContext* cx, unsigned argc,
Value* vp);
JSObject* StartDynamicModuleImport(JSContext* cx, HandleScript script,
HandleValue specifier);
bool FinishDynamicModuleImport(JSContext* cx, JS::DynamicImportStatus status,
bool OnModuleEvaluationFailure(JSContext* cx, HandleObject evaluationPromise);
bool FinishDynamicModuleImport(JSContext* cx, HandleObject evaluationPromise,
HandleValue referencingPrivate,
HandleString specifier, HandleObject promise);
// This is used so that Top Level Await functionality can be turned off
// entirely. It will be removed in bug#1676612.
bool FinishDynamicModuleImport_NoTLA(JSContext* cx,
JS::DynamicImportStatus status,
HandleValue referencingPrivate,
HandleString specifier,
HandleObject promise);
template <XDRMode mode>
XDRResult XDRModuleObject(XDRState<mode>* xdr, MutableHandleModuleObject modp);

View File

@ -53,57 +53,41 @@ function Number_isNaN(num) {
return num !== num;
}
// ES2018 draft rev f83aa38282c2a60c6916ebc410bfdf105a0f6a54
// ES2021 draft rev 889f2f30cf554b7ed812c0984626db1c8a4997c7
// 20.1.2.3 Number.isInteger ( number )
function Number_isInteger(number) {
// Step 1.
// Step 1. (Inlined call to IsIntegralNumber)
// 7.2.6 IsIntegralNumber, step 1.
if (typeof number !== "number")
return false;
// -(2**31) is an int32, but abs(-(2**31)) isn't. Avoid bailouts below by
// special casing it here.
if (number === -(2 ** 31))
return true;
var integer = std_Math_trunc(number);
// Step 3.
// Note: We're using abs + floor instead ceil to workaround bug 1379626.
var absNumber = std_Math_abs(number);
var integer = std_Math_floor(absNumber);
// Steps 2, 4.
if (absNumber - integer !== 0)
return false;
// Step 5.
return true;
// 7.2.6 IsIntegralNumber, steps 2-4.
// |number - integer| ensures Infinity correctly returns false, because
// |Infinity - Infinity| yields NaN.
return number - integer === 0;
}
// ES2018 draft rev f83aa38282c2a60c6916ebc410bfdf105a0f6a54
// ES2021 draft rev 889f2f30cf554b7ed812c0984626db1c8a4997c7
// 20.1.2.5 Number.isSafeInteger ( number )
function Number_isSafeInteger(number) {
// Step 1.
// Step 1. (Inlined call to IsIntegralNumber)
// 7.2.6 IsIntegralNumber, step 1.
if (typeof number !== "number")
return false;
// -(2**31) is an int32, but abs(-(2**31)) isn't. Avoid bailouts below by
// special casing it here.
if (number === -(2 ** 31))
return true;
var integer = std_Math_trunc(number);
// Step 3.
var absNumber = std_Math_abs(number);
var integer = std_Math_floor(absNumber);
// Steps 2, 4.
if (absNumber - integer !== 0)
// 7.2.6 IsIntegralNumber, steps 2-4.
// |number - integer| to handle the Infinity case correctly.
if (number - integer !== 0)
return false;
// Step 5.
if (integer <= (2 ** 53) - 1)
return true;
// Step 6.
return false;
// Steps 1.a, 2.
return -((2 ** 53) - 1) <= integer && integer <= (2 ** 53) - 1;
}
function Global_isNaN(number) {

View File

@ -32,7 +32,8 @@
#include "vm/PlainObject.h" // js::PlainObject
#include "vm/RegExpObject.h"
#include "vm/StringObject.h"
#include "vm/ToSource.h" // js::ValueToSource
#include "vm/ToSource.h" // js::ValueToSource
#include "vm/WellKnownAtom.h" // js_*_str
#include "vm/JSObject-inl.h"
#include "vm/NativeObject-inl.h"
@ -93,8 +94,9 @@ bool js::obj_propertyIsEnumerable(JSContext* cx, unsigned argc, Value* vp) {
/* Step 3. */
PropertyResult prop;
if (obj->isNative() && NativeLookupOwnProperty<NoGC>(
cx, &obj->as<NativeObject>(), id, &prop)) {
if (obj->is<NativeObject>() &&
NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id,
&prop)) {
/* Step 4. */
if (!prop) {
args.rval().setBoolean(false);
@ -493,59 +495,48 @@ JSString* js::ObjectToSource(JSContext* cx, HandleObject obj) {
return buf.finishString();
}
static bool GetBuiltinTagSlow(JSContext* cx, HandleObject obj,
MutableHandleString builtinTag) {
static JSString* GetBuiltinTagSlow(JSContext* cx, HandleObject obj) {
// Step 4.
bool isArray;
if (!IsArray(cx, obj, &isArray)) {
return false;
return nullptr;
}
// Step 5.
if (isArray) {
builtinTag.set(cx->names().objectArray);
return true;
return cx->names().objectArray;
}
// Steps 6-13.
// Steps 6-14.
ESClass cls;
if (!JS::GetBuiltinClass(cx, obj, &cls)) {
return false;
return nullptr;
}
switch (cls) {
case ESClass::String:
builtinTag.set(cx->names().objectString);
return true;
return cx->names().objectString;
case ESClass::Arguments:
builtinTag.set(cx->names().objectArguments);
return true;
return cx->names().objectArguments;
case ESClass::Error:
builtinTag.set(cx->names().objectError);
return true;
return cx->names().objectError;
case ESClass::Boolean:
builtinTag.set(cx->names().objectBoolean);
return true;
return cx->names().objectBoolean;
case ESClass::Number:
builtinTag.set(cx->names().objectNumber);
return true;
return cx->names().objectNumber;
case ESClass::Date:
builtinTag.set(cx->names().objectDate);
return true;
return cx->names().objectDate;
case ESClass::RegExp:
builtinTag.set(cx->names().objectRegExp);
return true;
return cx->names().objectRegExp;
default:
if (obj->isCallable()) {
// Non-standard: Prevent <object> from showing up as Function.
RootedObject unwrapped(cx, CheckedUnwrapDynamic(obj, cx));
JSObject* unwrapped = CheckedUnwrapDynamic(obj, cx);
if (!unwrapped || !unwrapped->getClass()->isDOMClass()) {
builtinTag.set(cx->names().objectFunction);
return true;
return cx->names().objectFunction;
}
}
builtinTag.set(nullptr);
return true;
return cx->names().objectObject;
}
}
@ -553,12 +544,11 @@ static MOZ_ALWAYS_INLINE JSString* GetBuiltinTagFast(JSObject* obj,
const JSClass* clasp,
JSContext* cx) {
MOZ_ASSERT(clasp == obj->getClass());
MOZ_ASSERT(!clasp->isProxy());
MOZ_ASSERT(!clasp->isProxyObject());
// Optimize the non-proxy case to bypass GetBuiltinClass.
if (clasp == &PlainObject::class_) {
// This is not handled by GetBuiltinTagSlow, but this case is by far
// the most common so we optimize it here.
// This case is by far the most common so we handle it first.
return cx->names().objectObject;
}
@ -603,7 +593,7 @@ static MOZ_ALWAYS_INLINE JSString* GetBuiltinTagFast(JSObject* obj,
return cx->names().objectFunction;
}
return nullptr;
return cx->names().objectObject;
}
// For primitive values we try to avoid allocating the object if we can
@ -679,33 +669,14 @@ bool js::obj_toString(JSContext* cx, unsigned argc, Value* vp) {
obj = &args.thisv().toObject();
}
// When |obj| is a non-proxy object, compute |builtinTag| only when needed.
RootedString builtinTag(cx);
const JSClass* clasp = obj->getClass();
if (MOZ_UNLIKELY(clasp->isProxy())) {
if (!GetBuiltinTagSlow(cx, obj, &builtinTag)) {
if (MOZ_UNLIKELY(clasp->isProxyObject())) {
builtinTag = GetBuiltinTagSlow(cx, obj);
if (!builtinTag) {
return false;
}
} else {
builtinTag = GetBuiltinTagFast(obj, clasp, cx);
#ifdef DEBUG
// Assert this fast path is correct and matches BuiltinTagSlow. The
// only exception is the PlainObject case: we special-case it here
// because it's so common, but BuiltinTagSlow doesn't handle this.
RootedString builtinTagSlow(cx);
if (!GetBuiltinTagSlow(cx, obj, &builtinTagSlow)) {
return false;
}
if (clasp == &PlainObject::class_) {
MOZ_ASSERT(!builtinTagSlow);
} else {
MOZ_ASSERT(builtinTagSlow == builtinTag);
}
#endif
}
// Step 14.
if (!builtinTag) {
builtinTag = cx->names().objectObject;
}
// Step 15.
@ -717,6 +688,18 @@ bool js::obj_toString(JSContext* cx, unsigned argc, Value* vp) {
// Step 16.
if (!tag.isString()) {
if (!builtinTag) {
builtinTag = GetBuiltinTagFast(obj, clasp, cx);
#ifdef DEBUG
// Assert this fast path is correct and matches BuiltinTagSlow.
JSString* builtinTagSlow = GetBuiltinTagSlow(cx, obj);
if (!builtinTagSlow) {
return false;
}
MOZ_ASSERT(builtinTagSlow == builtinTag);
#endif
}
args.rval().setString(builtinTag);
return true;
}
@ -736,21 +719,14 @@ bool js::obj_toString(JSContext* cx, unsigned argc, Value* vp) {
return true;
}
JSString* js::ObjectClassToString(JSContext* cx, HandleObject obj) {
const JSClass* clasp = obj->getClass();
JSString* js::ObjectClassToString(JSContext* cx, JSObject* obj) {
AutoUnsafeCallWithABI unsafe;
if (JSString* tag = GetBuiltinTagFast(obj, clasp, cx)) {
return tag;
}
const char* className = clasp->name;
StringBuffer sb(cx);
if (!sb.append("[object ") || !sb.append(className, strlen(className)) ||
!sb.append(']')) {
if (MaybeHasInterestingSymbolProperty(cx, obj,
cx->wellKnownSymbols().toStringTag)) {
return nullptr;
}
return sb.finishAtom();
return GetBuiltinTagFast(obj, obj->getClass(), cx);
}
static bool obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp) {
@ -798,7 +774,7 @@ static bool obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp) {
static bool PropertyIsEnumerable(JSContext* cx, HandleObject obj, HandleId id,
bool* enumerable) {
PropertyResult prop;
if (obj->isNative() &&
if (obj->is<NativeObject>() &&
NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id, &prop)) {
if (!prop) {
*enumerable = false;
@ -823,7 +799,7 @@ static bool TryAssignNative(JSContext* cx, HandleObject to, HandleObject from,
bool* optimized) {
*optimized = false;
if (!from->isNative() || !to->isNative()) {
if (!from->is<NativeObject>() || !to->is<NativeObject>()) {
return true;
}
@ -868,7 +844,7 @@ static bool TryAssignNative(JSContext* cx, HandleObject to, HandleObject from,
// Ensure |from| is still native: a getter/setter might have been swapped
// with a non-native object.
if (MOZ_LIKELY(from->isNative() &&
if (MOZ_LIKELY(from->is<NativeObject>() &&
from->as<NativeObject>().lastProperty() == fromShape &&
shape->isDataProperty())) {
if (!shape->enumerable()) {
@ -993,7 +969,7 @@ static bool obj_assign(JSContext* cx, unsigned argc, Value* vp) {
}
/* ES5 15.2.4.6. */
static bool obj_isPrototypeOf(JSContext* cx, unsigned argc, Value* vp) {
bool js::obj_isPrototypeOf(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
/* Step 1. */
@ -1018,30 +994,10 @@ static bool obj_isPrototypeOf(JSContext* cx, unsigned argc, Value* vp) {
}
PlainObject* js::ObjectCreateImpl(JSContext* cx, HandleObject proto,
NewObjectKind newKind,
HandleObjectGroup group) {
NewObjectKind newKind) {
// Give the new object a small number of fixed slots, like we do for empty
// object literals ({}).
gc::AllocKind allocKind = GuessObjectGCKind(0);
if (!proto) {
// Object.create(null) is common, optimize it by using an allocation
// site specific ObjectGroup. Because GetCallerInitGroup is pretty
// slow, the caller can pass in the group if it's known and we use that
// instead.
RootedObjectGroup ngroup(cx, group);
if (!ngroup) {
ngroup = ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Null);
if (!ngroup) {
return nullptr;
}
}
MOZ_ASSERT(!ngroup->proto().toObjectOrNull());
return NewObjectWithGroup<PlainObject>(cx, ngroup, allocKind, newKind);
}
return NewObjectWithGivenProtoAndKinds<PlainObject>(cx, proto, allocKind,
newKind);
}
@ -1049,8 +1005,7 @@ PlainObject* js::ObjectCreateImpl(JSContext* cx, HandleObject proto,
PlainObject* js::ObjectCreateWithTemplate(JSContext* cx,
HandlePlainObject templateObj) {
RootedObject proto(cx, templateObj->staticPrototype());
RootedObjectGroup group(cx, templateObj->group());
return ObjectCreateImpl(cx, proto, GenericObject, group);
return ObjectCreateImpl(cx, proto, GenericObject);
}
// ES 2017 draft 19.1.2.3.1
@ -1309,7 +1264,7 @@ static bool TryEnumerableOwnPropertiesNative(JSContext* cx, HandleObject obj,
// they're only marked as indexed after their enumerate hook ran. And
// because their enumerate hook is slowish, it's more performant to
// exclude them directly instead of executing the hook first.
if (!obj->isNative() || obj->as<NativeObject>().isIndexed() ||
if (!obj->is<NativeObject>() || obj->as<NativeObject>().isIndexed() ||
obj->getClass()->getNewEnumerate() || obj->is<StringObject>()) {
return true;
}
@ -1371,7 +1326,7 @@ static bool TryEnumerableOwnPropertiesNative(JSContext* cx, HandleObject obj,
if (obj->is<TypedArrayObject>()) {
Handle<TypedArrayObject*> tobj = obj.as<TypedArrayObject>();
uint32_t len = tobj->length().deprecatedGetUint32();
size_t len = tobj->length().get();
// Fail early if the typed array contains too many elements for a
// dense array, because we likely OOM anyway when trying to allocate
@ -1421,7 +1376,7 @@ static bool TryEnumerableOwnPropertiesNative(JSContext* cx, HandleObject obj,
// Up to this point no side-effects through accessor properties are
// possible which could have replaced |obj| with a non-native object.
MOZ_ASSERT(obj->isNative());
MOZ_ASSERT(obj->is<NativeObject>());
if (kind == EnumerableOwnPropertiesKind::Keys ||
kind == EnumerableOwnPropertiesKind::Names ||
@ -1507,7 +1462,7 @@ static bool TryEnumerableOwnPropertiesNative(JSContext* cx, HandleObject obj,
// Ensure |obj| is still native: a getter might have been swapped with a
// non-native object.
if (obj->isNative() &&
if (obj->is<NativeObject>() &&
obj->as<NativeObject>().lastProperty() == objShape &&
shape->isDataProperty()) {
if (!shape->enumerable()) {
@ -1761,7 +1716,7 @@ bool js::GetOwnPropertyKeys(JSContext* cx, HandleObject obj, unsigned flags,
return false;
}
array->ensureDenseInitializedLength(cx, 0, keys.length());
array->ensureDenseInitializedLength(0, keys.length());
RootedValue val(cx);
for (size_t i = 0, len = keys.length(); i < len; i++) {
@ -2015,7 +1970,7 @@ static JSObject* CreateObjectConstructor(JSContext* cx, JSProtoKey key) {
/* Create the Object function now that we have a [[Prototype]] for it. */
JSFunction* fun = NewNativeConstructor(
cx, obj_construct, 1, HandlePropertyName(cx->names().Object),
gc::AllocKind::FUNCTION, SingletonObject);
gc::AllocKind::FUNCTION, TenuredObject);
if (!fun) {
return nullptr;
}
@ -2026,14 +1981,14 @@ static JSObject* CreateObjectConstructor(JSContext* cx, JSProtoKey key) {
static JSObject* CreateObjectPrototype(JSContext* cx, JSProtoKey key) {
MOZ_ASSERT(!cx->zone()->isAtomsZone());
MOZ_ASSERT(cx->global()->isNative());
MOZ_ASSERT(cx->global()->is<NativeObject>());
/*
* Create |Object.prototype| first, mirroring CreateBlankProto but for the
* prototype of the created object.
*/
RootedPlainObject objectProto(
cx, NewSingletonObjectWithGivenProto<PlainObject>(cx, nullptr));
cx, NewTenuredObjectWithGivenProto<PlainObject>(cx, nullptr));
if (!objectProto) {
return nullptr;
}
@ -2087,7 +2042,7 @@ static bool FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor,
*/
Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
if (global->shouldSplicePrototype()) {
if (!JSObject::splicePrototype(cx, global, tagged)) {
if (!GlobalObject::splicePrototype(cx, global, tagged)) {
return false;
}
}

View File

@ -15,44 +15,45 @@ namespace js {
class PlainObject;
// Object constructor native. Exposed only so the JIT can know its address.
MOZ_MUST_USE bool obj_construct(JSContext* cx, unsigned argc, JS::Value* vp);
[[nodiscard]] bool obj_construct(JSContext* cx, unsigned argc, JS::Value* vp);
PlainObject* ObjectCreateImpl(JSContext* cx, HandleObject proto,
NewObjectKind newKind = GenericObject,
HandleObjectGroup group = nullptr);
NewObjectKind newKind = GenericObject);
PlainObject* ObjectCreateWithTemplate(JSContext* cx,
Handle<PlainObject*> templateObj);
// Object methods exposed so they can be installed in the self-hosting global.
MOZ_MUST_USE bool obj_propertyIsEnumerable(JSContext* cx, unsigned argc,
Value* vp);
[[nodiscard]] bool obj_propertyIsEnumerable(JSContext* cx, unsigned argc,
Value* vp);
MOZ_MUST_USE bool obj_create(JSContext* cx, unsigned argc, JS::Value* vp);
[[nodiscard]] bool obj_isPrototypeOf(JSContext* cx, unsigned argc, Value* vp);
MOZ_MUST_USE bool obj_is(JSContext* cx, unsigned argc, JS::Value* vp);
[[nodiscard]] bool obj_create(JSContext* cx, unsigned argc, JS::Value* vp);
MOZ_MUST_USE bool obj_toString(JSContext* cx, unsigned argc, JS::Value* vp);
[[nodiscard]] bool obj_is(JSContext* cx, unsigned argc, JS::Value* vp);
MOZ_MUST_USE bool obj_setProto(JSContext* cx, unsigned argc, JS::Value* vp);
[[nodiscard]] bool obj_toString(JSContext* cx, unsigned argc, JS::Value* vp);
JSString* ObjectClassToString(JSContext* cx, HandleObject obj);
[[nodiscard]] bool obj_setProto(JSContext* cx, unsigned argc, JS::Value* vp);
MOZ_MUST_USE bool GetOwnPropertyKeys(JSContext* cx, HandleObject obj,
unsigned flags,
JS::MutableHandleValue rval);
JSString* ObjectClassToString(JSContext* cx, JSObject* obj);
[[nodiscard]] bool GetOwnPropertyKeys(JSContext* cx, HandleObject obj,
unsigned flags,
JS::MutableHandleValue rval);
// Exposed for SelfHosting.cpp
MOZ_MUST_USE bool GetOwnPropertyDescriptorToArray(JSContext* cx, unsigned argc,
JS::Value* vp);
[[nodiscard]] bool GetOwnPropertyDescriptorToArray(JSContext* cx, unsigned argc,
JS::Value* vp);
/*
* Like IdToValue, but convert int jsids to strings. This is used when
* exposing a jsid to script for Object.getOwnProperty{Names,Symbols}
* or scriptable proxy traps.
*/
MOZ_MUST_USE bool IdToStringOrSymbol(JSContext* cx, JS::HandleId id,
JS::MutableHandleValue result);
[[nodiscard]] bool IdToStringOrSymbol(JSContext* cx, JS::HandleId id,
JS::MutableHandleValue result);
// Object.prototype.toSource. Function.prototype.toSource and uneval use this.
JSString* ObjectToSource(JSContext* cx, JS::HandleObject obj);

View File

@ -9,6 +9,7 @@
#include "mozilla/Compiler.h"
#include "mozilla/Sprintf.h"
#include <iterator>
#include <stdarg.h>
#ifdef MOZ_CALLGRIND
@ -36,8 +37,6 @@
using namespace js;
using mozilla::ArrayLength;
/* Thread-unsafe error management */
static char gLastError[2000];
@ -500,7 +499,7 @@ bool js_StartPerf() {
mainPidStr, "--output", outfile};
Vector<const char*, 0, SystemAllocPolicy> args;
if (!args.append(defaultArgs, ArrayLength(defaultArgs))) {
if (!args.append(defaultArgs, std::size(defaultArgs))) {
return false;
}

View File

@ -27,35 +27,35 @@ typedef int pid_t;
*
* Returns true if no profilers fail to start.
*/
extern MOZ_MUST_USE JS_PUBLIC_API bool JS_StartProfiling(
[[nodiscard]] extern JS_PUBLIC_API bool JS_StartProfiling(
const char* profileName, pid_t pid);
/**
* Stop any profilers that were previously started with JS_StartProfiling.
* Returns true if no profilers fail to stop.
*/
extern MOZ_MUST_USE JS_PUBLIC_API bool JS_StopProfiling(
[[nodiscard]] extern JS_PUBLIC_API bool JS_StopProfiling(
const char* profileName);
/**
* Write the current profile data to the given file, if applicable to whatever
* profiler is being used.
*/
extern MOZ_MUST_USE JS_PUBLIC_API bool JS_DumpProfile(const char* outfile,
const char* profileName);
[[nodiscard]] extern JS_PUBLIC_API bool JS_DumpProfile(const char* outfile,
const char* profileName);
/**
* Pause currently active profilers (only supported by some profilers). Returns
* whether any profilers failed to pause. (Profilers that do not support
* pause/resume do not count.)
*/
extern MOZ_MUST_USE JS_PUBLIC_API bool JS_PauseProfilers(
[[nodiscard]] extern JS_PUBLIC_API bool JS_PauseProfilers(
const char* profileName);
/**
* Resume suspended profilers
*/
extern MOZ_MUST_USE JS_PUBLIC_API bool JS_ResumeProfilers(
[[nodiscard]] extern JS_PUBLIC_API bool JS_ResumeProfilers(
const char* profileName);
/**
@ -67,19 +67,19 @@ JS_PUBLIC_API const char* JS_UnsafeGetLastProfilingError();
#ifdef MOZ_CALLGRIND
extern MOZ_MUST_USE JS_FRIEND_API bool js_StopCallgrind();
[[nodiscard]] extern JS_FRIEND_API bool js_StopCallgrind();
extern MOZ_MUST_USE JS_FRIEND_API bool js_StartCallgrind();
[[nodiscard]] extern JS_FRIEND_API bool js_StartCallgrind();
extern MOZ_MUST_USE JS_FRIEND_API bool js_DumpCallgrind(const char* outfile);
[[nodiscard]] extern JS_FRIEND_API bool js_DumpCallgrind(const char* outfile);
#endif /* MOZ_CALLGRIND */
#ifdef __linux__
extern MOZ_MUST_USE JS_FRIEND_API bool js_StartPerf();
[[nodiscard]] extern JS_FRIEND_API bool js_StartPerf();
extern MOZ_MUST_USE JS_FRIEND_API bool js_StopPerf();
[[nodiscard]] extern JS_FRIEND_API bool js_StopPerf();
#endif /* __linux__ */

View File

@ -316,7 +316,7 @@ class MutableWrappedPtrOperations<PromiseCombinatorElements, Wrapper>
elements().setElementNeedsWrapping = needsWrapping;
}
MOZ_MUST_USE bool pushUndefined(JSContext* cx) {
[[nodiscard]] bool pushUndefined(JSContext* cx) {
// Helper for the AutoRealm we need to work with |array|. We mostly do this
// for performance; we could go ahead and do the define via a cross-
// compartment proxy instead...
@ -340,7 +340,8 @@ class MutableWrappedPtrOperations<PromiseCombinatorElements, Wrapper>
// Promise.all/allSettled/any function, which isn't necessarily the same
// compartment as unwrappedArray as explained in NewPromiseCombinatorElements.
// So before storing |val| we may need to enter unwrappedArray's compartment.
MOZ_MUST_USE bool setElement(JSContext* cx, uint32_t index, HandleValue val) {
[[nodiscard]] bool setElement(JSContext* cx, uint32_t index,
HandleValue val) {
// The index is guaranteed to be initialized to `undefined`.
MOZ_ASSERT(unwrappedArray()->getDenseElement(index).isUndefined());
@ -585,7 +586,7 @@ static bool MaybeGetAndClearExceptionAndStack(JSContext* cx,
return GetAndClearExceptionAndStack(cx, rval, stack);
}
static MOZ_MUST_USE bool RunRejectFunction(
[[nodiscard]] static bool RunRejectFunction(
JSContext* cx, HandleObject onRejectedFunc, HandleValue result,
HandleObject promiseObj, HandleSavedFrame unwrappedRejectionStack,
UnhandledRejectionBehavior behavior);
@ -862,7 +863,7 @@ static bool ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp);
static bool RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp);
// ES2016, 25.4.1.3.
static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool CreateResolvingFunctions(
[[nodiscard]] static MOZ_ALWAYS_INLINE bool CreateResolvingFunctions(
JSContext* cx, HandleObject promise, MutableHandleObject resolveFn,
MutableHandleObject rejectFn) {
HandlePropertyName funName = cx->names().empty;
@ -912,12 +913,12 @@ static bool IsSettledMaybeWrappedPromise(JSObject* promise) {
}
// ES2016, 25.4.1.7.
static MOZ_MUST_USE bool RejectMaybeWrappedPromise(
[[nodiscard]] static bool RejectMaybeWrappedPromise(
JSContext* cx, HandleObject promiseObj, HandleValue reason,
HandleSavedFrame unwrappedRejectionStack);
// ES2016, 25.4.1.7.
static MOZ_MUST_USE bool RejectPromiseInternal(
[[nodiscard]] static bool RejectPromiseInternal(
JSContext* cx, Handle<PromiseObject*> promise, HandleValue reason,
HandleSavedFrame unwrappedRejectionStack = nullptr);
@ -964,15 +965,15 @@ static bool RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp) {
return true;
}
static MOZ_MUST_USE bool FulfillMaybeWrappedPromise(JSContext* cx,
HandleObject promiseObj,
HandleValue value_);
[[nodiscard]] static bool FulfillMaybeWrappedPromise(JSContext* cx,
HandleObject promiseObj,
HandleValue value_);
static MOZ_MUST_USE bool EnqueuePromiseResolveThenableJob(
[[nodiscard]] static bool EnqueuePromiseResolveThenableJob(
JSContext* cx, HandleValue promiseToResolve, HandleValue thenable,
HandleValue thenVal);
static MOZ_MUST_USE bool EnqueuePromiseResolveThenableBuiltinJob(
[[nodiscard]] static bool EnqueuePromiseResolveThenableBuiltinJob(
JSContext* cx, HandleObject promiseToResolve, HandleObject thenable);
static bool Promise_then_impl(JSContext* cx, HandleValue promiseVal,
@ -980,9 +981,9 @@ static bool Promise_then_impl(JSContext* cx, HandleValue promiseVal,
MutableHandleValue rval, bool rvalUsed);
// ES2016, 25.4.1.3.2, steps 6-13.
static MOZ_MUST_USE bool ResolvePromiseInternal(JSContext* cx,
HandleObject promise,
HandleValue resolutionVal) {
[[nodiscard]] static bool ResolvePromiseInternal(JSContext* cx,
HandleObject promise,
HandleValue resolutionVal) {
cx->check(promise, resolutionVal);
MOZ_ASSERT(!IsSettledMaybeWrappedPromise(promise));
@ -1124,7 +1125,7 @@ static bool PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp);
* targetState - The PromiseState this reaction job targets. This decides
* whether the onFulfilled or onRejected handler is called.
*/
MOZ_MUST_USE static bool EnqueuePromiseReactionJob(
[[nodiscard]] static bool EnqueuePromiseReactionJob(
JSContext* cx, HandleObject reactionObj, HandleValue handlerArg_,
JS::PromiseState targetState) {
MOZ_ASSERT(targetState == JS::PromiseState::Fulfilled ||
@ -1257,10 +1258,10 @@ MOZ_MUST_USE static bool EnqueuePromiseReactionJob(
return cx->runtime()->enqueuePromiseJob(cx, job, promise, global);
}
static MOZ_MUST_USE bool TriggerPromiseReactions(JSContext* cx,
HandleValue reactionsVal,
JS::PromiseState state,
HandleValue valueOrReason);
[[nodiscard]] static bool TriggerPromiseReactions(JSContext* cx,
HandleValue reactionsVal,
JS::PromiseState state,
HandleValue valueOrReason);
// ES2016, Commoned-out implementation of 25.4.1.4. and 25.4.1.7.
//
@ -1268,7 +1269,7 @@ static MOZ_MUST_USE bool TriggerPromiseReactions(JSContext* cx,
// which is only used for debugging purposes.
// It allows callers to to pass in the stack of some exception which
// triggered the rejection of the promise.
static MOZ_MUST_USE bool ResolvePromise(
[[nodiscard]] static bool ResolvePromise(
JSContext* cx, Handle<PromiseObject*> promise, HandleValue valueOrReason,
JS::PromiseState state,
HandleSavedFrame unwrappedRejectionStack = nullptr) {
@ -1311,7 +1312,7 @@ static MOZ_MUST_USE bool ResolvePromise(
}
// ES2016, 25.4.1.7.
static MOZ_MUST_USE bool RejectPromiseInternal(
[[nodiscard]] static bool RejectPromiseInternal(
JSContext* cx, Handle<PromiseObject*> promise, HandleValue reason,
HandleSavedFrame unwrappedRejectionStack) {
return ResolvePromise(cx, promise, reason, JS::PromiseState::Rejected,
@ -1319,9 +1320,9 @@ static MOZ_MUST_USE bool RejectPromiseInternal(
}
// ES2016, 25.4.1.4.
static MOZ_MUST_USE bool FulfillMaybeWrappedPromise(JSContext* cx,
HandleObject promiseObj,
HandleValue value_) {
[[nodiscard]] static bool FulfillMaybeWrappedPromise(JSContext* cx,
HandleObject promiseObj,
HandleValue value_) {
Rooted<PromiseObject*> promise(cx);
RootedValue value(cx, value_);
@ -1347,7 +1348,7 @@ static MOZ_MUST_USE bool FulfillMaybeWrappedPromise(JSContext* cx,
static bool GetCapabilitiesExecutor(JSContext* cx, unsigned argc, Value* vp);
static bool PromiseConstructor(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE PromiseObject* CreatePromiseObjectInternal(
[[nodiscard]] static PromiseObject* CreatePromiseObjectInternal(
JSContext* cx, HandleObject proto = nullptr, bool protoIsWrapped = false,
bool informDebugger = true);
@ -1356,7 +1357,7 @@ enum GetCapabilitiesExecutorSlots {
GetCapabilitiesExecutorSlots_Reject
};
static MOZ_MUST_USE PromiseObject*
[[nodiscard]] static PromiseObject*
CreatePromiseObjectWithoutResolutionFunctions(JSContext* cx) {
PromiseObject* promise = CreatePromiseObjectInternal(cx);
if (!promise) {
@ -1367,7 +1368,7 @@ CreatePromiseObjectWithoutResolutionFunctions(JSContext* cx) {
return promise;
}
static MOZ_MUST_USE PromiseObject* CreatePromiseWithDefaultResolutionFunctions(
[[nodiscard]] static PromiseObject* CreatePromiseWithDefaultResolutionFunctions(
JSContext* cx, MutableHandleObject resolve, MutableHandleObject reject) {
// ES2016, 25.4.3.1., as if called with GetCapabilitiesExecutor as the
// executor argument.
@ -1394,7 +1395,7 @@ static MOZ_MUST_USE PromiseObject* CreatePromiseWithDefaultResolutionFunctions(
}
// ES2016, 25.4.1.5.
static MOZ_MUST_USE bool NewPromiseCapability(
[[nodiscard]] static bool NewPromiseCapability(
JSContext* cx, HandleObject C, MutableHandle<PromiseCapability> capability,
bool canOmitResolutionFunctions) {
RootedValue cVal(cx, ObjectValue(*C));
@ -1509,7 +1510,7 @@ static bool GetCapabilitiesExecutor(JSContext* cx, unsigned argc, Value* vp) {
}
// ES2016, 25.4.1.7.
static MOZ_MUST_USE bool RejectMaybeWrappedPromise(
[[nodiscard]] static bool RejectMaybeWrappedPromise(
JSContext* cx, HandleObject promiseObj, HandleValue reason_,
HandleSavedFrame unwrappedRejectionStack) {
Rooted<PromiseObject*> promise(cx);
@ -1608,10 +1609,10 @@ static bool ForEachReaction(JSContext* cx, HandleValue reactionsVal, F f) {
}
// ES2016, 25.4.1.8.
static MOZ_MUST_USE bool TriggerPromiseReactions(JSContext* cx,
HandleValue reactionsVal,
JS::PromiseState state,
HandleValue valueOrReason) {
[[nodiscard]] static bool TriggerPromiseReactions(JSContext* cx,
HandleValue reactionsVal,
JS::PromiseState state,
HandleValue valueOrReason) {
MOZ_ASSERT(state == JS::PromiseState::Fulfilled ||
state == JS::PromiseState::Rejected);
@ -1620,15 +1621,15 @@ static MOZ_MUST_USE bool TriggerPromiseReactions(JSContext* cx,
});
}
static MOZ_MUST_USE bool RunFulfillFunction(JSContext* cx,
HandleObject onFulfilledFunc,
HandleValue result,
HandleObject promiseObj);
[[nodiscard]] static bool RunFulfillFunction(JSContext* cx,
HandleObject onFulfilledFunc,
HandleValue result,
HandleObject promiseObj);
// Implements PromiseReactionJob optimized for the case when the reaction
// handler is one of the default resolving functions as created by the
// CreateResolvingFunctions abstract operation.
static MOZ_MUST_USE bool DefaultResolvingPromiseReactionJob(
[[nodiscard]] static bool DefaultResolvingPromiseReactionJob(
JSContext* cx, Handle<PromiseReactionRecord*> reaction) {
MOZ_ASSERT(reaction->targetState() != JS::PromiseState::Pending);
@ -1680,7 +1681,7 @@ static MOZ_MUST_USE bool DefaultResolvingPromiseReactionJob(
reaction->unhandledRejectionBehavior());
}
static MOZ_MUST_USE bool AsyncFunctionPromiseReactionJob(
[[nodiscard]] static bool AsyncFunctionPromiseReactionJob(
JSContext* cx, Handle<PromiseReactionRecord*> reaction) {
MOZ_ASSERT(reaction->isAsyncFunction());
@ -1700,7 +1701,7 @@ static MOZ_MUST_USE bool AsyncFunctionPromiseReactionJob(
return AsyncFunctionAwaitedRejected(cx, generator, argument);
}
static MOZ_MUST_USE bool AsyncGeneratorPromiseReactionJob(
[[nodiscard]] static bool AsyncGeneratorPromiseReactionJob(
JSContext* cx, Handle<PromiseReactionRecord*> reaction) {
MOZ_ASSERT(reaction->isAsyncGenerator());
@ -1984,7 +1985,7 @@ static bool PromiseResolveThenableJob(JSContext* cx, unsigned argc, Value* vp) {
return Call(cx, rejectVal, UndefinedHandleValue, rval, &rval);
}
static MOZ_MUST_USE bool OriginalPromiseThenWithoutSettleHandlers(
[[nodiscard]] static bool OriginalPromiseThenWithoutSettleHandlers(
JSContext* cx, Handle<PromiseObject*> promise,
Handle<PromiseObject*> promiseToResolve);
@ -2050,7 +2051,7 @@ static bool PromiseResolveBuiltinThenableJob(JSContext* cx, unsigned argc,
* thenable_ - The thenable to resolve the Promise with.
* thenVal - The `then` function to invoke with the `thenable` as the receiver.
*/
static MOZ_MUST_USE bool EnqueuePromiseResolveThenableJob(
[[nodiscard]] static bool EnqueuePromiseResolveThenableJob(
JSContext* cx, HandleValue promiseToResolve_, HandleValue thenable_,
HandleValue thenVal) {
// Need to re-root these to enable wrapping them below.
@ -2118,7 +2119,7 @@ static MOZ_MUST_USE bool EnqueuePromiseResolveThenableJob(
* promiseToResolve - The promise to resolve, obviously.
* thenable - The thenable to resolve the Promise with.
*/
static MOZ_MUST_USE bool EnqueuePromiseResolveThenableBuiltinJob(
[[nodiscard]] static bool EnqueuePromiseResolveThenableBuiltinJob(
JSContext* cx, HandleObject promiseToResolve, HandleObject thenable) {
cx->check(promiseToResolve, thenable);
MOZ_ASSERT(promiseToResolve->is<PromiseObject>());
@ -2143,11 +2144,11 @@ static MOZ_MUST_USE bool EnqueuePromiseResolveThenableBuiltinJob(
incumbentGlobal);
}
static MOZ_MUST_USE bool AddDummyPromiseReactionForDebugger(
[[nodiscard]] static bool AddDummyPromiseReactionForDebugger(
JSContext* cx, Handle<PromiseObject*> promise,
HandleObject dependentPromise);
static MOZ_MUST_USE bool AddPromiseReaction(
[[nodiscard]] static bool AddPromiseReaction(
JSContext* cx, Handle<PromiseObject*> promise,
Handle<PromiseReactionRecord*> reaction);
@ -2222,7 +2223,7 @@ static void ClearResolutionFunctionSlots(JSFunction* resolutionFun) {
}
// ES2016, 25.4.3.1. steps 3-7.
static MOZ_MUST_USE MOZ_ALWAYS_INLINE PromiseObject*
[[nodiscard]] static MOZ_ALWAYS_INLINE PromiseObject*
CreatePromiseObjectInternal(JSContext* cx, HandleObject proto /* = nullptr */,
bool protoIsWrapped /* = false */,
bool informDebugger /* = true */) {
@ -2484,22 +2485,22 @@ class MOZ_STACK_CLASS PromiseForOfIterator : public JS::ForOfIterator {
}
};
static MOZ_MUST_USE bool PerformPromiseAll(
[[nodiscard]] static bool PerformPromiseAll(
JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
bool* done);
static MOZ_MUST_USE bool PerformPromiseAllSettled(
[[nodiscard]] static bool PerformPromiseAllSettled(
JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
bool* done);
static MOZ_MUST_USE bool PerformPromiseAny(
[[nodiscard]] static bool PerformPromiseAny(
JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
bool* done);
static MOZ_MUST_USE bool PerformPromiseRace(
[[nodiscard]] static bool PerformPromiseRace(
JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
bool* done);
@ -2517,8 +2518,8 @@ enum class CombinatorKind { All, AllSettled, Any, Race };
// https://tc39.es/proposal-promise-any/
//
// Promise.any ( iterable )
static MOZ_MUST_USE bool CommonPromiseCombinator(JSContext* cx, CallArgs& args,
CombinatorKind kind) {
[[nodiscard]] static bool CommonPromiseCombinator(JSContext* cx, CallArgs& args,
CombinatorKind kind) {
HandleValue iterable = args.get(0);
// Step 2 (moved from NewPromiseCapability, step 1).
@ -2651,11 +2652,11 @@ static bool Promise_static_all(JSContext* cx, unsigned argc, Value* vp) {
return CommonPromiseCombinator(cx, args, CombinatorKind::All);
}
static MOZ_MUST_USE bool PerformPromiseThen(
[[nodiscard]] static bool PerformPromiseThen(
JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_,
HandleValue onRejected_, Handle<PromiseCapability> resultCapability);
static MOZ_MUST_USE bool PerformPromiseThenWithoutSettleHandlers(
[[nodiscard]] static bool PerformPromiseThenWithoutSettleHandlers(
JSContext* cx, Handle<PromiseObject*> promise,
Handle<PromiseObject*> promiseToResolve,
Handle<PromiseCapability> resultCapability);
@ -2668,7 +2669,7 @@ static bool PromiseAllResolveElementFunction(JSContext* cx, unsigned argc,
Value* vp);
// Unforgeable version of ES2016, 25.4.4.1.
MOZ_MUST_USE JSObject* js::GetWaitForAllPromise(
[[nodiscard]] JSObject* js::GetWaitForAllPromise(
JSContext* cx, JS::HandleObjectVector promises) {
#ifdef DEBUG
for (size_t i = 0, len = promises.length(); i < len; i++) {
@ -2709,7 +2710,7 @@ MOZ_MUST_USE JSObject* js::GetWaitForAllPromise(
if (!valuesArray) {
return nullptr;
}
valuesArray->ensureDenseInitializedLength(cx, 0, promiseCount);
valuesArray->ensureDenseInitializedLength(0, promiseCount);
values.initialize(valuesArray);
}
@ -2794,10 +2795,10 @@ MOZ_MUST_USE JSObject* js::GetWaitForAllPromise(
return resultCapability.promise();
}
static MOZ_MUST_USE bool RunFulfillFunction(JSContext* cx,
HandleObject onFulfilledFunc,
HandleValue result,
HandleObject promiseObj) {
[[nodiscard]] static bool RunFulfillFunction(JSContext* cx,
HandleObject onFulfilledFunc,
HandleValue result,
HandleObject promiseObj) {
cx->check(onFulfilledFunc);
cx->check(result);
cx->check(promiseObj);
@ -2828,7 +2829,7 @@ static MOZ_MUST_USE bool RunFulfillFunction(JSContext* cx,
return true;
}
static MOZ_MUST_USE bool RunRejectFunction(
[[nodiscard]] static bool RunRejectFunction(
JSContext* cx, HandleObject onRejectedFunc, HandleValue result,
HandleObject promiseObj, HandleSavedFrame unwrappedRejectionStack,
UnhandledRejectionBehavior behavior) {
@ -2877,7 +2878,7 @@ static MOZ_MUST_USE bool RunRejectFunction(
return true;
}
static MOZ_MUST_USE JSObject* CommonStaticResolveRejectImpl(
[[nodiscard]] static JSObject* CommonStaticResolveRejectImpl(
JSContext* cx, HandleValue thisVal, HandleValue argVal,
ResolutionMode mode);
@ -2892,7 +2893,7 @@ static bool IsPromiseSpecies(JSContext* cx, JSFunction* species);
// https://tc39.es/proposal-promise-any/
// Runtime Semantics: PerformPromiseAny, steps 6-8.
template <typename T>
static MOZ_MUST_USE bool CommonPerformPromiseCombinator(
[[nodiscard]] static bool CommonPerformPromiseCombinator(
JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
HandleObject resultPromise, HandleValue promiseResolve, bool* done,
bool resolveReturnsUndefined, T getResolveAndReject) {
@ -3175,7 +3176,7 @@ static MOZ_MUST_USE bool CommonPerformPromiseCombinator(
// Create the elements for the Promise combinators Promise.all and
// Promise.allSettled.
static MOZ_MUST_USE bool NewPromiseCombinatorElements(
[[nodiscard]] static bool NewPromiseCombinatorElements(
JSContext* cx, Handle<PromiseCapability> resultCapability,
MutableHandle<PromiseCombinatorElements> elements) {
// We have to be very careful about which compartments we create things for
@ -3227,7 +3228,7 @@ static MOZ_MUST_USE bool NewPromiseCombinatorElements(
}
// Retrieve the combinator elements from the data holder.
static MOZ_MUST_USE bool GetPromiseCombinatorElements(
[[nodiscard]] static bool GetPromiseCombinatorElements(
JSContext* cx, Handle<PromiseCombinatorDataHolder*> data,
MutableHandle<PromiseCombinatorElements> elements) {
bool needsWrapping = false;
@ -3308,7 +3309,7 @@ static bool PromiseCombinatorElementFunctionAlreadyCalled(
// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
// 25.6.4.1.1 PerformPromiseAll (iteratorRecord, constructor, resultCapability)
static MOZ_MUST_USE bool PerformPromiseAll(
[[nodiscard]] static bool PerformPromiseAll(
JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
bool* done) {
@ -3445,7 +3446,7 @@ static bool Promise_static_race(JSContext* cx, unsigned argc, Value* vp) {
// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
// 25.6.4.3.1 PerformPromiseRace (iteratorRecord, constructor, resultCapability)
static MOZ_MUST_USE bool PerformPromiseRace(
[[nodiscard]] static bool PerformPromiseRace(
JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
bool* done) {
@ -3500,7 +3501,7 @@ static bool Promise_static_allSettled(JSContext* cx, unsigned argc, Value* vp) {
// 25.6.4.2 Promise.allSettled ( iterable )
//
// PerformPromiseAllSettled ( iteratorRecord, constructor, resultCapability )
static MOZ_MUST_USE bool PerformPromiseAllSettled(
[[nodiscard]] static bool PerformPromiseAllSettled(
JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
bool* done) {
@ -3711,7 +3712,7 @@ static void ThrowAggregateError(JSContext* cx,
// https://tc39.es/proposal-promise-any/
//
// PerformPromiseAny ( iteratorRecord, constructor, resultCapability )
static MOZ_MUST_USE bool PerformPromiseAny(
[[nodiscard]] static bool PerformPromiseAny(
JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
bool* done) {
@ -3917,7 +3918,7 @@ static void ThrowAggregateError(JSContext* cx,
// 25.6.4.4 Promise.reject ( r )
// 25.6.4.5 Promise.resolve ( x )
// 25.6.4.5.1 PromiseResolve ( C, x )
static MOZ_MUST_USE JSObject* CommonStaticResolveRejectImpl(
[[nodiscard]] static JSObject* CommonStaticResolveRejectImpl(
JSContext* cx, HandleValue thisVal, HandleValue argVal,
ResolutionMode mode) {
// Steps 1-2 of Promise.reject and Promise.resolve.
@ -3994,9 +3995,9 @@ static MOZ_MUST_USE JSObject* CommonStaticResolveRejectImpl(
return promise;
}
MOZ_MUST_USE JSObject* js::PromiseResolve(JSContext* cx,
HandleObject constructor,
HandleValue value) {
[[nodiscard]] JSObject* js::PromiseResolve(JSContext* cx,
HandleObject constructor,
HandleValue value) {
RootedValue C(cx, ObjectValue(*constructor));
return CommonStaticResolveRejectImpl(cx, C, value, ResolveMode);
}
@ -4284,10 +4285,10 @@ static bool PromiseThenNewPromiseCapability(
}
// ES2016, 25.4.5.3., steps 3-5.
MOZ_MUST_USE PromiseObject* js::OriginalPromiseThen(JSContext* cx,
HandleObject promiseObj,
HandleObject onFulfilled,
HandleObject onRejected) {
[[nodiscard]] PromiseObject* js::OriginalPromiseThen(JSContext* cx,
HandleObject promiseObj,
HandleObject onFulfilled,
HandleObject onRejected) {
cx->check(promiseObj);
cx->check(onFulfilled);
cx->check(onRejected);
@ -4328,7 +4329,7 @@ MOZ_MUST_USE PromiseObject* js::OriginalPromiseThen(JSContext* cx,
return newPromise;
}
static MOZ_MUST_USE bool OriginalPromiseThenWithoutSettleHandlers(
[[nodiscard]] static bool OriginalPromiseThenWithoutSettleHandlers(
JSContext* cx, Handle<PromiseObject*> promise,
Handle<PromiseObject*> promiseToResolve) {
cx->check(promise);
@ -4346,11 +4347,11 @@ static MOZ_MUST_USE bool OriginalPromiseThenWithoutSettleHandlers(
resultCapability);
}
static MOZ_MUST_USE bool PerformPromiseThenWithReaction(
[[nodiscard]] static bool PerformPromiseThenWithReaction(
JSContext* cx, Handle<PromiseObject*> promise,
Handle<PromiseReactionRecord*> reaction);
MOZ_MUST_USE bool js::ReactToUnwrappedPromise(
[[nodiscard]] bool js::ReactToUnwrappedPromise(
JSContext* cx, Handle<PromiseObject*> unwrappedPromise,
HandleObject onFulfilled_, HandleObject onRejected_,
UnhandledRejectionBehavior behavior) {
@ -4430,7 +4431,7 @@ static bool OriginalPromiseThenBuiltin(JSContext* cx, HandleValue promiseVal,
return true;
}
MOZ_MUST_USE bool js::RejectPromiseWithPendingError(
[[nodiscard]] bool js::RejectPromiseWithPendingError(
JSContext* cx, Handle<PromiseObject*> promise) {
cx->check(promise);
@ -4451,7 +4452,7 @@ MOZ_MUST_USE bool js::RejectPromiseWithPendingError(
// js/src/builtin/AsyncFunction.cpp, to call Promise internal functions.
// ES 2018 draft 14.6.11 and 14.7.14 step 1.
MOZ_MUST_USE PromiseObject* js::CreatePromiseObjectForAsync(JSContext* cx) {
[[nodiscard]] PromiseObject* js::CreatePromiseObjectForAsync(JSContext* cx) {
// Step 1.
PromiseObject* promise = CreatePromiseObjectWithoutResolutionFunctions(cx);
if (!promise) {
@ -4467,7 +4468,7 @@ bool js::IsPromiseForAsyncFunctionOrGenerator(JSObject* promise) {
PromiseHasAnyFlag(promise->as<PromiseObject>(), PROMISE_FLAG_ASYNC);
}
static MOZ_MUST_USE PromiseObject* CreatePromiseObjectForAsyncGenerator(
[[nodiscard]] static PromiseObject* CreatePromiseObjectForAsyncGenerator(
JSContext* cx) {
PromiseObject* promise = CreatePromiseObjectWithoutResolutionFunctions(cx);
if (!promise) {
@ -4480,9 +4481,9 @@ static MOZ_MUST_USE PromiseObject* CreatePromiseObjectForAsyncGenerator(
// ES2019 draft rev 7428c89bef626548084cd4e697a19ece7168f24c
// 25.7.5.1 AsyncFunctionStart, steps 3.f-g.
MOZ_MUST_USE bool js::AsyncFunctionThrown(JSContext* cx,
Handle<PromiseObject*> resultPromise,
HandleValue reason) {
[[nodiscard]] bool js::AsyncFunctionThrown(JSContext* cx,
Handle<PromiseObject*> resultPromise,
HandleValue reason) {
if (resultPromise->state() != JS::PromiseState::Pending) {
// OOM after resolving promise.
// Report a warning and ignore the result.
@ -4499,7 +4500,7 @@ MOZ_MUST_USE bool js::AsyncFunctionThrown(JSContext* cx,
// ES2019 draft rev 7428c89bef626548084cd4e697a19ece7168f24c
// 25.7.5.1 AsyncFunctionStart, steps 3.d-e, 3.g.
MOZ_MUST_USE bool js::AsyncFunctionReturned(
[[nodiscard]] bool js::AsyncFunctionReturned(
JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value) {
return ResolvePromiseInternal(cx, resultPromise, value);
}
@ -4509,10 +4510,11 @@ MOZ_MUST_USE bool js::AsyncFunctionReturned(
// Helper function that performs 6.2.3.1 Await(promise) steps 2 and 9.
// The same steps are also used in a few other places in the spec.
template <typename T>
static MOZ_MUST_USE bool InternalAwait(JSContext* cx, HandleValue value,
HandleObject resultPromise,
PromiseHandler onFulfilled,
PromiseHandler onRejected, T extraStep) {
[[nodiscard]] static bool InternalAwait(JSContext* cx, HandleValue value,
HandleObject resultPromise,
PromiseHandler onFulfilled,
PromiseHandler onRejected,
T extraStep) {
// Step 2: Let promise be ? PromiseResolve(%Promise%, « value »).
RootedObject promise(cx, PromiseObject::unforgeableResolve(cx, value));
if (!promise) {
@ -4549,7 +4551,7 @@ static MOZ_MUST_USE bool InternalAwait(JSContext* cx, HandleValue value,
//
// 6.2.3.1 Await(promise) steps 2-10 when the running execution context is
// evaluating an `await` expression in an async function.
MOZ_MUST_USE JSObject* js::AsyncFunctionAwait(
[[nodiscard]] JSObject* js::AsyncFunctionAwait(
JSContext* cx, Handle<AsyncFunctionGeneratorObject*> genObj,
HandleValue value) {
auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
@ -4565,7 +4567,7 @@ MOZ_MUST_USE JSObject* js::AsyncFunctionAwait(
// 6.2.3.1 Await(promise) steps 2-10 when the running execution context is
// evaluating an `await` expression in an async generator.
MOZ_MUST_USE bool js::AsyncGeneratorAwait(
[[nodiscard]] bool js::AsyncGeneratorAwait(
JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue value) {
auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
@ -4785,12 +4787,12 @@ bool js::AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args,
enum class ResumeNextKind { Enqueue, Reject, Resolve };
static MOZ_MUST_USE bool AsyncGeneratorResumeNext(
[[nodiscard]] static bool AsyncGeneratorResumeNext(
JSContext* cx, Handle<AsyncGeneratorObject*> generator, ResumeNextKind kind,
HandleValue valueOrException = UndefinedHandleValue, bool done = false);
// 25.5.3.3 AsyncGeneratorResolve ( generator, value, done )
MOZ_MUST_USE bool js::AsyncGeneratorResolve(
[[nodiscard]] bool js::AsyncGeneratorResolve(
JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, HandleValue value,
bool done) {
return AsyncGeneratorResumeNext(cx, asyncGenObj, ResumeNextKind::Resolve,
@ -4798,7 +4800,7 @@ MOZ_MUST_USE bool js::AsyncGeneratorResolve(
}
// 25.5.3.4 AsyncGeneratorReject ( generator, exception )
MOZ_MUST_USE bool js::AsyncGeneratorReject(
[[nodiscard]] bool js::AsyncGeneratorReject(
JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue exception) {
return AsyncGeneratorResumeNext(cx, asyncGenObj, ResumeNextKind::Reject,
@ -4809,7 +4811,7 @@ MOZ_MUST_USE bool js::AsyncGeneratorReject(
// 25.5.3.3 AsyncGeneratorResolve ( generator, value, done )
// 25.5.3.4 AsyncGeneratorReject ( generator, exception )
// 25.5.3.5 AsyncGeneratorResumeNext ( generator )
static MOZ_MUST_USE bool AsyncGeneratorResumeNext(
[[nodiscard]] static bool AsyncGeneratorResumeNext(
JSContext* cx, Handle<AsyncGeneratorObject*> generator, ResumeNextKind kind,
HandleValue valueOrException_ /* = UndefinedHandleValue */,
bool done /* = false */) {
@ -5033,11 +5035,11 @@ static MOZ_MUST_USE bool AsyncGeneratorResumeNext(
}
// 25.5.3.6 AsyncGeneratorEnqueue ( generator, completion )
MOZ_MUST_USE bool js::AsyncGeneratorEnqueue(JSContext* cx,
HandleValue asyncGenVal,
CompletionKind completionKind,
HandleValue completionValue,
MutableHandleValue result) {
[[nodiscard]] bool js::AsyncGeneratorEnqueue(JSContext* cx,
HandleValue asyncGenVal,
CompletionKind completionKind,
HandleValue completionValue,
MutableHandleValue result) {
// Step 1 (implicit).
// Step 3.
@ -5264,7 +5266,7 @@ bool js::Promise_then(JSContext* cx, unsigned argc, Value* vp) {
}
// ES2016, 25.4.5.3.1.
static MOZ_MUST_USE bool PerformPromiseThen(
[[nodiscard]] static bool PerformPromiseThen(
JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_,
HandleValue onRejected_, Handle<PromiseCapability> resultCapability) {
// Step 1 (implicit).
@ -5293,7 +5295,7 @@ static MOZ_MUST_USE bool PerformPromiseThen(
return PerformPromiseThenWithReaction(cx, promise, reaction);
}
static MOZ_MUST_USE bool PerformPromiseThenWithoutSettleHandlers(
[[nodiscard]] static bool PerformPromiseThenWithoutSettleHandlers(
JSContext* cx, Handle<PromiseObject*> promise,
Handle<PromiseObject*> promiseToResolve,
Handle<PromiseCapability> resultCapability) {
@ -5321,7 +5323,7 @@ static MOZ_MUST_USE bool PerformPromiseThenWithoutSettleHandlers(
// https://tc39.github.io/ecma262/#sec-performpromisethen
// 25.6.5.4.1 PerformPromiseThen steps 8-11.
static MOZ_MUST_USE bool PerformPromiseThenWithReaction(
[[nodiscard]] static bool PerformPromiseThenWithReaction(
JSContext* cx, Handle<PromiseObject*> unwrappedPromise,
Handle<PromiseReactionRecord*> reaction) {
// Step 8: If promise.[[PromiseState]] is "pending", then
@ -5380,7 +5382,7 @@ static MOZ_MUST_USE bool PerformPromiseThenWithReaction(
return true;
}
static MOZ_MUST_USE bool AddPromiseReaction(
[[nodiscard]] static bool AddPromiseReaction(
JSContext* cx, Handle<PromiseObject*> unwrappedPromise,
Handle<PromiseReactionRecord*> reaction) {
MOZ_RELEASE_ASSERT(reaction->is<PromiseReactionRecord>());
@ -5454,7 +5456,7 @@ static MOZ_MUST_USE bool AddPromiseReaction(
return true;
}
static MOZ_MUST_USE bool AddDummyPromiseReactionForDebugger(
[[nodiscard]] static bool AddDummyPromiseReactionForDebugger(
JSContext* cx, Handle<PromiseObject*> promise,
HandleObject dependentPromise) {
if (promise->state() != JS::PromiseState::Pending) {
@ -5693,14 +5695,20 @@ void PromiseObject::copyUserInteractionFlagsFrom(PromiseObject& rhs) {
//
// Currently we only support skipping jobs when the async function is resumed
// at least once.
static MOZ_MUST_USE bool IsTopMostAsyncFunctionCall(JSContext* cx) {
[[nodiscard]] static bool IsTopMostAsyncFunctionCall(JSContext* cx) {
FrameIter iter(cx);
// The current frame should be the async function.
if (iter.done()) {
return false;
}
MOZ_ASSERT(iter.isFunctionFrame());
if (!iter.isFunctionFrame() && iter.isModuleFrame()) {
// The iterator is not a function frame, it is a module frame.
// Ignore this optimization for now.
return true;
}
MOZ_ASSERT(iter.calleeTemplate()->isAsync());
#ifdef DEBUG
@ -5752,8 +5760,8 @@ static MOZ_MUST_USE bool IsTopMostAsyncFunctionCall(JSContext* cx) {
return false;
}
MOZ_MUST_USE bool js::TrySkipAwait(JSContext* cx, HandleValue val,
bool* canSkip, MutableHandleValue resolved) {
[[nodiscard]] bool js::CanSkipAwait(JSContext* cx, HandleValue val,
bool* canSkip) {
if (!cx->canSkipEnqueuingJobs) {
*canSkip = false;
return true;
@ -5767,7 +5775,6 @@ MOZ_MUST_USE bool js::TrySkipAwait(JSContext* cx, HandleValue val,
// Primitive values cannot be 'thenables', so we can trivially skip the
// await operation.
if (!val.isObject()) {
resolved.set(val);
*canSkip = true;
return true;
}
@ -5797,11 +5804,36 @@ MOZ_MUST_USE bool js::TrySkipAwait(JSContext* cx, HandleValue val,
return true;
}
resolved.set(promise->value());
*canSkip = true;
return true;
}
[[nodiscard]] bool js::ExtractAwaitValue(JSContext* cx, HandleValue val,
MutableHandleValue resolved) {
// Ensure all callers of this are jumping past the
// extract if it's not possible to extract.
#ifdef DEBUG
bool canSkip;
if (!CanSkipAwait(cx, val, &canSkip)) {
return false;
}
MOZ_ASSERT(canSkip == true);
#endif
// Primitive values cannot be 'thenables', so we can trivially skip the
// await operation.
if (!val.isObject()) {
resolved.set(val);
return true;
}
JSObject* obj = &val.toObject();
PromiseObject* promise = &obj->as<PromiseObject>();
resolved.set(promise->value());
return true;
}
JS::AutoDebuggerJobQueueInterruption::AutoDebuggerJobQueueInterruption()
: cx(nullptr) {}

View File

@ -7,8 +7,6 @@
#include "js/Promise.h"
#include "mozilla/Attributes.h" // MOZ_MUST_USE
#include "jsapi.h" // js::CompletionKind
#include "jstypes.h" // JS_PUBLIC_API
@ -46,15 +44,15 @@ extern bool Promise_static_resolve(JSContext* cx, unsigned argc, JS::Value* vp);
* Asserts that all objects in the `promises` vector are, maybe wrapped,
* instances of `Promise` or a subclass of `Promise`.
*/
MOZ_MUST_USE JSObject* GetWaitForAllPromise(JSContext* cx,
JS::HandleObjectVector promises);
[[nodiscard]] JSObject* GetWaitForAllPromise(JSContext* cx,
JS::HandleObjectVector promises);
/**
* Enqueues resolve/reject reactions in the given Promise's reactions lists
* as though by calling the original value of Promise.prototype.then, and
* without regard to any Promise subclassing used in `promiseObj` itself.
*/
MOZ_MUST_USE PromiseObject* OriginalPromiseThen(
[[nodiscard]] PromiseObject* OriginalPromiseThen(
JSContext* cx, JS::Handle<JSObject*> promiseObj,
JS::Handle<JSObject*> onFulfilled, JS::Handle<JSObject*> onRejected);
@ -82,7 +80,7 @@ enum class UnhandledRejectionBehavior { Ignore, Report };
* 0. The sense of "react" here is the sense of the term as defined by Web IDL:
* https://heycam.github.io/webidl/#dfn-perform-steps-once-promise-is-settled
*/
extern MOZ_MUST_USE bool ReactToUnwrappedPromise(
[[nodiscard]] extern bool ReactToUnwrappedPromise(
JSContext* cx, JS::Handle<PromiseObject*> unwrappedPromise,
JS::Handle<JSObject*> onFulfilled_, JS::Handle<JSObject*> onRejected_,
UnhandledRejectionBehavior behavior);
@ -93,9 +91,9 @@ extern MOZ_MUST_USE bool ReactToUnwrappedPromise(
* The abstract operation PromiseResolve, given a constructor and a value,
* returns a new promise resolved with that value.
*/
MOZ_MUST_USE JSObject* PromiseResolve(JSContext* cx,
JS::Handle<JSObject*> constructor,
JS::Handle<JS::Value> value);
[[nodiscard]] JSObject* PromiseResolve(JSContext* cx,
JS::Handle<JSObject*> constructor,
JS::Handle<JS::Value> value);
/**
* Reject |promise| with the value of the current pending exception.
@ -103,59 +101,60 @@ MOZ_MUST_USE JSObject* PromiseResolve(JSContext* cx,
* |promise| must be from the current realm. Callers must enter the realm of
* |promise| if they are not already in it.
*/
MOZ_MUST_USE bool RejectPromiseWithPendingError(
[[nodiscard]] bool RejectPromiseWithPendingError(
JSContext* cx, JS::Handle<PromiseObject*> promise);
/**
* Create the promise object which will be used as the return value of an async
* function.
*/
MOZ_MUST_USE PromiseObject* CreatePromiseObjectForAsync(JSContext* cx);
[[nodiscard]] PromiseObject* CreatePromiseObjectForAsync(JSContext* cx);
/**
* Returns true if the given object is a promise created by
* either CreatePromiseObjectForAsync function or async generator's method.
*/
MOZ_MUST_USE bool IsPromiseForAsyncFunctionOrGenerator(JSObject* promise);
[[nodiscard]] bool IsPromiseForAsyncFunctionOrGenerator(JSObject* promise);
MOZ_MUST_USE bool AsyncFunctionReturned(
[[nodiscard]] bool AsyncFunctionReturned(
JSContext* cx, JS::Handle<PromiseObject*> resultPromise,
JS::Handle<JS::Value> value);
MOZ_MUST_USE bool AsyncFunctionThrown(JSContext* cx,
JS::Handle<PromiseObject*> resultPromise,
JS::Handle<JS::Value> reason);
[[nodiscard]] bool AsyncFunctionThrown(JSContext* cx,
JS::Handle<PromiseObject*> resultPromise,
JS::Handle<JS::Value> reason);
// Start awaiting `value` in an async function (, but doesn't suspend the
// async function's execution!). Returns the async function's result promise.
MOZ_MUST_USE JSObject* AsyncFunctionAwait(
[[nodiscard]] JSObject* AsyncFunctionAwait(
JSContext* cx, JS::Handle<AsyncFunctionGeneratorObject*> genObj,
JS::Handle<JS::Value> value);
// If the await operation can be skipped and the resolution value for `val` can
// be acquired, stored the resolved value to `resolved` and `true` to
// `*canSkip`. Otherwise, stores `false` to `*canSkip`.
MOZ_MUST_USE bool TrySkipAwait(JSContext* cx, JS::Handle<JS::Value> val,
bool* canSkip,
JS::MutableHandle<JS::Value> resolved);
[[nodiscard]] bool CanSkipAwait(JSContext* cx, JS::Handle<JS::Value> val,
bool* canSkip);
[[nodiscard]] bool ExtractAwaitValue(JSContext* cx, JS::Handle<JS::Value> val,
JS::MutableHandle<JS::Value> resolved);
MOZ_MUST_USE bool AsyncGeneratorAwait(
[[nodiscard]] bool AsyncGeneratorAwait(
JSContext* cx, JS::Handle<AsyncGeneratorObject*> asyncGenObj,
JS::Handle<JS::Value> value);
MOZ_MUST_USE bool AsyncGeneratorResolve(
[[nodiscard]] bool AsyncGeneratorResolve(
JSContext* cx, JS::Handle<AsyncGeneratorObject*> asyncGenObj,
JS::Handle<JS::Value> value, bool done);
MOZ_MUST_USE bool AsyncGeneratorReject(
[[nodiscard]] bool AsyncGeneratorReject(
JSContext* cx, JS::Handle<AsyncGeneratorObject*> asyncGenObj,
JS::Handle<JS::Value> exception);
MOZ_MUST_USE bool AsyncGeneratorEnqueue(JSContext* cx,
JS::Handle<JS::Value> asyncGenVal,
CompletionKind completionKind,
JS::Handle<JS::Value> completionValue,
JS::MutableHandle<JS::Value> result);
[[nodiscard]] bool AsyncGeneratorEnqueue(JSContext* cx,
JS::Handle<JS::Value> asyncGenVal,
CompletionKind completionKind,
JS::Handle<JS::Value> completionValue,
JS::MutableHandle<JS::Value> result);
bool AsyncFromSyncIteratorMethod(JSContext* cx, JS::CallArgs& args,
CompletionKind completionKind);
@ -175,9 +174,9 @@ struct PromiseReactionRecordBuilder {
// Some reaction records refer to internal resolution or rejection functions
// that are not naturally represented as debuggee JavaScript functions. In
// this case, resolve and reject may be nullptr.
virtual MOZ_MUST_USE bool then(JSContext* cx, JS::Handle<JSObject*> resolve,
JS::Handle<JSObject*> reject,
JS::Handle<JSObject*> result) = 0;
[[nodiscard]] virtual bool then(JSContext* cx, JS::Handle<JSObject*> resolve,
JS::Handle<JSObject*> reject,
JS::Handle<JSObject*> result) = 0;
// A reaction record created when one native promise is resolved to another.
// The 'promise' argument is the promise that will be settled in the same way
@ -185,7 +184,7 @@ struct PromiseReactionRecordBuilder {
//
// Note that promise may not be same-compartment with cx. This function
// presents the promise exactly as it appears in the reaction record.
virtual MOZ_MUST_USE bool direct(
[[nodiscard]] virtual bool direct(
JSContext* cx, JS::Handle<PromiseObject*> unwrappedPromise) = 0;
// A reaction record that resumes an asynchronous function suspended at an
@ -194,7 +193,7 @@ struct PromiseReactionRecordBuilder {
//
// Note that generator may not be same-compartment with cx. This function
// presents the generator exactly as it appears in the reaction record.
virtual MOZ_MUST_USE bool asyncFunction(
[[nodiscard]] virtual bool asyncFunction(
JSContext* cx,
JS::Handle<AsyncFunctionGeneratorObject*> unwrappedGenerator) = 0;
@ -204,7 +203,7 @@ struct PromiseReactionRecordBuilder {
//
// Note that generator may not be same-compartment with cx. This function
// presents the generator exactly as it appears in the reaction record.
virtual MOZ_MUST_USE bool asyncGenerator(
[[nodiscard]] virtual bool asyncGenerator(
JSContext* cx, JS::Handle<AsyncGeneratorObject*> unwrappedGenerator) = 0;
};

View File

@ -43,7 +43,7 @@ static bool Reflect_deleteProperty(JSContext* cx, unsigned argc, Value* vp) {
if (!DeleteProperty(cx, target, key, result)) {
return false;
}
args.rval().setBoolean(result.reallyOk());
args.rval().setBoolean(result.ok());
return true;
}
@ -123,7 +123,7 @@ static bool Reflect_preventExtensions(JSContext* cx, unsigned argc, Value* vp) {
if (!PreventExtensions(cx, target, result)) {
return false;
}
args.rval().setBoolean(result.reallyOk());
args.rval().setBoolean(result.ok());
return true;
}
@ -154,7 +154,7 @@ static bool Reflect_set(JSContext* cx, unsigned argc, Value* vp) {
if (!SetProperty(cx, target, key, value, receiver, result)) {
return false;
}
args.rval().setBoolean(result.reallyOk());
args.rval().setBoolean(result.ok());
return true;
}
@ -189,7 +189,7 @@ static bool Reflect_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp) {
if (!SetPrototype(cx, obj, proto, result)) {
return false;
}
args.rval().setBoolean(result.reallyOk());
args.rval().setBoolean(result.ok());
return true;
}
@ -211,6 +211,9 @@ static const JSFunctionSpec reflect_methods[] = {
JS_FN("setPrototypeOf", Reflect_setPrototypeOf, 2, 0),
JS_FS_END};
static const JSPropertySpec reflect_properties[] = {
JS_STRING_SYM_PS(toStringTag, "Reflect", JSPROP_READONLY), JS_PS_END};
/*** Setup ******************************************************************/
static JSObject* CreateReflectObject(JSContext* cx, JSProtoKey key) {
@ -219,11 +222,11 @@ static JSObject* CreateReflectObject(JSContext* cx, JSProtoKey key) {
if (!proto) {
return nullptr;
}
return NewSingletonObjectWithGivenProto<PlainObject>(cx, proto);
return NewTenuredObjectWithGivenProto<PlainObject>(cx, proto);
}
static const ClassSpec ReflectClassSpec = {CreateReflectObject, nullptr,
reflect_methods, nullptr};
reflect_methods, reflect_properties};
const JSClass js::ReflectClass = {"Reflect", 0, JS_NULL_CLASS_OPS,
&ReflectClassSpec};

View File

@ -15,14 +15,14 @@ extern const JSClass ReflectClass;
namespace js {
extern MOZ_MUST_USE bool Reflect_getPrototypeOf(JSContext* cx, unsigned argc,
Value* vp);
[[nodiscard]] extern bool Reflect_getPrototypeOf(JSContext* cx, unsigned argc,
Value* vp);
extern MOZ_MUST_USE bool Reflect_isExtensible(JSContext* cx, unsigned argc,
Value* vp);
[[nodiscard]] extern bool Reflect_isExtensible(JSContext* cx, unsigned argc,
Value* vp);
extern MOZ_MUST_USE bool Reflect_ownKeys(JSContext* cx, unsigned argc,
Value* vp);
[[nodiscard]] extern bool Reflect_ownKeys(JSContext* cx, unsigned argc,
Value* vp);
} // namespace js

View File

@ -14,7 +14,7 @@
#include "builtin/Array.h"
#include "builtin/Reflect.h"
#include "frontend/CompilationInfo.h"
#include "frontend/CompilationStencil.h"
#include "frontend/ModuleSharedContext.h"
#include "frontend/ParseNode.h"
#include "frontend/Parser.h"
@ -289,7 +289,7 @@ class NodeBuilder {
callbacks(cx),
userv(c) {}
MOZ_MUST_USE bool init(HandleObject userobj = nullptr) {
[[nodiscard]] bool init(HandleObject userobj = nullptr) {
if (src) {
if (!atomValue(src, &srcval)) {
return false;
@ -343,9 +343,9 @@ class NodeBuilder {
}
private:
MOZ_MUST_USE bool callbackHelper(HandleValue fun, const InvokeArgs& args,
size_t i, TokenPos* pos,
MutableHandleValue dst) {
[[nodiscard]] bool callbackHelper(HandleValue fun, const InvokeArgs& args,
size_t i, TokenPos* pos,
MutableHandleValue dst) {
// The end of the implementation of callback(). All arguments except
// loc have already been stored in range [0, i).
if (saveLoc) {
@ -361,9 +361,9 @@ class NodeBuilder {
// that convert to HandleValue, so this isn't as template-y as it seems,
// just variadic.
template <typename... Arguments>
MOZ_MUST_USE bool callbackHelper(HandleValue fun, const InvokeArgs& args,
size_t i, HandleValue head,
Arguments&&... tail) {
[[nodiscard]] bool callbackHelper(HandleValue fun, const InvokeArgs& args,
size_t i, HandleValue head,
Arguments&&... tail) {
// Recursive loop to store the arguments into args. This eventually
// bottoms out in a call to the non-template callbackHelper() above.
args[i].set(head);
@ -375,7 +375,7 @@ class NodeBuilder {
// bool callback(HandleValue fun, HandleValue... args, TokenPos* pos,
// MutableHandleValue dst);
template <typename... Arguments>
MOZ_MUST_USE bool callback(HandleValue fun, Arguments&&... args) {
[[nodiscard]] bool callback(HandleValue fun, Arguments&&... args) {
InvokeArgs iargs(cx);
if (!iargs.init(cx, sizeof...(args) - 2 + size_t(saveLoc))) {
return false;
@ -393,7 +393,7 @@ class NodeBuilder {
return v.isMagic(JS_SERIALIZE_NO_NODE) ? JS::UndefinedHandleValue : v;
}
MOZ_MUST_USE bool atomValue(const char* s, MutableHandleValue dst) {
[[nodiscard]] bool atomValue(const char* s, MutableHandleValue dst) {
/*
* Bug 575416: instead of Atomize, lookup constant atoms in tbl file
*/
@ -406,7 +406,7 @@ class NodeBuilder {
return true;
}
MOZ_MUST_USE bool newObject(MutableHandleObject dst) {
[[nodiscard]] bool newObject(MutableHandleObject dst) {
RootedPlainObject nobj(cx, NewBuiltinClassInstance<PlainObject>(cx));
if (!nobj) {
return false;
@ -416,12 +416,12 @@ class NodeBuilder {
return true;
}
MOZ_MUST_USE bool newArray(NodeVector& elts, MutableHandleValue dst);
[[nodiscard]] bool newArray(NodeVector& elts, MutableHandleValue dst);
MOZ_MUST_USE bool createNode(ASTType type, TokenPos* pos,
MutableHandleObject dst);
[[nodiscard]] bool createNode(ASTType type, TokenPos* pos,
MutableHandleObject dst);
MOZ_MUST_USE bool newNodeHelper(HandleObject obj, MutableHandleValue dst) {
[[nodiscard]] bool newNodeHelper(HandleObject obj, MutableHandleValue dst) {
// The end of the implementation of newNode().
MOZ_ASSERT(obj);
dst.setObject(*obj);
@ -429,8 +429,8 @@ class NodeBuilder {
}
template <typename... Arguments>
MOZ_MUST_USE bool newNodeHelper(HandleObject obj, const char* name,
HandleValue value, Arguments&&... rest) {
[[nodiscard]] bool newNodeHelper(HandleObject obj, const char* name,
HandleValue value, Arguments&&... rest) {
// Recursive loop to define properties. Note that the newNodeHelper()
// call below passes two fewer arguments than we received, as we omit
// `name` and `value`. This eventually bottoms out in a call to the
@ -447,15 +447,15 @@ class NodeBuilder {
// {const char *name0, HandleValue value0,}...
// MutableHandleValue dst);
template <typename... Arguments>
MOZ_MUST_USE bool newNode(ASTType type, TokenPos* pos, Arguments&&... args) {
[[nodiscard]] bool newNode(ASTType type, TokenPos* pos, Arguments&&... args) {
RootedObject node(cx);
return createNode(type, pos, &node) &&
newNodeHelper(node, std::forward<Arguments>(args)...);
}
MOZ_MUST_USE bool listNode(ASTType type, const char* propName,
NodeVector& elts, TokenPos* pos,
MutableHandleValue dst) {
[[nodiscard]] bool listNode(ASTType type, const char* propName,
NodeVector& elts, TokenPos* pos,
MutableHandleValue dst) {
RootedValue array(cx);
if (!newArray(elts, &array)) {
return false;
@ -469,8 +469,8 @@ class NodeBuilder {
return newNode(type, pos, propName, array, dst);
}
MOZ_MUST_USE bool defineProperty(HandleObject obj, const char* name,
HandleValue val) {
[[nodiscard]] bool defineProperty(HandleObject obj, const char* name,
HandleValue val) {
MOZ_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
/*
@ -488,9 +488,9 @@ class NodeBuilder {
return DefineDataProperty(cx, obj, atom->asPropertyName(), optVal);
}
MOZ_MUST_USE bool newNodeLoc(TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool newNodeLoc(TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool setNodeLoc(HandleObject node, TokenPos* pos);
[[nodiscard]] bool setNodeLoc(HandleObject node, TokenPos* pos);
public:
/*
@ -506,228 +506,239 @@ class NodeBuilder {
* misc nodes
*/
MOZ_MUST_USE bool program(NodeVector& elts, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool program(NodeVector& elts, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool literal(HandleValue val, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool literal(HandleValue val, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool identifier(HandleValue name, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool identifier(HandleValue name, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool function(ASTType type, TokenPos* pos, HandleValue id,
NodeVector& args, NodeVector& defaults,
HandleValue body, HandleValue rest,
GeneratorStyle generatorStyle, bool isAsync,
bool isExpression, MutableHandleValue dst);
[[nodiscard]] bool function(ASTType type, TokenPos* pos, HandleValue id,
NodeVector& args, NodeVector& defaults,
HandleValue body, HandleValue rest,
GeneratorStyle generatorStyle, bool isAsync,
bool isExpression, MutableHandleValue dst);
MOZ_MUST_USE bool variableDeclarator(HandleValue id, HandleValue init,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool variableDeclarator(HandleValue id, HandleValue init,
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool switchCase(HandleValue expr, NodeVector& elts,
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool catchClause(HandleValue var, HandleValue body,
[[nodiscard]] bool switchCase(HandleValue expr, NodeVector& elts,
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool prototypeMutation(HandleValue val, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool propertyInitializer(HandleValue key, HandleValue val,
PropKind kind, bool isShorthand,
bool isMethod, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool catchClause(HandleValue var, HandleValue body,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool prototypeMutation(HandleValue val, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool propertyInitializer(HandleValue key, HandleValue val,
PropKind kind, bool isShorthand,
bool isMethod, TokenPos* pos,
MutableHandleValue dst);
/*
* statements
*/
MOZ_MUST_USE bool blockStatement(NodeVector& elts, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool expressionStatement(HandleValue expr, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool emptyStatement(TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool ifStatement(HandleValue test, HandleValue cons,
HandleValue alt, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool breakStatement(HandleValue label, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool continueStatement(HandleValue label, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool labeledStatement(HandleValue label, HandleValue stmt,
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool throwStatement(HandleValue arg, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool returnStatement(HandleValue arg, TokenPos* pos,
[[nodiscard]] bool blockStatement(NodeVector& elts, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool forStatement(HandleValue init, HandleValue test,
HandleValue update, HandleValue stmt,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool expressionStatement(HandleValue expr, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool forInStatement(HandleValue var, HandleValue expr,
HandleValue stmt, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool emptyStatement(TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool forOfStatement(HandleValue var, HandleValue expr,
HandleValue stmt, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool withStatement(HandleValue expr, HandleValue stmt,
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool whileStatement(HandleValue test, HandleValue stmt,
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool doWhileStatement(HandleValue stmt, HandleValue test,
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool switchStatement(HandleValue disc, NodeVector& elts,
bool lexical, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool tryStatement(HandleValue body, HandleValue handler,
HandleValue finally, TokenPos* pos,
[[nodiscard]] bool ifStatement(HandleValue test, HandleValue cons,
HandleValue alt, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool debuggerStatement(TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool breakStatement(HandleValue label, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool importDeclaration(NodeVector& elts, HandleValue moduleSpec,
[[nodiscard]] bool continueStatement(HandleValue label, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool labeledStatement(HandleValue label, HandleValue stmt,
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool importSpecifier(HandleValue importName,
HandleValue bindingName, TokenPos* pos,
[[nodiscard]] bool throwStatement(HandleValue arg, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool exportDeclaration(HandleValue decl, NodeVector& elts,
HandleValue moduleSpec,
HandleValue isDefault, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool returnStatement(HandleValue arg, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool exportSpecifier(HandleValue bindingName,
HandleValue exportName, TokenPos* pos,
[[nodiscard]] bool forStatement(HandleValue init, HandleValue test,
HandleValue update, HandleValue stmt,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool forInStatement(HandleValue var, HandleValue expr,
HandleValue stmt, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool exportBatchSpecifier(TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool forOfStatement(HandleValue var, HandleValue expr,
HandleValue stmt, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool classDefinition(bool expr, HandleValue name,
HandleValue heritage, HandleValue block,
[[nodiscard]] bool withStatement(HandleValue expr, HandleValue stmt,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool whileStatement(HandleValue test, HandleValue stmt,
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool classMembers(NodeVector& members, MutableHandleValue dst);
MOZ_MUST_USE bool classMethod(HandleValue name, HandleValue body,
PropKind kind, bool isStatic, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool classField(HandleValue name, HandleValue initializer,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool doWhileStatement(HandleValue stmt, HandleValue test,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool switchStatement(HandleValue disc, NodeVector& elts,
bool lexical, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool tryStatement(HandleValue body, HandleValue handler,
HandleValue finally, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool debuggerStatement(TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool importDeclaration(NodeVector& elts, HandleValue moduleSpec,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool importSpecifier(HandleValue importName,
HandleValue bindingName, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool importNamespaceSpecifier(HandleValue bindingName,
TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool exportDeclaration(HandleValue decl, NodeVector& elts,
HandleValue moduleSpec,
HandleValue isDefault, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool exportSpecifier(HandleValue bindingName,
HandleValue exportName, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool exportNamespaceSpecifier(HandleValue exportName,
TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool exportBatchSpecifier(TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool classDefinition(bool expr, HandleValue name,
HandleValue heritage, HandleValue block,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool classMembers(NodeVector& members, MutableHandleValue dst);
[[nodiscard]] bool classMethod(HandleValue name, HandleValue body,
PropKind kind, bool isStatic, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool classField(HandleValue name, HandleValue initializer,
TokenPos* pos, MutableHandleValue dst);
/*
* expressions
*/
MOZ_MUST_USE bool binaryExpression(BinaryOperator op, HandleValue left,
HandleValue right, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool unaryExpression(UnaryOperator op, HandleValue expr,
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool assignmentExpression(AssignmentOperator op, HandleValue lhs,
HandleValue rhs, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool updateExpression(HandleValue expr, bool incr, bool prefix,
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool logicalExpression(ParseNodeKind pnk, HandleValue left,
[[nodiscard]] bool binaryExpression(BinaryOperator op, HandleValue left,
HandleValue right, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool conditionalExpression(HandleValue test, HandleValue cons,
HandleValue alt, TokenPos* pos,
[[nodiscard]] bool unaryExpression(UnaryOperator op, HandleValue expr,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool assignmentExpression(AssignmentOperator op,
HandleValue lhs, HandleValue rhs,
TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool sequenceExpression(NodeVector& elts, TokenPos* pos,
[[nodiscard]] bool updateExpression(HandleValue expr, bool incr, bool prefix,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool logicalExpression(ParseNodeKind pnk, HandleValue left,
HandleValue right, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool newExpression(HandleValue callee, NodeVector& args,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool conditionalExpression(HandleValue test, HandleValue cons,
HandleValue alt, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool callExpression(HandleValue callee, NodeVector& args,
TokenPos* pos, MutableHandleValue dst,
bool isOptional = false);
[[nodiscard]] bool sequenceExpression(NodeVector& elts, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool memberExpression(bool computed, HandleValue expr,
HandleValue member, TokenPos* pos,
MutableHandleValue dst,
bool isOptional = false);
MOZ_MUST_USE bool arrayExpression(NodeVector& elts, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool templateLiteral(NodeVector& elts, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool taggedTemplate(HandleValue callee, NodeVector& args,
[[nodiscard]] bool newExpression(HandleValue callee, NodeVector& args,
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool callSiteObj(NodeVector& raw, NodeVector& cooked,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool callExpression(HandleValue callee, NodeVector& args,
TokenPos* pos, MutableHandleValue dst,
bool isOptional = false);
MOZ_MUST_USE bool spreadExpression(HandleValue expr, TokenPos* pos,
[[nodiscard]] bool memberExpression(bool computed, HandleValue expr,
HandleValue member, TokenPos* pos,
MutableHandleValue dst,
bool isOptional = false);
[[nodiscard]] bool arrayExpression(NodeVector& elts, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool optionalExpression(HandleValue expr, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool deleteOptionalExpression(HandleValue expr, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool computedName(HandleValue name, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool objectExpression(NodeVector& elts, TokenPos* pos,
[[nodiscard]] bool templateLiteral(NodeVector& elts, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool thisExpression(TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool yieldExpression(HandleValue arg, YieldKind kind,
[[nodiscard]] bool taggedTemplate(HandleValue callee, NodeVector& args,
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool metaProperty(HandleValue meta, HandleValue property,
[[nodiscard]] bool callSiteObj(NodeVector& raw, NodeVector& cooked,
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool callImportExpression(HandleValue ident, HandleValue arg,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool spreadExpression(HandleValue expr, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool super(TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool optionalExpression(HandleValue expr, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool deleteOptionalExpression(HandleValue expr, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool computedName(HandleValue name, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool objectExpression(NodeVector& elts, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool thisExpression(TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool yieldExpression(HandleValue arg, YieldKind kind,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool metaProperty(HandleValue meta, HandleValue property,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool callImportExpression(HandleValue ident, HandleValue arg,
TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool super(TokenPos* pos, MutableHandleValue dst);
/*
* declarations
*/
MOZ_MUST_USE bool variableDeclaration(NodeVector& elts, VarDeclKind kind,
TokenPos* pos, MutableHandleValue dst);
[[nodiscard]] bool variableDeclaration(NodeVector& elts, VarDeclKind kind,
TokenPos* pos, MutableHandleValue dst);
/*
* patterns
*/
MOZ_MUST_USE bool arrayPattern(NodeVector& elts, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool objectPattern(NodeVector& elts, TokenPos* pos,
[[nodiscard]] bool arrayPattern(NodeVector& elts, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool propertyPattern(HandleValue key, HandleValue patt,
bool isShorthand, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool objectPattern(NodeVector& elts, TokenPos* pos,
MutableHandleValue dst);
[[nodiscard]] bool propertyPattern(HandleValue key, HandleValue patt,
bool isShorthand, TokenPos* pos,
MutableHandleValue dst);
};
} /* anonymous namespace */
@ -1393,6 +1404,17 @@ bool NodeBuilder::importSpecifier(HandleValue importName,
dst);
}
bool NodeBuilder::importNamespaceSpecifier(HandleValue bindingName,
TokenPos* pos,
MutableHandleValue dst) {
RootedValue cb(cx, callbacks[AST_IMPORT_NAMESPACE_SPEC]);
if (!cb.isNull()) {
return callback(cb, bindingName, pos, dst);
}
return newNode(AST_IMPORT_NAMESPACE_SPEC, pos, "name", bindingName, dst);
}
bool NodeBuilder::exportDeclaration(HandleValue decl, NodeVector& elts,
HandleValue moduleSpec,
HandleValue isDefault, TokenPos* pos,
@ -1424,6 +1446,17 @@ bool NodeBuilder::exportSpecifier(HandleValue bindingName,
dst);
}
bool NodeBuilder::exportNamespaceSpecifier(HandleValue exportName,
TokenPos* pos,
MutableHandleValue dst) {
RootedValue cb(cx, callbacks[AST_EXPORT_NAMESPACE_SPEC]);
if (!cb.isNull()) {
return callback(cb, exportName, pos, dst);
}
return newNode(AST_EXPORT_NAMESPACE_SPEC, pos, "name", exportName, dst);
}
bool NodeBuilder::exportBatchSpecifier(TokenPos* pos, MutableHandleValue dst) {
RootedValue cb(cx, callbacks[AST_EXPORT_BATCH_SPEC]);
if (!cb.isNull()) {
@ -1675,8 +1708,10 @@ class ASTSerializer {
bool variableDeclarator(ParseNode* pn, MutableHandleValue dst);
bool importDeclaration(BinaryNode* importNode, MutableHandleValue dst);
bool importSpecifier(BinaryNode* importSpec, MutableHandleValue dst);
bool importNamespaceSpecifier(UnaryNode* importSpec, MutableHandleValue dst);
bool exportDeclaration(ParseNode* exportNode, MutableHandleValue dst);
bool exportSpecifier(BinaryNode* exportSpec, MutableHandleValue dst);
bool exportNamespaceSpecifier(UnaryNode* exportSpec, MutableHandleValue dst);
bool classDefinition(ClassNode* pn, bool expr, MutableHandleValue dst);
bool optStatement(ParseNode* pn, MutableHandleValue dst) {
@ -1725,6 +1760,7 @@ class ASTSerializer {
bool identifier(HandleAtom atom, TokenPos* pos, MutableHandleValue dst);
bool identifier(NameNode* id, MutableHandleValue dst);
bool identifierOrLiteral(ParseNode* id, MutableHandleValue dst);
bool literal(ParseNode* pn, MutableHandleValue dst);
bool optPattern(ParseNode* pn, MutableHandleValue dst) {
@ -2046,10 +2082,17 @@ bool ASTSerializer::importDeclaration(BinaryNode* importNode,
}
for (ParseNode* item : specList->contents()) {
BinaryNode* spec = &item->as<BinaryNode>();
RootedValue elt(cx);
if (!importSpecifier(spec, &elt)) {
return false;
if (item->is<UnaryNode>()) {
auto* spec = &item->as<UnaryNode>();
if (!importNamespaceSpecifier(spec, &elt)) {
return false;
}
} else {
auto* spec = &item->as<BinaryNode>();
if (!importSpecifier(spec, &elt)) {
return false;
}
}
elts.infallibleAppend(elt);
}
@ -2067,12 +2110,23 @@ bool ASTSerializer::importSpecifier(BinaryNode* importSpec,
RootedValue importName(cx);
RootedValue bindingName(cx);
return identifier(importNameNode, &importName) &&
return identifierOrLiteral(importNameNode, &importName) &&
identifier(bindingNameNode, &bindingName) &&
builder.importSpecifier(importName, bindingName, &importSpec->pn_pos,
dst);
}
bool ASTSerializer::importNamespaceSpecifier(UnaryNode* importSpec,
MutableHandleValue dst) {
MOZ_ASSERT(importSpec->isKind(ParseNodeKind::ImportNamespaceSpec));
NameNode* bindingNameNode = &importSpec->kid()->as<NameNode>();
RootedValue bindingName(cx);
return identifier(bindingNameNode, &bindingName) &&
builder.importNamespaceSpecifier(bindingName, &importSpec->pn_pos,
dst);
}
bool ASTSerializer::exportDeclaration(ParseNode* exportNode,
MutableHandleValue dst) {
MOZ_ASSERT(exportNode->isKind(ParseNodeKind::ExportStmt) ||
@ -2103,7 +2157,12 @@ bool ASTSerializer::exportDeclaration(ParseNode* exportNode,
if (!exportSpecifier(&spec->as<BinaryNode>(), &elt)) {
return false;
}
} else if (spec->isKind(ParseNodeKind::ExportNamespaceSpec)) {
if (!exportNamespaceSpecifier(&spec->as<UnaryNode>(), &elt)) {
return false;
}
} else {
MOZ_ASSERT(spec->isKind(ParseNodeKind::ExportBatchSpecStmt));
if (!builder.exportBatchSpecifier(&exportNode->pn_pos, &elt)) {
return false;
}
@ -2165,12 +2224,22 @@ bool ASTSerializer::exportSpecifier(BinaryNode* exportSpec,
RootedValue bindingName(cx);
RootedValue exportName(cx);
return identifier(bindingNameNode, &bindingName) &&
identifier(exportNameNode, &exportName) &&
return identifierOrLiteral(bindingNameNode, &bindingName) &&
identifierOrLiteral(exportNameNode, &exportName) &&
builder.exportSpecifier(bindingName, exportName, &exportSpec->pn_pos,
dst);
}
bool ASTSerializer::exportNamespaceSpecifier(UnaryNode* exportSpec,
MutableHandleValue dst) {
MOZ_ASSERT(exportSpec->isKind(ParseNodeKind::ExportNamespaceSpec));
NameNode* exportNameNode = &exportSpec->kid()->as<NameNode>();
RootedValue exportName(cx);
return identifierOrLiteral(exportNameNode, &exportName) &&
builder.exportNamespaceSpecifier(exportName, &exportSpec->pn_pos, dst);
}
bool ASTSerializer::switchCase(CaseClause* caseClause, MutableHandleValue dst) {
MOZ_ASSERT_IF(
caseClause->caseExpression(),
@ -2550,7 +2619,7 @@ bool ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst) {
return false;
}
members.infallibleAppend(prop);
} else {
} else if (!item->isKind(ParseNodeKind::DefaultConstructor)) {
ClassMethod* method = &item->as<ClassMethod>();
MOZ_ASSERT(memberList->pn_pos.encloses(method->pn_pos));
@ -3286,8 +3355,9 @@ bool ASTSerializer::literal(ParseNode* pn, MutableHandleValue dst) {
case ParseNodeKind::RegExpExpr: {
RegExpObject* re = pn->as<RegExpLiteral>().create(
cx, parser->getCompilationInfo().input.atomCache,
parser->getCompilationInfo().stencil);
cx, parser->parserAtoms(),
parser->getCompilationState().input.atomCache,
parser->getCompilationState());
if (!re) {
return false;
}
@ -3301,7 +3371,8 @@ bool ASTSerializer::literal(ParseNode* pn, MutableHandleValue dst) {
break;
case ParseNodeKind::BigIntExpr: {
BigInt* x = pn->as<BigIntLiteral>().create(cx);
auto index = pn->as<BigIntLiteral>().index();
BigInt* x = parser->compilationState_.bigIntData[index].createBigInt(cx);
if (!x) {
return false;
}
@ -3453,6 +3524,13 @@ bool ASTSerializer::identifier(NameNode* id, MutableHandleValue dst) {
return identifier(pnAtom, &id->pn_pos, dst);
}
bool ASTSerializer::identifierOrLiteral(ParseNode* id, MutableHandleValue dst) {
if (id->getKind() == ParseNodeKind::Name) {
return identifier(&id->as<NameNode>(), dst);
}
return literal(id, dst);
}
bool ASTSerializer::function(FunctionNode* funNode, ASTType type,
MutableHandleValue dst) {
FunctionBox* funbox = funNode->funbox();
@ -3770,25 +3848,27 @@ static bool reflect_parse(JSContext* cx, uint32_t argc, Value* vp) {
options.allowHTMLComments = target == ParseGoal::Script;
mozilla::Range<const char16_t> chars = linearChars.twoByteRange();
Rooted<CompilationInfo> compilationInfo(cx, CompilationInfo(cx, options));
Rooted<CompilationInput> input(cx, CompilationInput(options));
if (target == ParseGoal::Script) {
if (!compilationInfo.get().input.initForGlobal(cx)) {
if (!input.get().initForGlobal(cx)) {
return false;
}
} else {
if (!compilationInfo.get().input.initForModule(cx)) {
if (!input.get().initForModule(cx)) {
return false;
}
}
LifoAllocScope allocScope(&cx->tempLifoAlloc());
frontend::CompilationState compilationState(cx, allocScope, options,
compilationInfo.get().stencil);
frontend::CompilationState compilationState(cx, allocScope, input.get());
if (!compilationState.init(cx)) {
return false;
}
Parser<FullParseHandler, char16_t> parser(
cx, options, chars.begin().get(), chars.length(),
/* foldConstants = */ false, compilationInfo.get(), compilationState,
nullptr, nullptr);
/* foldConstants = */ false, compilationState,
/* syntaxParser = */ nullptr);
if (!parser.checkOptions()) {
return false;
}
@ -3811,7 +3891,7 @@ static bool reflect_parse(JSContext* cx, uint32_t argc, Value* vp) {
uint32_t len = chars.length();
SourceExtent extent =
SourceExtent::makeGlobalExtent(len, options.lineno, options.column);
ModuleSharedContext modulesc(cx, compilationInfo.get(), builder, extent);
ModuleSharedContext modulesc(cx, options, builder, extent);
pn = parser.moduleBody(&modulesc);
if (!pn) {
return false;

View File

@ -19,6 +19,7 @@
#include "vm/JSContext.h"
#include "vm/RegExpStatics.h"
#include "vm/SelfHosting.h"
#include "vm/WellKnownAtom.h" // js_*_str
#include "vm/EnvironmentObject-inl.h"
#include "vm/JSObject-inl.h"
@ -36,8 +37,22 @@ using JS::CompileOptions;
using JS::RegExpFlag;
using JS::RegExpFlags;
// Allocate an object for the |.groups| or |.indices.groups| property
// of a regexp match result.
static PlainObject* CreateGroupsObject(JSContext* cx,
HandlePlainObject groupsTemplate) {
if (groupsTemplate->inDictionaryMode()) {
return NewObjectWithGivenProto<PlainObject>(cx, nullptr);
}
PlainObject* result;
JS_TRY_VAR_OR_RETURN_NULL(
cx, result, PlainObject::createWithTemplate(cx, groupsTemplate));
return result;
}
/*
* ES 2021 draft 21.2.5.2.2: Steps 16-28
* Implements RegExpBuiltinExec: Steps 18-35
* https://tc39.es/ecma262/#sec-regexpbuiltinexec
*/
bool js::CreateRegExpMatchResult(JSContext* cx, HandleRegExpShared re,
@ -55,44 +70,35 @@ bool js::CreateRegExpMatchResult(JSContext* cx, HandleRegExpShared re,
* input: input string
* index: start index for the match
* groups: named capture groups for the match
* indices: capture indices for the match, if required
*/
bool hasIndices = re->hasIndices();
// Get the templateObject that defines the shape and type of the output
// object.
RegExpRealm::ResultTemplateKind kind =
hasIndices ? RegExpRealm::ResultTemplateKind::WithIndices
: RegExpRealm::ResultTemplateKind::Normal;
ArrayObject* templateObject =
cx->realm()->regExps.getOrCreateMatchResultTemplateObject(cx);
cx->realm()->regExps.getOrCreateMatchResultTemplateObject(cx, kind);
if (!templateObject) {
return false;
}
// Step 16
// Steps 18-19
size_t numPairs = matches.length();
MOZ_ASSERT(numPairs > 0);
// Steps 18-19
// Steps 20-21: Allocate the match result object.
RootedArrayObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(
cx, numPairs, templateObject));
if (!arr) {
return false;
}
// Step 24 (reordered)
RootedPlainObject groups(cx);
bool groupsInDictionaryMode = false;
if (re->numNamedCaptures() > 0) {
RootedPlainObject groupsTemplate(cx, re->getGroupsTemplate());
if (groupsTemplate->inDictionaryMode()) {
groups = NewObjectWithGivenProto<PlainObject>(cx, nullptr);
groups->setGroup(groupsTemplate->group());
groupsInDictionaryMode = true;
} else {
JS_TRY_VAR_OR_RETURN_FALSE(
cx, groups, PlainObject::createWithTemplate(cx, groupsTemplate));
}
}
// Steps 22-23 and 27 a-e.
// Store a Value for each pair.
// Steps 28-29 and 33 a-d: Initialize the elements of the match result.
// Store a Value for each match pair.
for (size_t i = 0; i < numPairs; i++) {
const MatchPair& pair = matches[i];
@ -111,18 +117,82 @@ bool js::CreateRegExpMatchResult(JSContext* cx, HandleRegExpShared re,
}
}
// Step 27 f.
// The groups template object stores the names of the named captures in the
// the order in which they are defined. The named capture indices vector
// stores the corresponding capture indices. If we are not in dictionary mode,
// we simply fill in the slots with the correct values. In dictionary mode,
// we have to define the properties explicitly.
if (!groupsInDictionaryMode) {
for (uint32_t i = 0; i < re->numNamedCaptures(); i++) {
uint32_t idx = re->getNamedCaptureIndex(i);
groups->setSlot(i, arr->getDenseElement(idx));
// Step 34a (reordered): Allocate and initialize the indices object if needed.
// This is an inlined implementation of MakeIndicesArray:
// https://tc39.es/ecma262/#sec-makeindicesarray
RootedArrayObject indices(cx);
RootedPlainObject indicesGroups(cx);
if (hasIndices) {
// MakeIndicesArray: step 8
ArrayObject* indicesTemplate =
cx->realm()->regExps.getOrCreateMatchResultTemplateObject(
cx, RegExpRealm::ResultTemplateKind::Indices);
if (!indicesTemplate) {
return false;
}
} else {
indices =
NewDenseFullyAllocatedArrayWithTemplate(cx, numPairs, indicesTemplate);
if (!indices) {
return false;
}
// MakeIndicesArray: steps 10-12
if (re->numNamedCaptures() > 0) {
RootedPlainObject groupsTemplate(cx, re->getGroupsTemplate());
indicesGroups = CreateGroupsObject(cx, groupsTemplate);
if (!indicesGroups) {
return false;
}
indices->setSlot(RegExpRealm::IndicesGroupsSlot,
ObjectValue(*indicesGroups));
} else {
indices->setSlot(RegExpRealm::IndicesGroupsSlot, UndefinedValue());
}
// MakeIndicesArray: step 13 a-d. (Step 13.e is implemented below.)
for (size_t i = 0; i < numPairs; i++) {
const MatchPair& pair = matches[i];
if (pair.isUndefined()) {
// Since we had a match, first pair must be present.
MOZ_ASSERT(i != 0);
indices->setDenseInitializedLength(i + 1);
indices->initDenseElement(i, UndefinedValue());
} else {
RootedArrayObject indexPair(cx, NewDenseFullyAllocatedArray(cx, 2));
if (!indexPair) {
return false;
}
indexPair->setDenseInitializedLength(2);
indexPair->initDenseElement(0, Int32Value(pair.start));
indexPair->initDenseElement(1, Int32Value(pair.limit));
indices->setDenseInitializedLength(i + 1);
indices->initDenseElement(i, ObjectValue(*indexPair));
}
}
}
// Steps 30-31 (reordered): Allocate the groups object (if needed).
RootedPlainObject groups(cx);
bool groupsInDictionaryMode = false;
if (re->numNamedCaptures() > 0) {
RootedPlainObject groupsTemplate(cx, re->getGroupsTemplate());
groupsInDictionaryMode = groupsTemplate->inDictionaryMode();
groups = CreateGroupsObject(cx, groupsTemplate);
if (!groups) {
return false;
}
}
// Step 33 e-f: Initialize the properties of |groups| and |indices.groups|.
// The groups template object stores the names of the named captures
// in the the order in which they are defined. The named capture
// indices vector stores the corresponding capture indices. In
// dictionary mode, we have to define the properties explicitly. If
// we are not in dictionary mode, we simply fill in the slots with
// the correct values.
if (groupsInDictionaryMode) {
RootedIdVector keys(cx);
RootedPlainObject groupsTemplate(cx, re->getGroupsTemplate());
if (!GetPropertyKeys(cx, groupsTemplate, 0, &keys)) {
@ -138,23 +208,48 @@ bool js::CreateRegExpMatchResult(JSContext* cx, HandleRegExpShared re,
if (!NativeDefineDataProperty(cx, groups, key, val, JSPROP_ENUMERATE)) {
return false;
}
// MakeIndicesArray: Step 13.e (reordered)
if (hasIndices) {
val = indices->getDenseElement(idx);
if (!NativeDefineDataProperty(cx, indicesGroups, key, val,
JSPROP_ENUMERATE)) {
return false;
}
}
}
} else {
for (uint32_t i = 0; i < re->numNamedCaptures(); i++) {
uint32_t idx = re->getNamedCaptureIndex(i);
groups->setSlot(i, arr->getDenseElement(idx));
// MakeIndicesArray: Step 13.e (reordered)
if (hasIndices) {
indicesGroups->setSlot(i, indices->getDenseElement(idx));
}
}
}
// Step 20 (reordered).
// Step 22 (reordered).
// Set the |index| property.
arr->setSlot(RegExpRealm::MatchResultObjectIndexSlot,
Int32Value(matches[0].start));
// Step 21 (reordered).
// Step 23 (reordered).
// Set the |input| property.
arr->setSlot(RegExpRealm::MatchResultObjectInputSlot, StringValue(input));
// Steps 25-26 (reordered)
// Step 32 (reordered)
// Set the |groups| property.
arr->setSlot(RegExpRealm::MatchResultObjectGroupsSlot,
groups ? ObjectValue(*groups) : UndefinedValue());
// Step 34b
// Set the |indices| property.
if (re->hasIndices()) {
arr->setSlot(RegExpRealm::MatchResultObjectIndicesSlot,
ObjectValue(*indices));
}
#ifdef DEBUG
RootedValue test(cx);
RootedId id(cx, NameToId(cx->names().index));
@ -169,7 +264,7 @@ bool js::CreateRegExpMatchResult(JSContext* cx, HandleRegExpShared re,
MOZ_ASSERT(test == arr->getSlot(RegExpRealm::MatchResultObjectInputSlot));
#endif
// Step 28.
// Step 35.
rval.setObject(*arr);
return true;
}
@ -661,188 +756,146 @@ bool js::regexp_construct_raw_flags(JSContext* cx, unsigned argc, Value* vp) {
return true;
}
MOZ_ALWAYS_INLINE bool IsRegExpPrototype(HandleValue v, JSContext* cx) {
return (v.isObject() &&
cx->global()->maybeGetRegExpPrototype() == &v.toObject());
// This is a specialized implementation of "UnwrapAndTypeCheckThis" for RegExp
// getters that need to return a special value for same-realm
// %RegExp.prototype%.
template <typename Fn>
static bool RegExpGetter(JSContext* cx, CallArgs& args, const char* methodName,
Fn&& fn,
HandleValue fallbackValue = UndefinedHandleValue) {
JSObject* obj = nullptr;
if (args.thisv().isObject()) {
obj = &args.thisv().toObject();
if (IsWrapper(obj)) {
obj = CheckedUnwrapStatic(obj);
if (!obj) {
ReportAccessDenied(cx);
return false;
}
}
}
if (obj) {
// Step 4ff
if (obj->is<RegExpObject>()) {
return fn(&obj->as<RegExpObject>());
}
// Step 3.a. "If SameValue(R, %RegExp.prototype%) is true, return
// undefined."
// Or `return "(?:)"` for get RegExp.prototype.source.
if (obj == cx->global()->maybeGetRegExpPrototype()) {
args.rval().set(fallbackValue);
return true;
}
// fall-through
}
// Step 2. and Step 3.b.
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
JSMSG_INCOMPATIBLE_REGEXP_GETTER, methodName,
InformalValueTypeName(args.thisv()));
return false;
}
// ES 2017 draft 21.2.5.4.
MOZ_ALWAYS_INLINE bool regexp_global_impl(JSContext* cx, const CallArgs& args) {
MOZ_ASSERT(IsRegExpObject(args.thisv()));
// Steps 4-6.
RegExpObject* reObj = &args.thisv().toObject().as<RegExpObject>();
args.rval().setBoolean(reObj->global());
return true;
bool js::regexp_hasIndices(JSContext* cx, unsigned argc, JS::Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
return RegExpGetter(cx, args, "hasIndices", [args](RegExpObject* unwrapped) {
args.rval().setBoolean(unwrapped->hasIndices());
return true;
});
}
// ES2021 draft rev 0b3a808af87a9123890767152a26599cc8fde161
// 21.2.5.5 get RegExp.prototype.global
bool js::regexp_global(JSContext* cx, unsigned argc, JS::Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
// Step 3.a.
if (IsRegExpPrototype(args.thisv(), cx)) {
args.rval().setUndefined();
return RegExpGetter(cx, args, "global", [args](RegExpObject* unwrapped) {
args.rval().setBoolean(unwrapped->global());
return true;
}
// Steps 1-3.
return CallNonGenericMethod<IsRegExpObject, regexp_global_impl>(cx, args);
}
// ES 2017 draft 21.2.5.5.
MOZ_ALWAYS_INLINE bool regexp_ignoreCase_impl(JSContext* cx,
const CallArgs& args) {
MOZ_ASSERT(IsRegExpObject(args.thisv()));
// Steps 4-6.
RegExpObject* reObj = &args.thisv().toObject().as<RegExpObject>();
args.rval().setBoolean(reObj->ignoreCase());
return true;
});
}
// ES2021 draft rev 0b3a808af87a9123890767152a26599cc8fde161
// 21.2.5.6 get RegExp.prototype.ignoreCase
bool js::regexp_ignoreCase(JSContext* cx, unsigned argc, JS::Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
// Step 3.a.
if (IsRegExpPrototype(args.thisv(), cx)) {
args.rval().setUndefined();
return RegExpGetter(cx, args, "ignoreCase", [args](RegExpObject* unwrapped) {
args.rval().setBoolean(unwrapped->ignoreCase());
return true;
}
// Steps 1-3.
return CallNonGenericMethod<IsRegExpObject, regexp_ignoreCase_impl>(cx, args);
}
// ES 2017 draft 21.2.5.7.
MOZ_ALWAYS_INLINE bool regexp_multiline_impl(JSContext* cx,
const CallArgs& args) {
MOZ_ASSERT(IsRegExpObject(args.thisv()));
// Steps 4-6.
RegExpObject* reObj = &args.thisv().toObject().as<RegExpObject>();
args.rval().setBoolean(reObj->multiline());
return true;
});
}
// ES2021 draft rev 0b3a808af87a9123890767152a26599cc8fde161
// 21.2.5.9 get RegExp.prototype.multiline
bool js::regexp_multiline(JSContext* cx, unsigned argc, JS::Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
// Step 3.a.
if (IsRegExpPrototype(args.thisv(), cx)) {
args.rval().setUndefined();
return RegExpGetter(cx, args, "multiline", [args](RegExpObject* unwrapped) {
args.rval().setBoolean(unwrapped->multiline());
return true;
}
// Steps 1-3.
return CallNonGenericMethod<IsRegExpObject, regexp_multiline_impl>(cx, args);
}
// ES 2017 draft 21.2.5.10.
MOZ_ALWAYS_INLINE bool regexp_source_impl(JSContext* cx, const CallArgs& args) {
MOZ_ASSERT(IsRegExpObject(args.thisv()));
// Step 5.
RegExpObject* reObj = &args.thisv().toObject().as<RegExpObject>();
RootedAtom src(cx, reObj->getSource());
if (!src) {
return false;
}
// Step 7.
JSString* str = EscapeRegExpPattern(cx, src);
if (!str) {
return false;
}
args.rval().setString(str);
return true;
});
}
// ES2021 draft rev 0b3a808af87a9123890767152a26599cc8fde161
// 21.2.5.12 get RegExp.prototype.source
static bool regexp_source(JSContext* cx, unsigned argc, JS::Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
// Step 3.a. Return "(?:)" for %RegExp.prototype%.
RootedValue fallback(cx, StringValue(cx->names().emptyRegExp));
return RegExpGetter(
cx, args, "source",
[cx, args](RegExpObject* unwrapped) {
RootedAtom src(cx, unwrapped->getSource());
MOZ_ASSERT(src);
// Mark potentially cross-compartment JSAtom.
cx->markAtom(src);
// Step 3.a.
if (IsRegExpPrototype(args.thisv(), cx)) {
args.rval().setString(cx->names().emptyRegExp);
return true;
}
// Step 7.
JSString* escaped = EscapeRegExpPattern(cx, src);
if (!escaped) {
return false;
}
// Steps 1-4.
return CallNonGenericMethod<IsRegExpObject, regexp_source_impl>(cx, args);
}
// ES 2020 draft 21.2.5.3.
MOZ_ALWAYS_INLINE bool regexp_dotAll_impl(JSContext* cx, const CallArgs& args) {
MOZ_ASSERT(IsRegExpObject(args.thisv()));
// Steps 4-6.
RegExpObject* reObj = &args.thisv().toObject().as<RegExpObject>();
args.rval().setBoolean(reObj->dotAll());
return true;
args.rval().setString(escaped);
return true;
},
fallback);
}
// ES2021 draft rev 0b3a808af87a9123890767152a26599cc8fde161
// 21.2.5.3 get RegExp.prototype.dotAll
bool js::regexp_dotAll(JSContext* cx, unsigned argc, JS::Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
// Step 3.a.
if (IsRegExpPrototype(args.thisv(), cx)) {
args.rval().setUndefined();
return RegExpGetter(cx, args, "dotAll", [args](RegExpObject* unwrapped) {
args.rval().setBoolean(unwrapped->dotAll());
return true;
}
// Steps 1-3.
return CallNonGenericMethod<IsRegExpObject, regexp_dotAll_impl>(cx, args);
}
// ES 2017 draft 21.2.5.12.
MOZ_ALWAYS_INLINE bool regexp_sticky_impl(JSContext* cx, const CallArgs& args) {
MOZ_ASSERT(IsRegExpObject(args.thisv()));
// Steps 4-6.
RegExpObject* reObj = &args.thisv().toObject().as<RegExpObject>();
args.rval().setBoolean(reObj->sticky());
return true;
});
}
// ES2021 draft rev 0b3a808af87a9123890767152a26599cc8fde161
// 21.2.5.14 get RegExp.prototype.sticky
bool js::regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
// Step 3.a.
if (IsRegExpPrototype(args.thisv(), cx)) {
args.rval().setUndefined();
return RegExpGetter(cx, args, "sticky", [args](RegExpObject* unwrapped) {
args.rval().setBoolean(unwrapped->sticky());
return true;
}
// Steps 1-3.
return CallNonGenericMethod<IsRegExpObject, regexp_sticky_impl>(cx, args);
}
// ES 2017 draft 21.2.5.15.
MOZ_ALWAYS_INLINE bool regexp_unicode_impl(JSContext* cx,
const CallArgs& args) {
MOZ_ASSERT(IsRegExpObject(args.thisv()));
// Steps 4-6.
RegExpObject* reObj = &args.thisv().toObject().as<RegExpObject>();
args.rval().setBoolean(reObj->unicode());
return true;
});
}
// ES2021 draft rev 0b3a808af87a9123890767152a26599cc8fde161
// 21.2.5.17 get RegExp.prototype.unicode
bool js::regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
// Step 3.a.
if (IsRegExpPrototype(args.thisv(), cx)) {
args.rval().setUndefined();
return RegExpGetter(cx, args, "unicode", [args](RegExpObject* unwrapped) {
args.rval().setBoolean(unwrapped->unicode());
return true;
}
// Steps 1-3.
return CallNonGenericMethod<IsRegExpObject, regexp_unicode_impl>(cx, args);
});
}
const JSPropertySpec js::regexp_properties[] = {
JS_SELF_HOSTED_GET("flags", "$RegExpFlagsGetter", 0),
JS_PSG("hasIndices", regexp_hasIndices, 0),
JS_PSG("global", regexp_global, 0),
JS_PSG("ignoreCase", regexp_ignoreCase, 0),
JS_PSG("multiline", regexp_multiline, 0),
@ -1834,7 +1887,7 @@ bool js::RegExpPrototypeOptimizable(JSContext* cx, unsigned argc, Value* vp) {
bool js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto) {
AutoUnsafeCallWithABI unsafe;
AutoAssertNoPendingException aanpe(cx);
if (!proto->isNative()) {
if (!proto->is<NativeObject>()) {
return false;
}
@ -1869,6 +1922,16 @@ bool js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto) {
return false;
}
JSNative hasIndicesGetter;
if (!GetOwnNativeGetterPure(cx, proto, NameToId(cx->names().hasIndices),
&hasIndicesGetter)) {
return false;
}
if (hasIndicesGetter != regexp_hasIndices) {
return false;
}
JSNative ignoreCaseGetter;
if (!GetOwnNativeGetterPure(cx, proto, NameToId(cx->names().ignoreCase),
&ignoreCaseGetter)) {
@ -2060,7 +2123,7 @@ bool js::intrinsic_GetElemBaseForLambda(JSContext* cx, unsigned argc,
JSObject& bobj = b.toObject();
const JSClass* clasp = bobj.getClass();
if (!clasp->isNative() || clasp->getOpsLookupProperty() ||
if (!clasp->isNativeObject() || clasp->getOpsLookupProperty() ||
clasp->getOpsGetProperty()) {
return true;
}
@ -2080,7 +2143,7 @@ bool js::intrinsic_GetStringDataProperty(JSContext* cx, unsigned argc,
MOZ_ASSERT(args.length() == 2);
RootedObject obj(cx, &args[0].toObject());
if (!obj->isNative()) {
if (!obj->is<NativeObject>()) {
// The object is already checked to be native in GetElemBaseForLambda,
// but it can be swapped to another class that is non-native.
// Return undefined to mark failure to get the property.

View File

@ -23,49 +23,50 @@ JSObject* InitRegExpClass(JSContext* cx, HandleObject obj);
* |input| may be nullptr if there is no JSString corresponding to
* |chars| and |length|.
*/
MOZ_MUST_USE bool ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res,
Handle<RegExpObject*> reobj,
HandleLinearString input,
size_t* lastIndex, bool test,
MutableHandleValue rval);
[[nodiscard]] bool ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res,
Handle<RegExpObject*> reobj,
HandleLinearString input,
size_t* lastIndex, bool test,
MutableHandleValue rval);
// Translation from MatchPairs to a JS array in regexp_exec()'s output format.
MOZ_MUST_USE bool CreateRegExpMatchResult(JSContext* cx, HandleRegExpShared re,
HandleString input,
const MatchPairs& matches,
MutableHandleValue rval);
[[nodiscard]] bool CreateRegExpMatchResult(JSContext* cx, HandleRegExpShared re,
HandleString input,
const MatchPairs& matches,
MutableHandleValue rval);
extern MOZ_MUST_USE bool RegExpMatcher(JSContext* cx, unsigned argc, Value* vp);
extern MOZ_MUST_USE bool RegExpMatcherRaw(JSContext* cx, HandleObject regexp,
HandleString input,
int32_t maybeLastIndex,
MatchPairs* maybeMatches,
MutableHandleValue output);
extern MOZ_MUST_USE bool RegExpSearcher(JSContext* cx, unsigned argc,
[[nodiscard]] extern bool RegExpMatcher(JSContext* cx, unsigned argc,
Value* vp);
extern MOZ_MUST_USE bool RegExpSearcherRaw(JSContext* cx, HandleObject regexp,
[[nodiscard]] extern bool RegExpMatcherRaw(JSContext* cx, HandleObject regexp,
HandleString input,
int32_t lastIndex,
int32_t maybeLastIndex,
MatchPairs* maybeMatches,
int32_t* result);
MutableHandleValue output);
extern MOZ_MUST_USE bool RegExpTester(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] extern bool RegExpSearcher(JSContext* cx, unsigned argc,
Value* vp);
extern MOZ_MUST_USE bool RegExpTesterRaw(JSContext* cx, HandleObject regexp,
HandleString input, int32_t lastIndex,
int32_t* endIndex);
[[nodiscard]] extern bool RegExpSearcherRaw(JSContext* cx, HandleObject regexp,
HandleString input,
int32_t lastIndex,
MatchPairs* maybeMatches,
int32_t* result);
extern MOZ_MUST_USE bool intrinsic_GetElemBaseForLambda(JSContext* cx,
unsigned argc,
Value* vp);
[[nodiscard]] extern bool RegExpTester(JSContext* cx, unsigned argc, Value* vp);
extern MOZ_MUST_USE bool intrinsic_GetStringDataProperty(JSContext* cx,
[[nodiscard]] extern bool RegExpTesterRaw(JSContext* cx, HandleObject regexp,
HandleString input, int32_t lastIndex,
int32_t* endIndex);
[[nodiscard]] extern bool intrinsic_GetElemBaseForLambda(JSContext* cx,
unsigned argc,
Value* vp);
[[nodiscard]] extern bool intrinsic_GetStringDataProperty(JSContext* cx,
unsigned argc,
Value* vp);
/*
* The following functions are for use by self-hosted code.
*/
@ -79,62 +80,64 @@ extern MOZ_MUST_USE bool intrinsic_GetStringDataProperty(JSContext* cx,
* Dedicated function for RegExp.prototype[@@replace] and
* RegExp.prototype[@@split] optimized paths.
*/
extern MOZ_MUST_USE bool regexp_construct_raw_flags(JSContext* cx,
[[nodiscard]] extern bool regexp_construct_raw_flags(JSContext* cx,
unsigned argc, Value* vp);
[[nodiscard]] extern bool IsRegExp(JSContext* cx, HandleValue value,
bool* result);
[[nodiscard]] extern bool RegExpCreate(JSContext* cx, HandleValue pattern,
HandleValue flags,
MutableHandleValue rval);
[[nodiscard]] extern bool RegExpPrototypeOptimizable(JSContext* cx,
unsigned argc, Value* vp);
[[nodiscard]] extern bool RegExpPrototypeOptimizableRaw(JSContext* cx,
JSObject* proto);
[[nodiscard]] extern bool RegExpInstanceOptimizable(JSContext* cx,
unsigned argc, Value* vp);
extern MOZ_MUST_USE bool IsRegExp(JSContext* cx, HandleValue value,
bool* result);
extern MOZ_MUST_USE bool RegExpCreate(JSContext* cx, HandleValue pattern,
HandleValue flags,
MutableHandleValue rval);
extern MOZ_MUST_USE bool RegExpPrototypeOptimizable(JSContext* cx,
unsigned argc, Value* vp);
extern MOZ_MUST_USE bool RegExpPrototypeOptimizableRaw(JSContext* cx,
[[nodiscard]] extern bool RegExpInstanceOptimizableRaw(JSContext* cx,
JSObject* obj,
JSObject* proto);
extern MOZ_MUST_USE bool RegExpInstanceOptimizable(JSContext* cx, unsigned argc,
Value* vp);
extern MOZ_MUST_USE bool RegExpInstanceOptimizableRaw(JSContext* cx,
JSObject* obj,
JSObject* proto);
extern MOZ_MUST_USE bool RegExpGetSubstitution(
[[nodiscard]] extern bool RegExpGetSubstitution(
JSContext* cx, HandleArrayObject matchResult, HandleLinearString string,
size_t position, HandleLinearString replacement, size_t firstDollarIndex,
HandleValue namedCaptures, MutableHandleValue rval);
extern MOZ_MUST_USE bool GetFirstDollarIndex(JSContext* cx, unsigned argc,
Value* vp);
[[nodiscard]] extern bool GetFirstDollarIndex(JSContext* cx, unsigned argc,
Value* vp);
extern MOZ_MUST_USE bool GetFirstDollarIndexRaw(JSContext* cx, JSString* str,
int32_t* index);
[[nodiscard]] extern bool GetFirstDollarIndexRaw(JSContext* cx, JSString* str,
int32_t* index);
extern int32_t GetFirstDollarIndexRawFlat(JSLinearString* text);
// RegExp ClassSpec members used in RegExpObject.cpp.
extern MOZ_MUST_USE bool regexp_construct(JSContext* cx, unsigned argc,
Value* vp);
[[nodiscard]] extern bool regexp_construct(JSContext* cx, unsigned argc,
Value* vp);
extern const JSPropertySpec regexp_static_props[];
extern const JSPropertySpec regexp_properties[];
extern const JSFunctionSpec regexp_methods[];
// Used in RegExpObject::isOriginalFlagGetter.
extern MOZ_MUST_USE bool regexp_global(JSContext* cx, unsigned argc,
JS::Value* vp);
extern MOZ_MUST_USE bool regexp_ignoreCase(JSContext* cx, unsigned argc,
JS::Value* vp);
extern MOZ_MUST_USE bool regexp_multiline(JSContext* cx, unsigned argc,
JS::Value* vp);
extern MOZ_MUST_USE bool regexp_dotAll(JSContext* cx, unsigned argc,
JS::Value* vp);
extern MOZ_MUST_USE bool regexp_sticky(JSContext* cx, unsigned argc,
JS::Value* vp);
extern MOZ_MUST_USE bool regexp_unicode(JSContext* cx, unsigned argc,
[[nodiscard]] extern bool regexp_hasIndices(JSContext* cx, unsigned argc,
JS::Value* vp);
[[nodiscard]] extern bool regexp_global(JSContext* cx, unsigned argc,
JS::Value* vp);
[[nodiscard]] extern bool regexp_ignoreCase(JSContext* cx, unsigned argc,
JS::Value* vp);
[[nodiscard]] extern bool regexp_multiline(JSContext* cx, unsigned argc,
JS::Value* vp);
[[nodiscard]] extern bool regexp_dotAll(JSContext* cx, unsigned argc,
JS::Value* vp);
[[nodiscard]] extern bool regexp_sticky(JSContext* cx, unsigned argc,
JS::Value* vp);
[[nodiscard]] extern bool regexp_unicode(JSContext* cx, unsigned argc,
JS::Value* vp);
} /* namespace js */

View File

@ -16,30 +16,34 @@ function $RegExpFlagsGetter() {
var result = "";
// Steps 4-5.
if (R.hasIndices)
result += "d";
// Steps 6-7.
if (R.global)
result += "g";
// Steps 6-7.
// Steps 8-9.
if (R.ignoreCase)
result += "i";
// Steps 8-9.
// Steps 10-11.
if (R.multiline)
result += "m";
// Steps 10-11.
// Steps 12-13.
if (R.dotAll)
result += "s";
// Steps 12-13.
// Steps 14-15.
if (R.unicode)
result += "u";
// Steps 14-15.
// Steps 16-17
if (R.sticky)
result += "y";
// Step 16.
// Step 18.
return result;
}
_SetCanonicalName($RegExpFlagsGetter, "get flags");
@ -229,6 +233,7 @@ function RegExpGlobalMatchOpt(rx, S, fullUnicode) {
// Checks if following properties and getters are not modified, and accessing
// them not observed by content script:
// * flags
// * hasIndices
// * global
// * ignoreCase
// * multiline

View File

@ -89,6 +89,7 @@
#define REGEXP_STICKY_FLAG 0x08
#define REGEXP_UNICODE_FLAG 0x10
#define REGEXP_DOTALL_FLAG 0x20
#define REGEXP_HASINDICES_FLAG 0x40
#define REGEXP_STRING_ITERATOR_REGEXP_SLOT 0
#define REGEXP_STRING_ITERATOR_STRING_SLOT 1
@ -99,11 +100,18 @@
#define REGEXP_STRING_ITERATOR_LASTINDEX_DONE -1
#define REGEXP_STRING_ITERATOR_LASTINDEX_SLOW -2
#define DATE_METHOD_LOCALE_TIME_STRING 0
#define DATE_METHOD_LOCALE_DATE_STRING 1
#define DATE_METHOD_LOCALE_STRING 2
#define MODULE_OBJECT_ENVIRONMENT_SLOT 1
#define MODULE_OBJECT_STATUS_SLOT 3
#define MODULE_OBJECT_EVALUATION_ERROR_SLOT 4
#define MODULE_OBJECT_DFS_INDEX_SLOT 14
#define MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT 15
#define MODULE_OBJECT_ASYNC_EVALUATING_SLOT 17
#define MODULE_OBJECT_TOP_LEVEL_CAPABILITY_SLOT 18
#define MODULE_OBJECT_PENDING_ASYNC_DEPENDENCIES_SLOT 20
// rev b012019fea18f29737a67c36911340a3e25bfc63
// 15.2.1.16 Cyclic Module Records

View File

@ -27,7 +27,7 @@
#include "vm/PromiseObject.h" // js::PromiseObject, js::PromiseResolvedWithUndefined
#include "vm/SelfHosting.h"
#include "builtin/streams/HandlerFunction-inl.h" // js::NewHandler
#include "builtin/HandlerFunction-inl.h" // js::NewHandler
#include "builtin/streams/ReadableStreamReader-inl.h" // js::Unwrap{ReaderFromStream{,NoThrow},StreamFromReader}
#include "vm/Compartment-inl.h"
#include "vm/List-inl.h" // js::ListObject, js::StoreNewListInFixedSlot
@ -105,7 +105,7 @@ const JSClass ByteStreamChunk::class_ = {
* Note: All arguments must be same-compartment with cx. ReadableStream
* controllers are always created in the same compartment as the stream.
*/
static MOZ_MUST_USE ReadableByteStreamController*
[[nodiscard]] static ReadableByteStreamController*
CreateReadableByteStreamController(JSContext* cx,
Handle<ReadableStream*> stream,
HandleValue underlyingByteSource,
@ -252,7 +252,7 @@ class MOZ_RAII AutoClearUnderlyingSource {
* Version of SetUpReadableByteStreamController that's specialized for handling
* external, embedding-provided, underlying sources.
*/
MOZ_MUST_USE bool js::SetUpExternalReadableByteStreamController(
[[nodiscard]] bool js::SetUpExternalReadableByteStreamController(
JSContext* cx, Handle<ReadableStream*> stream,
JS::ReadableStreamUnderlyingSource* source) {
// Done elsewhere in the standard: Create the controller object.
@ -388,13 +388,13 @@ JS_STREAMS_CLASS_SPEC(ReadableByteStreamController, 0, SlotCount,
// Streams spec, 3.11.5.1. [[CancelSteps]] ()
// Unified with 3.9.5.1 above.
static MOZ_MUST_USE bool ReadableByteStreamControllerHandleQueueDrain(
[[nodiscard]] static bool ReadableByteStreamControllerHandleQueueDrain(
JSContext* cx, Handle<ReadableStreamController*> unwrappedController);
/**
* Streams spec, 3.11.5.2. [[PullSteps]] ( forAuthorCode )
*/
static MOZ_MUST_USE PromiseObject* ReadableByteStreamControllerPullSteps(
[[nodiscard]] static PromiseObject* ReadableByteStreamControllerPullSteps(
JSContext* cx, Handle<ReadableByteStreamController*> unwrappedController) {
// Step 1: Let stream be this.[[controlledReadableByteStream]].
Rooted<ReadableStream*> unwrappedStream(cx, unwrappedController->stream());
@ -579,7 +579,7 @@ static MOZ_MUST_USE PromiseObject* ReadableByteStreamControllerPullSteps(
* and
* Streams spec, 3.11.5.2. [[PullSteps]] ( forAuthorCode )
*/
MOZ_MUST_USE PromiseObject* js::ReadableStreamControllerPullSteps(
[[nodiscard]] PromiseObject* js::ReadableStreamControllerPullSteps(
JSContext* cx, Handle<ReadableStreamController*> unwrappedController) {
if (unwrappedController->is<ReadableStreamDefaultController>()) {
Rooted<ReadableStreamDefaultController*> unwrappedDefaultController(
@ -605,14 +605,14 @@ MOZ_MUST_USE PromiseObject* js::ReadableStreamControllerPullSteps(
// ReadableByteStreamControllerCallPullIfNeeded ( controller )
// Unified with 3.9.2 above.
static MOZ_MUST_USE bool ReadableByteStreamControllerInvalidateBYOBRequest(
[[nodiscard]] static bool ReadableByteStreamControllerInvalidateBYOBRequest(
JSContext* cx, Handle<ReadableByteStreamController*> unwrappedController);
/**
* Streams spec, 3.13.5.
* ReadableByteStreamControllerClearPendingPullIntos ( controller )
*/
MOZ_MUST_USE bool js::ReadableByteStreamControllerClearPendingPullIntos(
[[nodiscard]] bool js::ReadableByteStreamControllerClearPendingPullIntos(
JSContext* cx, Handle<ReadableByteStreamController*> unwrappedController) {
// Step 1: Perform
// ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).
@ -630,7 +630,7 @@ MOZ_MUST_USE bool js::ReadableByteStreamControllerClearPendingPullIntos(
/**
* Streams spec, 3.13.6. ReadableByteStreamControllerClose ( controller )
*/
MOZ_MUST_USE bool js::ReadableByteStreamControllerClose(
[[nodiscard]] bool js::ReadableByteStreamControllerClose(
JSContext* cx, Handle<ReadableByteStreamController*> unwrappedController) {
// Step 1: Let stream be controller.[[controlledReadableByteStream]].
Rooted<ReadableStream*> unwrappedStream(cx, unwrappedController->stream());
@ -707,7 +707,7 @@ MOZ_MUST_USE bool js::ReadableByteStreamControllerClose(
* Streams spec, 3.13.15.
* ReadableByteStreamControllerHandleQueueDrain ( controller )
*/
static MOZ_MUST_USE bool ReadableByteStreamControllerHandleQueueDrain(
[[nodiscard]] static bool ReadableByteStreamControllerHandleQueueDrain(
JSContext* cx, Handle<ReadableStreamController*> unwrappedController) {
MOZ_ASSERT(unwrappedController->is<ReadableByteStreamController>());
@ -744,7 +744,7 @@ enum BYOBRequestSlots {
* Streams spec 3.13.16.
* ReadableByteStreamControllerInvalidateBYOBRequest ( controller )
*/
static MOZ_MUST_USE bool ReadableByteStreamControllerInvalidateBYOBRequest(
[[nodiscard]] static bool ReadableByteStreamControllerInvalidateBYOBRequest(
JSContext* cx, Handle<ReadableByteStreamController*> unwrappedController) {
// Step 1: If controller.[[byobRequest]] is undefined, return.
RootedValue unwrappedBYOBRequestVal(cx, unwrappedController->byobRequest());

View File

@ -5,8 +5,6 @@
#ifndef builtin_Stream_h
#define builtin_Stream_h
#include "mozilla/Attributes.h" // MOZ_MUST_USE
#include "jstypes.h" // JS_PUBLIC_API
#include "js/RootingAPI.h" // JS::Handle
@ -18,15 +16,15 @@ class PromiseObject;
class ReadableByteStreamController;
class ReadableStreamController;
extern MOZ_MUST_USE bool ReadableByteStreamControllerClearPendingPullIntos(
[[nodiscard]] extern bool ReadableByteStreamControllerClearPendingPullIntos(
JSContext* cx,
JS::Handle<ReadableByteStreamController*> unwrappedController);
extern MOZ_MUST_USE bool ReadableByteStreamControllerClose(
[[nodiscard]] extern bool ReadableByteStreamControllerClose(
JSContext* cx,
JS::Handle<ReadableByteStreamController*> unwrappedController);
extern MOZ_MUST_USE PromiseObject* ReadableStreamControllerPullSteps(
[[nodiscard]] extern PromiseObject* ReadableStreamControllerPullSteps(
JSContext* cx, JS::Handle<ReadableStreamController*> unwrappedController);
} // namespace js

View File

@ -4,7 +4,6 @@
#include "builtin/String.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/FloatingPoint.h"
@ -57,7 +56,8 @@
#include "vm/RegExpObject.h"
#include "vm/RegExpStatics.h"
#include "vm/SelfHosting.h"
#include "vm/ToSource.h" // js::ValueToSource
#include "vm/ToSource.h" // js::ValueToSource
#include "vm/WellKnownAtom.h" // js_*_str
#include "vm/InlineCharBuffer-inl.h"
#include "vm/Interpreter-inl.h"
@ -1998,7 +1998,7 @@ class StringSegmentRange {
explicit StringSegmentRange(JSContext* cx)
: stack(cx, StackVector(cx)), cur(cx) {}
MOZ_MUST_USE bool init(JSString* str) {
[[nodiscard]] bool init(JSString* str) {
MOZ_ASSERT(stack.empty());
return settle(str);
}
@ -2010,7 +2010,7 @@ class StringSegmentRange {
return cur;
}
MOZ_MUST_USE bool popFront() {
[[nodiscard]] bool popFront() {
MOZ_ASSERT(!empty());
if (stack.empty()) {
cur = nullptr;
@ -3296,21 +3296,9 @@ JSString* js::str_replaceAll_string_raw(JSContext* cx, HandleString string,
return ReplaceAll<Latin1Char, Latin1Char>(cx, str, search, repl);
}
static ArrayObject* NewFullyAllocatedStringArray(JSContext* cx,
HandleObjectGroup group,
uint32_t length) {
ArrayObject* array = NewFullyAllocatedArrayTryUseGroup(cx, group, length);
if (!array) {
return nullptr;
}
return array;
}
static ArrayObject* SingleElementStringArray(JSContext* cx,
HandleObjectGroup group,
HandleLinearString str) {
ArrayObject* array = NewFullyAllocatedStringArray(cx, group, 1);
ArrayObject* array = NewDenseFullyAllocatedArray(cx, 1);
if (!array) {
return nullptr;
}
@ -3321,8 +3309,7 @@ static ArrayObject* SingleElementStringArray(JSContext* cx,
// ES 2016 draft Mar 25, 2016 21.1.3.17 steps 4, 8, 12-18.
static ArrayObject* SplitHelper(JSContext* cx, HandleLinearString str,
uint32_t limit, HandleLinearString sep,
HandleObjectGroup group) {
uint32_t limit, HandleLinearString sep) {
size_t strLength = str->length();
size_t sepLength = sep->length();
MOZ_ASSERT(sepLength != 0);
@ -3334,11 +3321,11 @@ static ArrayObject* SplitHelper(JSContext* cx, HandleLinearString str,
// Step 12.b.
if (match != -1) {
return NewFullyAllocatedArrayTryUseGroup(cx, group, 0);
return NewDenseEmptyArray(cx);
}
// Steps 12.c-e.
return SingleElementStringArray(cx, group, str);
return SingleElementStringArray(cx, str);
}
// Step 3 (reordered).
@ -3397,8 +3384,7 @@ static ArrayObject* SplitHelper(JSContext* cx, HandleLinearString str,
// Step 14.c.ii.5.
if (splits.length() == limit) {
return NewCopiedArrayTryUseGroup(cx, group, splits.begin(),
splits.length());
return NewDenseCopiedArray(cx, splits.length(), splits.begin());
}
// Step 14.c.ii.6.
@ -3418,15 +3404,15 @@ static ArrayObject* SplitHelper(JSContext* cx, HandleLinearString str,
}
// Step 18.
return NewCopiedArrayTryUseGroup(cx, group, splits.begin(), splits.length());
return NewDenseCopiedArray(cx, splits.length(), splits.begin());
}
// Fast-path for splitting a string into a character array via split("").
static ArrayObject* CharSplitHelper(JSContext* cx, HandleLinearString str,
uint32_t limit, HandleObjectGroup group) {
uint32_t limit) {
size_t strLength = str->length();
if (strLength == 0) {
return NewFullyAllocatedArrayTryUseGroup(cx, group, 0);
return NewDenseEmptyArray(cx);
}
js::StaticStrings& staticStrings = cx->staticStrings();
@ -3435,8 +3421,7 @@ static ArrayObject* CharSplitHelper(JSContext* cx, HandleLinearString str,
"Neither limit nor strLength is zero, so resultlen is greater "
"than zero.");
RootedArrayObject splits(cx,
NewFullyAllocatedStringArray(cx, group, resultlen));
RootedArrayObject splits(cx, NewDenseFullyAllocatedArray(cx, resultlen));
if (!splits) {
return nullptr;
}
@ -3452,7 +3437,7 @@ static ArrayObject* CharSplitHelper(JSContext* cx, HandleLinearString str,
splits->initDenseElement(i, StringValue(staticStrings.getUnit(c)));
}
} else {
splits->ensureDenseInitializedLength(cx, 0, resultlen);
splits->ensureDenseInitializedLength(0, resultlen);
for (size_t i = 0; i < resultlen; ++i) {
JSString* sub = staticStrings.getUnitStringForElement(cx, str, i);
@ -3469,7 +3454,7 @@ static ArrayObject* CharSplitHelper(JSContext* cx, HandleLinearString str,
template <typename TextChar>
static MOZ_ALWAYS_INLINE ArrayObject* SplitSingleCharHelper(
JSContext* cx, HandleLinearString str, const TextChar* text,
uint32_t textLen, char16_t patCh, HandleObjectGroup group) {
uint32_t textLen, char16_t patCh) {
// Count the number of occurrences of patCh within text.
uint32_t count = 0;
for (size_t index = 0; index < textLen; index++) {
@ -3480,16 +3465,15 @@ static MOZ_ALWAYS_INLINE ArrayObject* SplitSingleCharHelper(
// Handle zero-occurrence case - return input string in an array.
if (count == 0) {
return SingleElementStringArray(cx, group, str);
return SingleElementStringArray(cx, str);
}
// Create the result array for the substring values.
RootedArrayObject splits(cx,
NewFullyAllocatedStringArray(cx, group, count + 1));
RootedArrayObject splits(cx, NewDenseFullyAllocatedArray(cx, count + 1));
if (!splits) {
return nullptr;
}
splits->ensureDenseInitializedLength(cx, 0, count + 1);
splits->ensureDenseInitializedLength(0, count + 1);
// Add substrings.
uint32_t splitsIndex = 0;
@ -3519,8 +3503,7 @@ static MOZ_ALWAYS_INLINE ArrayObject* SplitSingleCharHelper(
// ES 2016 draft Mar 25, 2016 21.1.3.17 steps 4, 8, 12-18.
static ArrayObject* SplitSingleCharHelper(JSContext* cx, HandleLinearString str,
char16_t ch,
HandleObjectGroup group) {
char16_t ch) {
// Step 12.
size_t strLength = str->length();
@ -3531,17 +3514,16 @@ static ArrayObject* SplitSingleCharHelper(JSContext* cx, HandleLinearString str,
if (linearChars.isLatin1()) {
return SplitSingleCharHelper(cx, str, linearChars.latin1Chars(), strLength,
ch, group);
ch);
}
return SplitSingleCharHelper(cx, str, linearChars.twoByteChars(), strLength,
ch, group);
ch);
}
// ES 2016 draft Mar 25, 2016 21.1.3.17 steps 4, 8, 12-18.
ArrayObject* js::StringSplitString(JSContext* cx, HandleObjectGroup group,
HandleString str, HandleString sep,
uint32_t limit) {
ArrayObject* js::StringSplitString(JSContext* cx, HandleString str,
HandleString sep, uint32_t limit) {
MOZ_ASSERT(limit > 0, "Only called for strictly positive limit.");
RootedLinearString linearStr(cx, str->ensureLinear(cx));
@ -3555,15 +3537,15 @@ ArrayObject* js::StringSplitString(JSContext* cx, HandleObjectGroup group,
}
if (linearSep->length() == 0) {
return CharSplitHelper(cx, linearStr, limit, group);
return CharSplitHelper(cx, linearStr, limit);
}
if (linearSep->length() == 1 && limit >= static_cast<uint32_t>(INT32_MAX)) {
char16_t ch = linearSep->latin1OrTwoByteChar(0);
return SplitSingleCharHelper(cx, linearStr, ch, group);
return SplitSingleCharHelper(cx, linearStr, ch);
}
return SplitHelper(cx, linearStr, limit, linearSep, group);
return SplitHelper(cx, linearStr, limit, linearSep);
}
static const JSFunctionSpec string_methods[] = {

View File

@ -5,8 +5,6 @@
#ifndef builtin_String_h
#define builtin_String_h
#include "mozilla/Attributes.h"
#include "NamespaceImports.h"
#include "js/RootingAPI.h"
@ -55,8 +53,8 @@ extern bool str_endsWith(JSContext* cx, unsigned argc, Value* vp);
*
* Usage: lowerCase = intl_toLocaleLowerCase(string, locale)
*/
extern MOZ_MUST_USE bool intl_toLocaleLowerCase(JSContext* cx, unsigned argc,
Value* vp);
[[nodiscard]] extern bool intl_toLocaleLowerCase(JSContext* cx, unsigned argc,
Value* vp);
/**
* Returns the input string converted to upper case based on the language
@ -64,13 +62,12 @@ extern MOZ_MUST_USE bool intl_toLocaleLowerCase(JSContext* cx, unsigned argc,
*
* Usage: upperCase = intl_toLocaleUpperCase(string, locale)
*/
extern MOZ_MUST_USE bool intl_toLocaleUpperCase(JSContext* cx, unsigned argc,
Value* vp);
[[nodiscard]] extern bool intl_toLocaleUpperCase(JSContext* cx, unsigned argc,
Value* vp);
#endif
ArrayObject* StringSplitString(JSContext* cx, Handle<ObjectGroup*> group,
HandleString str, HandleString sep,
uint32_t limit);
ArrayObject* StringSplitString(JSContext* cx, HandleString str,
HandleString sep, uint32_t limit);
JSString* StringFlatReplaceString(JSContext* cx, HandleString string,
HandleString pattern,

View File

@ -35,24 +35,25 @@ class SymbolObject : public NativeObject {
setFixedSlot(PRIMITIVE_VALUE_SLOT, SymbolValue(symbol));
}
static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
// Static methods.
static MOZ_MUST_USE bool for_(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool keyFor(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool for_(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool keyFor(JSContext* cx, unsigned argc, Value* vp);
// Methods defined on Symbol.prototype.
static MOZ_MUST_USE bool toString_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool toString(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool valueOf_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool valueOf(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool toPrimitive(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool toString_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool toString(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool valueOf_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool valueOf(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool toPrimitive(JSContext* cx, unsigned argc,
Value* vp);
// Properties defined on Symbol.prototype.
static MOZ_MUST_USE bool descriptionGetter_impl(JSContext* cx,
const CallArgs& args);
static MOZ_MUST_USE bool descriptionGetter(JSContext* cx, unsigned argc,
Value* vp);
[[nodiscard]] static bool descriptionGetter_impl(JSContext* cx,
const CallArgs& args);
[[nodiscard]] static bool descriptionGetter(JSContext* cx, unsigned argc,
Value* vp);
static const JSPropertySpec properties[];
static const JSFunctionSpec methods[];

View File

@ -8,6 +8,7 @@
#include "mozilla/Casting.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/Maybe.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Span.h"
#include "mozilla/Sprintf.h"
#include "mozilla/TextUtils.h"
@ -21,6 +22,7 @@
#include <cstdlib>
#include <ctime>
#include <initializer_list>
#include <iterator>
#include <utility>
#if defined(XP_UNIX) && !defined(XP_DARWIN)
@ -42,13 +44,15 @@
# include "frontend/TokenStream.h"
#endif
#include "frontend/BytecodeCompilation.h"
#include "frontend/CompilationInfo.h" // frontend::CompilationInfo, frontend::CompilationInfoVector
#include "frontend/CompilationStencil.h" // frontend::CompilationStencil
#include "gc/Allocator.h"
#include "gc/Zone.h"
#include "jit/BaselineJIT.h"
#include "jit/Disassemble.h"
#include "jit/InlinableNatives.h"
#include "jit/Invalidation.h"
#include "jit/Ion.h"
#include "jit/JitOptions.h"
#include "jit/JitRuntime.h"
#include "jit/TrialInlining.h"
#include "js/Array.h" // JS::NewArrayObject
@ -86,6 +90,7 @@
# include "unicode/utypes.h"
# include "unicode/uversion.h"
#endif
#include "util/DifferentialTesting.h"
#include "util/StringBuffer.h"
#include "util/Text.h"
#include "vm/AsyncFunction.h"
@ -125,7 +130,6 @@
using namespace js;
using mozilla::ArrayLength;
using mozilla::AssertedCast;
using mozilla::AsWritableChars;
using mozilla::Maybe;
@ -183,6 +187,12 @@ static bool GetRealmConfiguration(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
bool topLevelAwait = cx->options().topLevelAwait();
if (!JS_SetProperty(cx, info, "topLevelAwait",
topLevelAwait ? TrueHandleValue : FalseHandleValue)) {
return false;
}
bool offThreadParseGlobal = js::UseOffThreadParseGlobal();
if (!JS_SetProperty(
cx, info, "offThreadParseGlobal",
@ -415,15 +425,6 @@ static bool GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
#ifdef JS_MORE_DETERMINISTIC
value = BooleanValue(true);
#else
value = BooleanValue(false);
#endif
if (!JS_SetProperty(cx, info, "more-deterministic", value)) {
return false;
}
#ifdef MOZ_PROFILING
value = BooleanValue(true);
#else
@ -493,21 +494,10 @@ static bool IsLCovEnabled(JSContext* cx, unsigned argc, Value* vp) {
return true;
}
static bool IsTypeInferenceEnabled(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
// TODO(no-TI): remove testing function.
args.rval().setBoolean(false);
return true;
}
static bool TrialInline(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setUndefined();
if (!jit::JitOptions.warpBuilder) {
return true;
}
FrameIter iter(cx);
if (iter.done() || !iter.isBaseline() || iter.realm() != cx->realm()) {
return true;
@ -556,7 +546,7 @@ static bool GC(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
} else if (arg.isObject()) {
PrepareZoneForGC(UncheckedUnwrap(&arg.toObject())->zone());
PrepareZoneForGC(cx, UncheckedUnwrap(&arg.toObject())->zone());
zone = true;
}
}
@ -585,9 +575,7 @@ static bool GC(JSContext* cx, unsigned argc, Value* vp) {
}
}
#ifndef JS_MORE_DETERMINISTIC
size_t preBytes = cx->runtime()->gc.heapSize.bytes();
#endif
if (zone) {
PrepareForDebugGC(cx->runtime());
@ -598,10 +586,10 @@ static bool GC(JSContext* cx, unsigned argc, Value* vp) {
JS::NonIncrementalGC(cx, gckind, reason);
char buf[256] = {'\0'};
#ifndef JS_MORE_DETERMINISTIC
SprintfLiteral(buf, "before %zu, after %zu\n", preBytes,
cx->runtime()->gc.heapSize.bytes());
#endif
if (!js::SupportDifferentialTesting()) {
SprintfLiteral(buf, "before %zu, after %zu\n", preBytes,
cx->runtime()->gc.heapSize.bytes());
}
return ReturnStringCopy(cx, args, buf);
}
@ -624,7 +612,10 @@ static bool MinorGC(JSContext* cx, unsigned argc, Value* vp) {
_("gcBytes", JSGC_BYTES, false) \
_("nurseryBytes", JSGC_NURSERY_BYTES, false) \
_("gcNumber", JSGC_NUMBER, false) \
_("mode", JSGC_MODE, true) \
_("majorGCNumber", JSGC_MAJOR_GC_NUMBER, false) \
_("minorGCNumber", JSGC_MINOR_GC_NUMBER, false) \
_("incrementalGCEnabled", JSGC_INCREMENTAL_GC_ENABLED, true) \
_("perZoneGCEnabled", JSGC_PER_ZONE_GC_ENABLED, true) \
_("unusedChunks", JSGC_UNUSED_CHUNKS, false) \
_("totalChunks", JSGC_TOTAL_CHUNKS, false) \
_("sliceTimeBudgetMS", JSGC_SLICE_TIME_BUDGET_MS, true) \
@ -684,18 +675,17 @@ static bool GCParameter(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
size_t paramIndex = 0;
for (;; paramIndex++) {
if (paramIndex == ArrayLength(paramMap)) {
JS_ReportErrorASCII(
cx, "the first argument must be one of:" GC_PARAMETER_ARGS_LIST);
return false;
}
if (JS_LinearStringEqualsAscii(linearStr, paramMap[paramIndex].name)) {
break;
}
const auto* ptr = std::find_if(
std::begin(paramMap), std::end(paramMap), [&](const auto& param) {
return JS_LinearStringEqualsAscii(linearStr, param.name);
});
if (ptr == std::end(paramMap)) {
JS_ReportErrorASCII(
cx, "the first argument must be one of:" GC_PARAMETER_ARGS_LIST);
return false;
}
const ParamInfo& info = paramMap[paramIndex];
const ParamInfo& info = *ptr;
JSGCParamKey param = info.param;
// Request mode.
@ -853,12 +843,26 @@ static bool WasmGcEnabled(JSContext* cx, unsigned argc, Value* vp) {
return true;
}
static bool WasmExceptionsEnabled(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::ExceptionsAvailable(cx));
return true;
}
static bool WasmMultiValueEnabled(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::MultiValuesAvailable(cx));
return true;
}
#ifdef ENABLE_WASM_SIMD
static bool WasmSimdSupported(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::SimdAvailable(cx));
return true;
}
#endif
static bool WasmCompilersPresent(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
@ -1559,6 +1563,81 @@ static bool VerifyPostBarriers(JSContext* cx, unsigned argc, Value* vp) {
return true;
}
static bool CurrentGC(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 0) {
RootedObject callee(cx, &args.callee());
ReportUsageErrorASCII(cx, callee, "Too many arguments");
return false;
}
RootedObject result(cx, JS_NewPlainObject(cx));
if (!result) {
return false;
}
js::gc::GCRuntime& gc = cx->runtime()->gc;
const char* state = StateName(gc.state());
RootedString str(cx, JS_NewStringCopyZ(cx, state));
if (!str) {
return false;
}
RootedValue val(cx, StringValue(str));
if (!JS_DefineProperty(cx, result, "incrementalState", val,
JSPROP_ENUMERATE)) {
return false;
}
if (gc.state() == js::gc::State::Sweep) {
val = Int32Value(gc.getCurrentSweepGroupIndex());
if (!JS_DefineProperty(cx, result, "sweepGroup", val, JSPROP_ENUMERATE)) {
return false;
}
}
val = BooleanValue(gc.isShrinkingGC());
if (!JS_DefineProperty(cx, result, "isShrinking", val, JSPROP_ENUMERATE)) {
return false;
}
val = Int32Value(gc.gcNumber());
if (!JS_DefineProperty(cx, result, "number", val, JSPROP_ENUMERATE)) {
return false;
}
val = Int32Value(gc.minorGCCount());
if (!JS_DefineProperty(cx, result, "minorCount", val, JSPROP_ENUMERATE)) {
return false;
}
val = Int32Value(gc.majorGCCount());
if (!JS_DefineProperty(cx, result, "majorCount", val, JSPROP_ENUMERATE)) {
return false;
}
val = BooleanValue(gc.isFullGc());
if (!JS_DefineProperty(cx, result, "isFull", val, JSPROP_ENUMERATE)) {
return false;
}
val = BooleanValue(gc.isCompactingGc());
if (!JS_DefineProperty(cx, result, "isCompacting", val, JSPROP_ENUMERATE)) {
return false;
}
# ifdef DEBUG
val = Int32Value(gc.marker.queuePos);
if (!JS_DefineProperty(cx, result, "queuePos", val, JSPROP_ENUMERATE)) {
return false;
}
# endif
args.rval().setObject(*result);
return true;
}
static bool DeterministicGC(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
@ -1621,7 +1700,7 @@ static bool ScheduleZoneForGC(JSContext* cx, unsigned argc, Value* vp) {
if (args[0].isObject()) {
// Ensure that |zone| is collected during the next GC.
Zone* zone = UncheckedUnwrap(&args[0].toObject())->zone();
PrepareZoneForGC(zone);
PrepareZoneForGC(cx, zone);
} else if (args[0].isString()) {
// This allows us to schedule the atoms zone for GC.
Zone* zone = args[0].toString()->zoneFromAnyThread();
@ -1630,7 +1709,7 @@ static bool ScheduleZoneForGC(JSContext* cx, unsigned argc, Value* vp) {
ReportUsageErrorASCII(cx, callee, "Specified zone not accessible for GC");
return false;
}
PrepareZoneForGC(zone);
PrepareZoneForGC(cx, zone);
} else {
RootedObject callee(cx, &args.callee());
ReportUsageErrorASCII(cx, callee,
@ -1716,6 +1795,9 @@ static bool GCSlice(JSContext* cx, unsigned argc, Value* vp) {
if (args.length() >= 1) {
uint32_t work = 0;
if (!ToUint32(cx, args[0], &work)) {
RootedObject callee(cx, &args.callee());
ReportUsageErrorASCII(cx, callee,
"The work budget parameter |n| must be an integer");
return false;
}
budget = SliceBudget(WorkBudget(work));
@ -2926,11 +3008,11 @@ static bool DumpHeap(JSContext* cx, unsigned argc, Value* vp) {
}
static bool Terminate(JSContext* cx, unsigned arg, Value* vp) {
#ifdef JS_MORE_DETERMINISTIC
// Print a message to stderr in more-deterministic builds to help jsfunfuzz
// Print a message to stderr in differential testing to help jsfunfuzz
// find uncatchable-exception bugs.
fprintf(stderr, "terminate called\n");
#endif
if (js::SupportDifferentialTesting()) {
fprintf(stderr, "terminate called\n");
}
JS_ClearPendingException(cx);
return false;
@ -3208,6 +3290,24 @@ static bool testingFunc_bailAfter(JSContext* cx, unsigned argc, Value* vp) {
return true;
}
static bool testingFunc_invalidate(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
// If the topmost frame is Ion/Warp, find the IonScript and invalidate it.
FrameIter iter(cx);
if (!iter.done() && iter.isIon()) {
while (!iter.isPhysicalJitFrame()) {
++iter;
}
if (iter.script()->hasIonScript()) {
js::jit::Invalidate(cx, iter.script());
}
}
args.rval().setUndefined();
return true;
}
static constexpr unsigned JitWarmupResetLimit = 20;
static_assert(JitWarmupResetLimit <=
unsigned(JSScript::MutableFlags::WarmupResets_MASK),
@ -3419,7 +3519,7 @@ class CloneBufferObject : public NativeObject {
const char* data = nullptr;
UniqueChars dataOwner;
uint32_t nbytes;
size_t nbytes;
if (args.get(0).isObject() && args[0].toObject().is<ArrayBufferObject>()) {
ArrayBufferObject* buffer = &args[0].toObject().as<ArrayBufferObject>();
@ -3788,16 +3888,18 @@ static bool DetachArrayBuffer(JSContext* cx, unsigned argc, Value* vp) {
static bool HelperThreadCount(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
#ifdef JS_MORE_DETERMINISTIC
// Always return 0 to get consistent output with and without --no-threads.
args.rval().setInt32(0);
#else
if (js::SupportDifferentialTesting()) {
// Always return 0 to get consistent output with and without --no-threads.
args.rval().setInt32(0);
return true;
}
if (CanUseExtraThreads()) {
args.rval().setInt32(HelperThreadState().threadCount);
} else {
args.rval().setInt32(0);
}
#endif
return true;
}
@ -3880,6 +3982,14 @@ static bool SharedArrayRawBufferRefcount(JSContext* cx, unsigned argc,
#ifdef NIGHTLY_BUILD
static bool ObjectAddress(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
if (js::SupportDifferentialTesting()) {
RootedObject callee(cx, &args.callee());
ReportUsageErrorASCII(cx, callee,
"Function unavailable in differential testing mode.");
return false;
}
if (args.length() != 1) {
RootedObject callee(cx, &args.callee());
ReportUsageErrorASCII(cx, callee, "Wrong number of arguments");
@ -3891,20 +4001,23 @@ static bool ObjectAddress(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
# ifdef JS_MORE_DETERMINISTIC
args.rval().setInt32(0);
return true;
# else
void* ptr = js::UncheckedUnwrap(&args[0].toObject(), true);
char buffer[64];
SprintfLiteral(buffer, "%p", ptr);
return ReturnStringCopy(cx, args, buffer);
# endif
}
static bool SharedAddress(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
if (js::SupportDifferentialTesting()) {
RootedObject callee(cx, &args.callee());
ReportUsageErrorASCII(cx, callee,
"Function unavailable in differential testing mode.");
return false;
}
if (args.length() != 1) {
RootedObject callee(cx, &args.callee());
ReportUsageErrorASCII(cx, callee, "Wrong number of arguments");
@ -3916,9 +4029,6 @@ static bool SharedAddress(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
# ifdef JS_MORE_DETERMINISTIC
args.rval().setString(cx->staticStrings().getUint(0));
# else
RootedObject obj(cx, CheckedUnwrapStatic(&args[0].toObject()));
if (!obj) {
ReportAccessDenied(cx);
@ -3940,7 +4050,6 @@ static bool SharedAddress(JSContext* cx, unsigned argc, Value* vp) {
}
args.rval().setString(str);
# endif
return true;
}
@ -4021,8 +4130,21 @@ static bool ThrowOutOfMemory(JSContext* cx, unsigned argc, Value* vp) {
static bool ReportLargeAllocationFailure(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
void* buf = cx->runtime()->onOutOfMemoryCanGC(
AllocFunction::Malloc, js::MallocArena, JSRuntime::LARGE_ALLOCATION);
size_t bytes = JSRuntime::LARGE_ALLOCATION;
if (args.length() >= 1) {
if (!args[0].isInt32()) {
RootedObject callee(cx, &args.callee());
ReportUsageErrorASCII(cx, callee,
"First argument must be an integer if specified.");
return false;
}
bytes = args[0].toInt32();
}
void* buf = cx->runtime()->onOutOfMemoryCanGC(AllocFunction::Malloc,
js::MallocArena, bytes);
js_free(buf);
args.rval().setUndefined();
return true;
@ -4227,7 +4349,7 @@ static bool FindPath(JSContext* cx, unsigned argc, Value* vp) {
if (!result) {
return false;
}
result->ensureDenseInitializedLength(cx, 0, length);
result->ensureDenseInitializedLength(0, length);
// Walk |nodes| and |edges| in the stored order, and construct the result
// array in start-to-target order.
@ -4420,7 +4542,7 @@ static bool ShortestPaths(JSContext* cx, unsigned argc, Value* vp) {
if (!results) {
return false;
}
results->ensureDenseInitializedLength(cx, 0, length);
results->ensureDenseInitializedLength(0, length);
for (size_t i = 0; i < length; i++) {
size_t numPaths = values[i].length();
@ -4430,7 +4552,7 @@ static bool ShortestPaths(JSContext* cx, unsigned argc, Value* vp) {
if (!pathsArray) {
return false;
}
pathsArray->ensureDenseInitializedLength(cx, 0, numPaths);
pathsArray->ensureDenseInitializedLength(0, numPaths);
for (size_t j = 0; j < numPaths; j++) {
size_t pathLength = values[i][j].length();
@ -4440,7 +4562,7 @@ static bool ShortestPaths(JSContext* cx, unsigned argc, Value* vp) {
if (!path) {
return false;
}
path->ensureDenseInitializedLength(cx, 0, pathLength);
path->ensureDenseInitializedLength(0, pathLength);
for (size_t k = 0; k < pathLength; k++) {
RootedPlainObject part(cx, NewBuiltinClassInstance<PlainObject>(cx));
@ -4540,7 +4662,6 @@ static bool EvalReturningScope(JSContext* cx, unsigned argc, Value* vp) {
}
RootedObject varObj(cx);
RootedObject lexicalScope(cx);
{
// If we're switching globals here, ExecuteInFrameScriptEnvironment will
@ -4552,35 +4673,21 @@ static bool EvalReturningScope(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
RootedObject lexicalScope(cx);
if (!js::ExecuteInFrameScriptEnvironment(cx, obj, script, &lexicalScope)) {
return false;
}
varObj = lexicalScope->enclosingEnvironment()->enclosingEnvironment();
}
RootedObject rv(cx, JS_NewPlainObject(cx));
if (!rv) {
return false;
MOZ_ASSERT(varObj->is<NonSyntacticVariablesObject>());
}
RootedValue varObjVal(cx, ObjectValue(*varObj));
if (!cx->compartment()->wrap(cx, &varObjVal)) {
return false;
}
if (!JS_SetProperty(cx, rv, "vars", varObjVal)) {
return false;
}
RootedValue lexicalScopeVal(cx, ObjectValue(*lexicalScope));
if (!cx->compartment()->wrap(cx, &lexicalScopeVal)) {
return false;
}
if (!JS_SetProperty(cx, rv, "lexicals", lexicalScopeVal)) {
return false;
}
args.rval().setObject(*rv);
args.rval().set(varObjVal);
return true;
}
@ -4680,7 +4787,7 @@ static bool ByteSizeOfScript(JSContext* cx, unsigned argc, Value* vp) {
}
RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
if (fun->isNative()) {
if (fun->isNativeFun()) {
JS_ReportErrorASCII(cx, "Argument must be a scripted function");
return false;
}
@ -4770,16 +4877,6 @@ static bool GetStringRepresentation(JSContext* cx, unsigned argc, Value* vp) {
#endif
static bool SetLazyParsingDisabled(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
bool disable = !args.hasDefined(0) || ToBoolean(args[0]);
cx->realm()->behaviors().setDisableLazyParsing(disable);
args.rval().setUndefined();
return true;
}
static bool CompileStencilXDR(JSContext* cx, uint32_t argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
@ -4814,20 +4911,21 @@ static bool CompileStencilXDR(JSContext* cx, uint32_t argc, Value* vp) {
/* TODO: StencilXDR - Add option to select between full and syntax parse. */
options.setForceFullParse();
Rooted<frontend::CompilationInfo> compilationInfo(
cx, frontend::CompilationInfo(cx, options));
if (!compilationInfo.get().input.initForGlobal(cx)) {
return false;
}
if (!frontend::CompileGlobalScriptToStencil(cx, compilationInfo.get(), srcBuf,
ScopeKind::Global)) {
Rooted<frontend::CompilationInput> input(cx,
frontend::CompilationInput(options));
auto stencil = frontend::CompileGlobalScriptToExtensibleStencil(
cx, input.get(), srcBuf, ScopeKind::Global);
if (!stencil) {
return false;
}
/* Serialize the stencil to XDR. */
JS::TranscodeBuffer xdrBytes;
if (!compilationInfo.get().serializeStencils(cx, xdrBytes)) {
return false;
{
frontend::BorrowingCompilationStencil borrowingStencil(*stencil);
if (!borrowingStencil.serializeStencils(cx, input.get(), xdrBytes)) {
return false;
}
}
/* Dump the bytes into a javascript ArrayBuffer and return a UInt8Array. */
@ -4864,21 +4962,22 @@ static bool EvalStencilXDR(JSContext* cx, uint32_t argc, Value* vp) {
const char* filename = "compileStencilXDR-DATA.js";
uint32_t lineno = 1;
/* Prepare the CompilationInfoVector for decoding. */
/* Prepare the CompilationStencil for decoding. */
CompileOptions options(cx);
options.setFileAndLine(filename, lineno);
options.setForceFullParse();
Rooted<frontend::CompilationInfoVector> compilationInfos(
cx, frontend::CompilationInfoVector(cx, options));
if (!compilationInfos.get().initial.input.initForGlobal(cx)) {
Rooted<frontend::CompilationInput> input(cx,
frontend::CompilationInput(options));
if (!input.get().initForGlobal(cx)) {
return false;
}
frontend::CompilationStencil stencil(nullptr);
/* Deserialize the stencil from XDR. */
JS::TranscodeRange xdrRange(src->dataPointer(), src->byteLength().get());
bool succeeded = false;
if (!compilationInfos.get().deserializeStencils(cx, xdrRange, &succeeded)) {
if (!stencil.deserializeStencils(cx, input.get(), xdrRange, &succeeded)) {
return false;
}
if (!succeeded) {
@ -4888,7 +4987,10 @@ static bool EvalStencilXDR(JSContext* cx, uint32_t argc, Value* vp) {
/* Instantiate the stencil. */
Rooted<frontend::CompilationGCOutput> output(cx);
if (!compilationInfos.get().instantiateStencils(cx, output.get())) {
Rooted<frontend::CompilationGCOutput> outputForDelazification(cx);
if (!frontend::CompilationStencil::instantiateStencils(
cx, input.get(), stencil, output.get(),
outputForDelazification.address())) {
return false;
}
@ -4903,16 +5005,6 @@ static bool EvalStencilXDR(JSContext* cx, uint32_t argc, Value* vp) {
return true;
}
static bool SetDiscardSource(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
bool discard = !args.hasDefined(0) || ToBoolean(args[0]);
cx->realm()->behaviors().setDiscardSource(discard);
args.rval().setUndefined();
return true;
}
class AllocationMarkerObject : public NativeObject {
public:
static const JSClass class_;
@ -5157,6 +5249,24 @@ static bool ClearMarkQueue(JSContext* cx, unsigned argc, Value* vp) {
}
#endif // DEBUG
static bool NurseryStringsEnabled(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(cx->zone()->allocNurseryStrings);
return true;
}
static bool IsNurseryAllocated(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.get(0).isGCThing()) {
JS_ReportErrorASCII(
cx, "The function takes one argument, which must be a GC thing");
return false;
}
args.rval().setBoolean(IsInsideNursery(args[0].toGCThing()));
return true;
}
static bool GetLcovInfo(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
@ -5813,9 +5923,9 @@ static bool EncodeAsUtf8InBuffer(JSContext* cx, unsigned argc, Value* vp) {
if (!array) {
return false;
}
array->ensureDenseInitializedLength(cx, 0, 2);
array->ensureDenseInitializedLength(0, 2);
uint32_t length;
size_t length;
bool isSharedMemory;
uint8_t* data;
if (!args[1].isObject() ||
@ -5938,14 +6048,12 @@ static bool BaselineCompile(JSContext* cx, unsigned argc, Value* vp) {
const char* returnedStr = nullptr;
do {
#ifdef JS_MORE_DETERMINISTIC
// In order to check for differential behaviour, baselineCompile should have
// the same output whether --no-baseline is used or not.
if (fuzzingSafe) {
returnedStr = "skipped (fuzzing-safe)";
if (js::SupportDifferentialTesting()) {
returnedStr = "skipped (differential testing)";
break;
}
#endif
AutoRealm ar(cx, script);
if (script->hasBaselineScript()) {
@ -6075,6 +6183,36 @@ static bool GetICUOptions(JSContext* cx, unsigned argc, Value* vp) {
return true;
}
static bool IsSmallFunction(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject callee(cx, &args.callee());
if (!args.requireAtLeast(cx, "IsSmallFunction", 1)) {
return false;
}
HandleValue arg = args[0];
if (!arg.isObject() || !arg.toObject().is<JSFunction>()) {
ReportUsageErrorASCII(cx, callee, "First argument must be a function");
return false;
}
RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
if (!fun->isInterpreted()) {
ReportUsageErrorASCII(cx, callee,
"First argument must be an interpreted function");
return false;
}
JSScript* script = JSFunction::getOrCreateScript(cx, fun);
if (!script) {
return false;
}
args.rval().setBoolean(jit::JitOptions.isSmallFunction(script));
return true;
}
static bool PCCountProfiling_Start(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
@ -6201,10 +6339,6 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
"isLcovEnabled()",
" Return true if JS LCov support is enabled."),
JS_FN_HELP("isTypeInferenceEnabled", ::IsTypeInferenceEnabled, 0, 0,
"isTypeInferenceEnabled()",
" Return true if Type Inference is enabled."),
JS_FN_HELP("trialInline", TrialInline, 0, 0,
"trialInline()",
" Perform trial-inlining for the caller's frame if it's a BaselineFrame."),
@ -6433,6 +6567,11 @@ gc::ZealModeHelpText),
"verifypostbarriers()",
" Does nothing (the post-write barrier verifier has been remove)."),
JS_FN_HELP("currentgc", CurrentGC, 0, 0,
"currentgc()",
" Report various information about the currently running incremental GC,\n"
" if one is running."),
JS_FN_HELP("deterministicgc", DeterministicGC, 1, 0,
"deterministicgc(true|false)",
" If true, only allow determinstic GCs to run."),
@ -6568,6 +6707,13 @@ gc::ZealModeHelpText),
" Returns a boolean indicating whether the WebAssembly threads proposal is\n"
" supported on the current device."),
#ifdef ENABLE_WASM_SIMD
JS_FN_HELP("wasmSimdSupported", WasmSimdSupported, 0, 0,
"wasmSimdSupported()",
" Returns a boolean indicating whether WebAssembly SIMD is supported by the\n"
" compilers and runtime."),
#endif
JS_FN_HELP("wasmReftypesEnabled", WasmReftypesEnabled, 1, 0,
"wasmReftypesEnabled()",
" Returns a boolean indicating whether the WebAssembly reftypes proposal is enabled."),
@ -6584,6 +6730,10 @@ gc::ZealModeHelpText),
"wasmMultiValueEnabled()",
" Returns a boolean indicating whether the WebAssembly multi-value proposal is enabled."),
JS_FN_HELP("wasmExceptionsEnabled", WasmExceptionsEnabled, 1, 0,
"wasmExceptionsEnabled()",
" Returns a boolean indicating whether the WebAssembly exceptions proposal is enabled."),
#if defined(ENABLE_WASM_SIMD) && defined(DEBUG)
JS_FN_HELP("wasmSimdAnalysis", WasmSimdAnalysis, 1, 0,
"wasmSimdAnalysis(...)",
@ -6670,6 +6820,9 @@ gc::ZealModeHelpText),
" Start a counter to bail once after passing the given amount of possible bailout positions in\n"
" ionmonkey.\n"),
JS_FN_HELP("invalidate", testingFunc_invalidate, 0, 0,
"invalidate()",
" Force an immediate invalidation (if running in Warp)."),
JS_FN_HELP("inJit", testingFunc_inJit, 0, 0,
"inJit()",
@ -6750,7 +6903,7 @@ gc::ZealModeHelpText),
" Throw out of memory exception, for OOM handling testing."),
JS_FN_HELP("reportLargeAllocationFailure", ReportLargeAllocationFailure, 0, 0,
"reportLargeAllocationFailure()",
"reportLargeAllocationFailure([bytes])",
" Call the large allocation failure callback, as though a large malloc call failed,\n"
" then return undefined. In Gecko, this sends a memory pressure notification, which\n"
" can free up some memory."),
@ -6858,16 +7011,6 @@ gc::ZealModeHelpText),
#endif
JS_FN_HELP("setLazyParsingDisabled", SetLazyParsingDisabled, 1, 0,
"setLazyParsingDisabled(bool)",
" Explicitly disable lazy parsing in the current compartment. The default is that lazy "
" parsing is not explicitly disabled."),
JS_FN_HELP("setDiscardSource", SetDiscardSource, 1, 0,
"setDiscardSource(bool)",
" Explicitly enable source discarding in the current compartment. The default is that "
" source discarding is not explicitly enabled."),
JS_FN_HELP("allocationMarker", AllocationMarker, 0, 0,
"allocationMarker([options])",
" Return a freshly allocated object whose [[Class]] name is\n"
@ -6915,6 +7058,15 @@ gc::ZealModeHelpText),
" some fidelity."),
#endif // DEBUG
JS_FN_HELP("nurseryStringsEnabled", NurseryStringsEnabled, 0, 0,
"nurseryStringsEnabled()",
" Return whether strings are currently allocated in the nursery for current\n"
" global\n"),
JS_FN_HELP("isNurseryAllocated", IsNurseryAllocated, 1, 0,
"isNurseryAllocated(thing)",
" Return whether a GC thing is nursery allocated.\n"),
JS_FN_HELP("getLcovInfo", GetLcovInfo, 1, 0,
"getLcovInfo(global)",
" Generate LCOV tracefile for the given compartment. If no global are provided then\n"
@ -7038,6 +7190,10 @@ JS_FN_HELP("getICUOptions", GetICUOptions, 0, 0,
" timezone: the ICU default time zone, e.g. 'America/Los_Angeles'\n"
" host-timezone: the host time zone, e.g. 'America/Los_Angeles'"),
JS_FN_HELP("isSmallFunction", IsSmallFunction, 1, 0,
"isSmallFunction(fun)",
" Returns true if a scripted function is small enough to be inlinable."),
JS_FS_HELP_END
};
// clang-format on

View File

@ -9,21 +9,21 @@
namespace js {
MOZ_MUST_USE bool InitTestingFunctions();
[[nodiscard]] bool InitTestingFunctions();
MOZ_MUST_USE bool DefineTestingFunctions(JSContext* cx, HandleObject obj,
bool fuzzingSafe,
bool disableOOMFunctions);
[[nodiscard]] bool DefineTestingFunctions(JSContext* cx, HandleObject obj,
bool fuzzingSafe,
bool disableOOMFunctions);
MOZ_MUST_USE bool testingFunc_assertFloat32(JSContext* cx, unsigned argc,
Value* vp);
[[nodiscard]] bool testingFunc_assertFloat32(JSContext* cx, unsigned argc,
Value* vp);
MOZ_MUST_USE bool testingFunc_assertRecoveredOnBailout(JSContext* cx,
unsigned argc,
Value* vp);
[[nodiscard]] bool testingFunc_assertRecoveredOnBailout(JSContext* cx,
unsigned argc,
Value* vp);
MOZ_MUST_USE bool testingFunc_serialize(JSContext* cx, unsigned argc,
Value* vp);
[[nodiscard]] bool testingFunc_serialize(JSContext* cx, unsigned argc,
Value* vp);
extern JSScript* TestingFunctionArgumentToScript(JSContext* cx, HandleValue v,
JSFunction** funp = nullptr);

Some files were not shown because too many files have changed in this diff Show More