/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include"builtin/TestingFunctions.h"
#include"mozilla/Atomics.h" #include"mozilla/Casting.h" #ifdef JS_HAS_INTL_API # include "mozilla/intl/ICU4CLibrary.h" # include "mozilla/intl/Locale.h" # include "mozilla/intl/String.h" # include "mozilla/intl/TimeZone.h" #endif #include"mozilla/Maybe.h" #include"mozilla/RefPtr.h" #include"mozilla/ScopeExit.h" #include"mozilla/Span.h" #include"mozilla/Sprintf.h" #include"mozilla/StringBuffer.h" #include"mozilla/ThreadLocal.h"
using mozilla::AssertedCast;
using mozilla::AsWritableChars;
using mozilla::Maybe;
using mozilla::Some;
using mozilla::Span;
using JS::AutoStableStringChars;
using JS::CompileOptions;
using JS::SliceBudget;
using JS::SourceText;
using JS::WorkBudget;
// If fuzzingSafe is set, remove functionality that could cause problems with // fuzzers. Set this via the environment variable MOZ_FUZZING_SAFE.
mozilla::Atomic<bool> js::fuzzingSafe(false);
// If disableOOMFunctions is set, disable functionality that causes artificial // OOM conditions. static mozilla::Atomic<bool> disableOOMFunctions(false);
staticbool EnvVarIsDefined(constchar* name) { constchar* value = getenv(name); return value && *value;
}
staticbool GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject callee(cx, &args.callee());
RootedObject info(cx, JS_NewPlainObject(cx)); if (!info) { returnfalse;
} if (args.length() > 1) {
ReportUsageErrorASCII(cx, callee, "Must have zero or one arguments"); returnfalse;
} if (args.length() == 1 && !args[0].isString()) {
ReportUsageErrorASCII(cx, callee, "Argument must be a string"); returnfalse;
}
if (!JS_SetProperty(cx, info, "rooting-analysis", FalseHandleValue)) { returnfalse;
}
if (!JS_SetProperty(cx, info, "exact-rooting", TrueHandleValue)) { returnfalse;
}
if (!JS_SetProperty(cx, info, "trace-jscalls-api", FalseHandleValue)) { returnfalse;
}
if (!JS_SetProperty(cx, info, "incremental-gc", TrueHandleValue)) { returnfalse;
}
if (!JS_SetProperty(cx, info, "generational-gc", TrueHandleValue)) { returnfalse;
}
if (!JS_SetProperty(cx, info, "oom-backtraces", FalseHandleValue)) { returnfalse;
}
RootedValue value(cx); #ifdef DEBUG
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "debug", value)) { returnfalse;
}
#ifdef RELEASE_OR_BETA
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "release_or_beta", value)) { returnfalse;
}
#ifdef EARLY_BETA_OR_EARLIER
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "early_beta_or_earlier", value)) { returnfalse;
}
#ifdef MOZ_CODE_COVERAGE
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "coverage", value)) { returnfalse;
}
#ifdef JS_HAS_CTYPES
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "has-ctypes", value)) { returnfalse;
}
#ifdefined(JS_CODEGEN_X86)
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "x86", value)) { returnfalse;
}
#ifdefined(JS_CODEGEN_X64)
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "x64", value)) { returnfalse;
}
#ifdef JS_CODEGEN_ARM
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "arm", value)) { returnfalse;
}
#ifdef JS_SIMULATOR_ARM
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "arm-simulator", value)) { returnfalse;
}
#ifdef ANDROID
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "android", value)) { returnfalse;
}
#ifdef XP_WIN
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "windows", value)) { returnfalse;
}
#ifdef XP_MACOSX
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "osx", value)) { returnfalse;
}
#ifdef JS_CODEGEN_ARM64
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "arm64", value)) { returnfalse;
}
#ifdef JS_SIMULATOR_ARM64
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "arm64-simulator", value)) { returnfalse;
}
#ifdef JS_CODEGEN_MIPS64
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "mips64", value)) { returnfalse;
}
#ifdef JS_SIMULATOR_MIPS64
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "mips64-simulator", value)) { returnfalse;
}
#ifdef JS_SIMULATOR
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "simulator", value)) { returnfalse;
}
#ifdef __wasi__
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "wasi", value)) { returnfalse;
}
#ifdef ENABLE_PORTABLE_BASELINE_INTERP
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "pbl", value)) { returnfalse;
}
#ifdef JS_CODEGEN_LOONG64
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "loong64", value)) { returnfalse;
}
#ifdef JS_SIMULATOR_LOONG64
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "loong64-simulator", value)) { returnfalse;
}
#ifdef JS_CODEGEN_RISCV64
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "riscv64", value)) { returnfalse;
}
#ifdef JS_SIMULATOR_RISCV64
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "riscv64-simulator", value)) { returnfalse;
}
#ifdef MOZ_ASAN
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "asan", value)) { returnfalse;
}
#ifdef MOZ_TSAN
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "tsan", value)) { returnfalse;
}
#ifdef MOZ_UBSAN
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "ubsan", value)) { returnfalse;
}
#ifdef JS_GC_ZEAL
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "has-gczeal", value)) { returnfalse;
}
#ifdef MOZ_PROFILING
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "profiling", value)) { returnfalse;
}
#ifdef MOZ_VALGRIND
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "valgrind", value)) { returnfalse;
}
#ifdef JS_HAS_INTL_API
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "intl-api", value)) { returnfalse;
}
#ifdefined(SOLARIS)
value = BooleanValue(false); #else
value = BooleanValue(true); #endif if (!JS_SetProperty(cx, info, "mapped-array-buffer", value)) { returnfalse;
}
#ifdef MOZ_MEMORY
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "moz-memory", value)) { returnfalse;
}
value.setInt32(sizeof(void*)); if (!JS_SetProperty(cx, info, "pointer-byte-size", value)) { returnfalse;
}
#ifdef ENABLE_DECORATORS
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "decorators", value)) { returnfalse;
}
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "explicit-resource-management", value)) { returnfalse;
}
value = BooleanValue(true); if (!JS_SetProperty(cx, info, "source-phase-imports", value)) { returnfalse;
}
#ifdef FUZZING
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "fuzzing-defined", value)) { returnfalse;
}
#ifdef JS_JITSPEW
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "jitspew", value)) { returnfalse;
}
#if (defined(__GNUC__) && defined(__SSE__) && defined(__x86_64__)) || \ defined(__arm__) || defined(__aarch64__) // See js.cpp "disable-main-thread-denormals" command line option.
value = BooleanValue(true); #else
value = BooleanValue(false); #endif if (!JS_SetProperty(cx, info, "can-disable-main-thread-denormals", value)) { returnfalse;
}
value = Int32Value(JSFatInlineString::MAX_LENGTH_LATIN1); if (!JS_SetProperty(cx, info, "inline-latin1-chars", value)) { returnfalse;
}
value = Int32Value(JSFatInlineString::MAX_LENGTH_TWO_BYTE); if (!JS_SetProperty(cx, info, "inline-two-byte-chars", value)) { returnfalse;
}
value = Int32Value(JSThinInlineString::MAX_LENGTH_LATIN1); if (!JS_SetProperty(cx, info, "thin-inline-latin1-chars", value)) { returnfalse;
}
value = Int32Value(JSThinInlineString::MAX_LENGTH_TWO_BYTE); if (!JS_SetProperty(cx, info, "thin-inline-two-byte-chars", value)) { returnfalse;
}
if (js::ThinInlineAtom::EverInstantiated) {
value = Int32Value(js::ThinInlineAtom::MAX_LENGTH_LATIN1); if (!JS_SetProperty(cx, info, "thin-inline-atom-latin1-chars", value)) { returnfalse;
}
value = Int32Value(js::ThinInlineAtom::MAX_LENGTH_TWO_BYTE); if (!JS_SetProperty(cx, info, "thin-inline-atom-two-byte-chars", value)) { returnfalse;
}
}
value = Int32Value(js::FatInlineAtom::MAX_LENGTH_LATIN1); if (!JS_SetProperty(cx, info, "fat-inline-atom-latin1-chars", value)) { returnfalse;
}
value = Int32Value(js::FatInlineAtom::MAX_LENGTH_TWO_BYTE); if (!JS_SetProperty(cx, info, "fat-inline-atom-two-byte-chars", value)) { returnfalse;
}
// True when the build is suitable for --strict-benchmark-mode (no debug, // sanitizers, simulators, or fuzzing). Must stay in sync with the // compile-time checks in ApplyBenchmarkMode in js.cpp.
{ bool suitable = true; #ifdef JS_DEBUG
suitable = false; #endif #ifdef MOZ_ASAN
suitable = false; #endif #ifdef MOZ_TSAN
suitable = false; #endif #ifdef MOZ_MSAN
suitable = false; #endif #ifdefined(JS_SIMULATOR)
suitable = false; #endif #ifdef FUZZING
suitable = false; #endif
value = BooleanValue(suitable);
} if (!JS_SetProperty(cx, info, "benchmark-suitable", value)) { returnfalse;
}
if (args.length() == 1) {
RootedString str(cx, ToString(cx, args[0])); if (!str) { returnfalse;
}
RootedId id(cx); if (!JS_StringToId(cx, str, &id)) { returnfalse;
}
bool hasProperty; if (JS_HasPropertyById(cx, info, id, &hasProperty) && hasProperty) { // Returning a true/false from GetProperty return GetProperty(cx, info, info, id, args.rval());
}
JSString* str = ToString(cx, args.get(0)); if (!str) { returnfalse;
}
UniqueChars name = EncodeLatin1(cx, str); if (!name) { returnfalse;
}
JSGCParamKey param; bool writable; if (!GetGCParameterInfo(name.get(), ¶m, &writable)) {
JS_ReportErrorASCII(
cx, "the first argument must be one of:" GC_PARAMETER_ARGS_LIST); returnfalse;
}
// Request mode. if (args.length() == 1) {
uint32_t value = JS_GetGCParameter(cx, param);
args.rval().setNumber(value); return true;
}
if (!writable) {
JS_ReportErrorASCII(cx, "Attempt to change read-only parameter %s",
name.get()); returnfalse;
}
if (fuzzingSafe) { // Some Params are not yet fuzzing safe and so we silently skip // changing said parameters. switch (param) { case JSGC_SEMISPACE_NURSERY_ENABLED:
args.rval().setUndefined(); return true; default: break;
}
}
if (disableOOMFunctions) { switch (param) { case JSGC_MAX_BYTES: case JSGC_MAX_NURSERY_BYTES:
args.rval().setUndefined(); return true; default: break;
}
}
double d; if (!ToNumber(cx, args[1], &d)) { returnfalse;
}
if (d < 0 || d > UINT32_MAX) {
JS_ReportErrorASCII(cx, "Parameter value out of range"); returnfalse;
}
uint32_t value = floor(d); bool ok = cx->runtime()->gc.setParameter(cx, param, value); if (!ok) {
JS_ReportErrorASCII(cx, "Parameter value out of range"); returnfalse;
}
staticbool RelazifyFunctions(JSContext* cx, unsigned argc, Value* vp) { // Relazifying functions on GC is usually only done for compartments that are // not active. To aid fuzzing, this testing function allows us to relazify // even if the compartment is active.
CallArgs args = CallArgsFromVp(argc, vp);
// Disable relazification of all scripts on stack. It is a pervasive // assumption in the engine that running scripts still have bytecode. for (AllScriptFramesIter i(cx); !i.done(); ++i) {
i.script()->clearAllowRelazify();
}
// This triplet of predicates will select zero or one baseline compiler and // zero or one optimizing compiler. bool baseline = wasm::BaselineAvailable(cx); bool ion = wasm::IonAvailable(cx); bool none = !baseline && !ion; bool tiered = baseline && ion;
JSStringBuilder result(cx); if (none && !result.append("none")) { returnfalse;
} if (baseline && !result.append("baseline")) { returnfalse;
} if (tiered && !result.append("+")) { returnfalse;
} if (ion && !result.append("ion")) { returnfalse;
} if (JSString* str = result.finishString()) {
args.rval().setString(str); return true;
} returnfalse;
}
staticbool WasmLazyTieringEnabled(JSContext* cx, unsigned argc, Value* vp) { // Note: ensure this function stays in sync with `PlatformCanTier()`.
CallArgs args = CallArgsFromVp(argc, vp); bool baseline = wasm::BaselineAvailable(cx); bool ion = wasm::IonAvailable(cx);
// Unstable API for white-box testing of SIMD optimizations. // // Current API: takes no arguments, returns a string describing the last Simd // simplification applied.
// Get the type of the value
wasm::ValType valType; if (!wasm::ToValType(cx, args.get(0), &valType)) { returnfalse;
}
// Get the array buffer for the value if (!args.get(1).isObject() ||
!args.get(1).toObject().is<ArrayBufferObject>()) {
JS_ReportErrorASCII(cx, "argument is not an array buffer"); returnfalse;
}
Rooted<ArrayBufferObject*> buffer(
cx, &args.get(1).toObject().as<ArrayBufferObject>());
// Only allow POD to be created from bytes switch (valType.kind()) { case wasm::ValType::I32: case wasm::ValType::I64: case wasm::ValType::F32: case wasm::ValType::F64: case wasm::ValType::V128: break; default:
JS_ReportErrorASCII(
cx, "invalid valtype for creating WebAssembly.Global from bytes"); returnfalse;
}
// Check we have all the bytes we need if (valType.size() != buffer->byteLength()) {
JS_ReportErrorASCII(cx, "array buffer has incorrect size"); returnfalse;
}
// Copy the bytes from buffer into a tagged val
wasm::RootedVal val(cx);
val.get().initFromRootedLocation(valType, buffer->dataPointer());
// Create the global object
RootedObject proto(
cx, GlobalObject::getOrCreatePrototype(cx, JSProto_WasmGlobal)); if (!proto) { returnfalse;
}
Rooted<WasmGlobalObject*> result(
cx, WasmGlobalObject::create(cx, val, false, proto)); if (!result) { returnfalse;
}
// Get the global value if (!args.get(0).isObject() ||
!args.get(0).toObject().is<WasmGlobalObject>()) {
JS_ReportErrorASCII(cx, "argument is not wasm value"); returnfalse;
}
Rooted<WasmGlobalObject*> global(
cx, &args.get(0).toObject().as<WasmGlobalObject>());
// Check that we have a v128 value if (global->type().kind() != wasm::ValType::V128) {
JS_ReportErrorASCII(cx, "global is not a v128 value"); returnfalse;
}
wasm::V128 v128 = global->val().get().v128();
// Get the passed interpretation of lanes
LaneInterp interp; if (!ToLaneInterp(cx, args.get(1), &interp)) { returnfalse;
}
// Get the lane to extract
int32_t lane; if (!ToInt32(cx, args.get(2), &lane)) { returnfalse;
}
// Check that the lane interp is valid if (lane < 0 || size_t(lane) >= LaneInterpLanes(interp)) {
JS_ReportErrorASCII(cx, "invalid lane for interp"); returnfalse;
}
if (a->type().kind() != b->type().kind()) {
JS_ReportErrorASCII(cx, "globals are of different kind"); returnfalse;
}
bool result; const wasm::Val& aVal = a->val().get(); const wasm::Val& bVal = b->val().get(); switch (a->type().kind()) { case wasm::ValType::I32: {
result = aVal.i32() == bVal.i32(); break;
} case wasm::ValType::I64: {
result = aVal.i64() == bVal.i64(); break;
} case wasm::ValType::F32: {
result = mozilla::BitwiseCast<uint32_t>(aVal.f32()) ==
mozilla::BitwiseCast<uint32_t>(bVal.f32()); break;
} case wasm::ValType::F64: {
result = mozilla::BitwiseCast<uint64_t>(aVal.f64()) ==
mozilla::BitwiseCast<uint64_t>(bVal.f64()); break;
} case wasm::ValType::V128: { // Don't know the interpretation of the v128, so we only can do an exact // bitwise equality. Testing code can use wasmGlobalExtractLane to // workaround this if needed.
result = aVal.v128() == bVal.v128(); break;
} case wasm::ValType::Ref: {
result = aVal.ref() == bVal.ref(); break;
} default:
JS_ReportErrorASCII(cx, "unsupported type"); returnfalse;
}
args.rval().setBoolean(result); return true;
}
// Flavors of NaN values for WebAssembly. // See // https://webassembly.github.io/spec/core/syntax/values.html#floating-point. enumclass NaNFlavor { // A canonical NaN value. // - the sign bit is unspecified, // - the 8-bit exponent is set to all 1s // - the MSB of the payload is set to 1 (a quieted NaN) and all others to 0.
Canonical, // An arithmetic NaN. This is the same as a canonical NaN including that the // payload MSB is set to 1, but one or more of the remaining payload bits MAY // BE set to 1 (a canonical NaN specifies all 0s).
Arithmetic,
};
if (!args.get(0).isObject() ||
!args.get(0).toObject().is<WasmGlobalObject>()) {
JS_ReportErrorASCII(cx, "argument is not wasm value"); returnfalse;
}
Rooted<WasmGlobalObject*> global(
cx, &args.get(0).toObject().as<WasmGlobalObject>());
NaNFlavor flavor; if (!ToNaNFlavor(cx, args.get(1), &flavor)) { returnfalse;
}
bool result; const wasm::Val& val = global->val().get(); switch (global->type().kind()) { case wasm::ValType::F32: {
result = IsNaNFlavor(mozilla::BitwiseCast<uint32_t>(val.f32()), flavor); break;
} case wasm::ValType::F64: {
result = IsNaNFlavor(mozilla::BitwiseCast<uint64_t>(val.f64()), flavor); break;
} default:
JS_ReportErrorASCII(cx, "global is not a floating point value"); returnfalse;
}
args.rval().setBoolean(result); return true;
}
if (args.length() < 1) {
JS_ReportErrorASCII(cx, "not enough arguments"); returnfalse;
} if (!args.get(0).isObject() || !args.get(0).toObject().is<JSFunction>()) {
JS_ReportErrorASCII(cx, "argument is not an object"); returnfalse;
}
RootedFunction func(cx, &args[0].toObject().as<JSFunction>()); if (!func || !func->isWasm()) {
JS_ReportErrorASCII(cx, "argument is not an exported wasm function"); returnfalse;
}
// Switch to the function's realm
AutoRealm ar(cx, func);
// Get the instance and funcIndex for calling the function
wasm::Instance& instance = func->wasmInstance();
uint32_t funcIndex = func->wasmFuncIndex();
// Set up a modified call frame following the standard JS // [callee, this, arguments...] convention.
RootedValueVector wasmCallFrame(cx);
size_t len = 2 + args.length(); if (!wasmCallFrame.resize(len)) { returnfalse;
}
wasmCallFrame[0].set(ObjectValue(*func));
wasmCallFrame[1].set(args.thisv()); // Copy over the arguments needed to invoke the provided wasm function, // skipping the wasm function we're calling that is at `args.get(0)`. for (size_t i = 1; i < args.length(); i++) {
size_t wasmArg = i - 1;
wasmCallFrame[2 + wasmArg].set(args.get(i));
}
size_t wasmArgc = argc - 1;
CallArgs wasmCallArgs(CallArgsFromVp(wasmArgc, wasmCallFrame.begin()));
// Invoke the function with the new call frame bool result = instance.callExport(cx, funcIndex, wasmCallArgs,
wasm::CoercionLevel::Lossless); // Assign the wasm rval to our rval
args.rval().set(wasmCallArgs.rval()); return result;
}
if (stableTier) {
*tier = code.stableCompleteTier();
} elseif (bestTier) {
*tier = code.bestCompleteTier();
} elseif (baselineTier) {
*tier = wasm::Tier::Baseline;
} elseif (ionTier) {
*tier = wasm::Tier::Optimized;
} else { // You can omit the argument but you can't pass just anything you like returnfalse;
}
return true;
}
staticbool WasmExtractCode(JSContext* cx, unsigned argc, Value* vp) { if (!wasm::HasSupport(cx)) {
JS_ReportErrorASCII(cx, "wasm support unavailable"); returnfalse;
}
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.get(0).isObject()) {
JS_ReportErrorASCII(cx, "argument is not an object"); returnfalse;
}
Rooted<WasmModuleObject*> module(
cx, args[0].toObject().maybeUnwrapIf<WasmModuleObject>()); if (!module) {
JS_ReportErrorASCII(cx, "argument is not a WebAssembly.Module"); returnfalse;
}
#ifdef JS_CODEGEN_ARM // The ARM32 disassembler is currently not fuzzing-safe because it doesn't // handle constant pools correctly (bug 1875363). if (fuzzingSafe) {
JS_ReportErrorASCII(cx, "disnative is not fuzzing-safe on ARM32"); returnfalse;
} #elifdefined(JS_CODEGEN_RISCV64) // The riscv64 disassembler is currently not fuzzing-safe because it doesn't // handle constant pools correctly (bug 1987559). if (fuzzingSafe) {
JS_ReportErrorASCII(cx, "disnative is not fuzzing-safe on riscv64"); returnfalse;
} #endif
// Dump the raw code to a file before disassembling in case // finishString triggers a GC and discards the jitcode. if (!fuzzingSafe && args.length() > 1 && args[1].isString()) {
RootedString str(cx, args[1].toString());
JS::UniqueChars fileNameBytes = JS_EncodeStringToUTF8(cx, str);
constchar* fileName = fileNameBytes.get(); if (!fileName) {
ReportOutOfMemory(cx); returnfalse;
}
FILE* f = fopen(fileName, "w"); if (!f) {
JS_ReportErrorASCII(cx, "Could not open file for writing."); returnfalse;
}
uintptr_t expected_length = reinterpret_cast<uintptr_t>(jit_end) -
reinterpret_cast<uintptr_t>(jit_begin); if (expected_length != fwrite(jit_begin, jit_end - jit_begin, 1, f)) {
JS_ReportErrorASCII(cx, "Did not write all function bytes to the file.");
fclose(f); returnfalse;
}
fclose(f);
}
disasmPrinter.set(&sprinter); auto onFinish = mozilla::MakeScopeExit([&] { disasmPrinter.set(nullptr); });
if (!fun->hasJitScript()) {
args.rval().setUndefined(); return true;
}
#ifdef JS_CODEGEN_ARM // The ARM32 disassembler is currently not fuzzing-safe because it doesn't // handle constant pools correctly (bug 1875363). if (fuzzingSafe) {
JS_ReportErrorASCII(cx, "disblic is not fuzzing-safe on ARM32"); returnfalse;
} #elifdefined(JS_CODEGEN_RISCV64) // The riscv64 disassembler is currently not fuzzing-safe because it doesn't // handle constant pools correctly (bug 1987559). if (fuzzingSafe) {
JS_ReportErrorASCII(cx, "disblic is not fuzzing-safe on riscv64"); returnfalse;
} #endif
RootedScript script(cx, fun->nonLazyScript());
jit::ICScript* icScript = script->jitScript()->icScript(); for (uint32_t i = 0; i < icScript->numICEntries(); i++) {
jit::ICEntry& entry = icScript->icEntry(i);
jit::ICStub* stub = entry.firstStub();
if (!args.get(0).isObject()) {
JS_ReportErrorASCII(cx, "argument is not an object"); returnfalse;
}
Rooted<WasmModuleObject*> module(
cx, args[0].toObject().maybeUnwrapIf<WasmModuleObject>()); if (!module) {
JS_ReportErrorASCII(cx, "argument is not a WebAssembly.Module"); returnfalse;
}
bool b; switch (flag) { case Flag::Tier2Complete:
b = !module->module().testingTier2Active(); break; case Flag::Deserialized:
b = module->module().loggingDeserialized(); break; case Flag::ParsedBranchHints:
b = !module->module().codeMeta().branchHints.failedParse(); break;
}
if (!args.get(0).isObject()) {
JS_ReportErrorASCII(cx, "argument is not an object"); returnfalse;
}
if (args[0].toObject().is<WasmModuleObject>()) {
HashMap<constchar*, uint32_t, mozilla::CStringHasher, SystemAllocPolicy>
hashmap = args[0]
.toObject()
.as<WasmModuleObject>()
.module()
.code()
.metadataAnalysis(cx); if (hashmap.empty()) {
JS_ReportErrorASCII(cx, "Metadata analysis has failed"); returnfalse;
}
// metadataAnalysis returned a map of {key, value} with various statistics // convert it into a dictionary to be used by JS
Rooted<IdValueVector> props(cx, IdValueVector(cx));
for (auto iter = hashmap.iter(); !iter.done(); iter.next()) { constauto* key = iter.get().key(); auto value = iter.get().value();
JSString* string = JS_NewStringCopyZ(cx, key); if (!string) { returnfalse;
}
if (!props.append(
IdValuePair(NameToId(string->asLinear().toPropertyName(cx)),
NumberValue(value)))) { returnfalse;
}
}
if (!args.requireAtLeast(cx, "wasmGcReadField", 2)) { returnfalse;
}
if (!args[0].isObject() || !args[0].toObject().is<WasmGcObject>()) {
ReportUsageErrorASCII(cx, callee, "First argument must be a WebAssembly GC object"); returnfalse;
}
int32_t fieldIndex; if (!JS::ToInt32(cx, args[1], &fieldIndex) || fieldIndex < 0) {
ReportUsageErrorASCII(cx, callee, "Second argument must be a non-negative integer"); returnfalse;
}
if (!args.requireAtLeast(cx, "wasmGcArrayLength", 1)) { returnfalse;
}
if (!args[0].isObject() || !args[0].toObject().is<WasmArrayObject>()) {
ReportUsageErrorASCII(cx, callee, "First argument must be a WebAssembly GC array"); returnfalse;
}
staticbool IsLazyFunction(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); if (args.length() != 1) {
JS_ReportErrorASCII(cx, "The function takes exactly one argument."); returnfalse;
} if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
JS_ReportErrorASCII(cx, "The first argument should be a function."); returnfalse;
}
JSFunction* fun = &args[0].toObject().as<JSFunction>();
args.rval().setBoolean(fun->isInterpreted() && !fun->hasBytecode()); return true;
}
staticbool IsRelazifiableFunction(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); if (args.length() != 1) {
JS_ReportErrorASCII(cx, "The function takes exactly one argument."); returnfalse;
} if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
JS_ReportErrorASCII(cx, "The first argument should be a function."); returnfalse;
}
JSFunction* fun = &args[0].toObject().as<JSFunction>();
args.rval().setBoolean(fun->hasBytecode() &&
fun->nonLazyScript()->allowRelazify()); return true;
}
staticbool IsCollectingDelazifications(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); if (args.length() != 1) {
JS_ReportErrorASCII(cx, "The function takes exactly one argument."); returnfalse;
}
if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
JS_ReportErrorASCII(cx, "The first argument should be a function."); returnfalse;
}
if (fuzzingSafe) { // When running code concurrently to fill-up the stencil cache, the content // is not garanteed to be present.
args.rval().setBoolean(false); return true;
}
staticbool IsDelazificationsPopulated(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); if (args.length() != 1) {
JS_ReportErrorASCII(cx, "The function takes exactly one argument."); returnfalse;
}
if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
JS_ReportErrorASCII(cx, "The first argument should be a function."); returnfalse;
}
if (fuzzingSafe) { // When running code concurrently to fill-up the stencil cache, the content // is not garanteed to be present.
args.rval().setBoolean(false); return true;
}
JSFunction* fun = &args[0].toObject().as<JSFunction>();
BaseScript* script = fun->baseScript();
RefPtr<frontend::InitialStencilAndDelazifications> stencils =
script->sourceObject()->maybeGetStencils(); if (!stencils) {
args.rval().setBoolean(false); return true;
}
staticbool WaitForDelazificationOf(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); if (args.length() != 1) {
JS_ReportErrorASCII(cx, "The function takes exactly one argument."); returnfalse;
}
if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
JS_ReportErrorASCII(cx, "The first argument should be a function."); returnfalse;
}
args.rval().setUndefined();
JSFunction* fun = &args[0].toObject().as<JSFunction>();
BaseScript* script = fun->baseScript();
if (!script->sourceObject()->isSharingDelazifications()) { return true;
}
AutoLockHelperThreadState lock; if (!HelperThreadState().isInitialized(lock)) { return true;
}
while (true) { const frontend::CompilationStencil* stencil =
stencils->getDelazificationFor(script->extent()); if (stencil) { break;
}
HelperThreadState().wait(lock);
} return true;
}
staticbool HasSameBytecodeData(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); if (args.length() != 2) {
JS_ReportErrorASCII(cx, "The function takes exactly two argument."); returnfalse;
}
auto GetSharedData = [](JSContext* cx,
HandleValue v) -> SharedImmutableScriptData* { if (!v.isObject()) {
JS_ReportErrorASCII(cx, "The arguments must be interpreted functions."); return nullptr;
}
RootedObject obj(cx, CheckedUnwrapDynamic(&v.toObject(), cx)); if (!obj) { return nullptr;
}
if (!obj->is<JSFunction>() || !obj->as<JSFunction>().isInterpreted()) {
JS_ReportErrorASCII(cx, "The arguments must be interpreted functions."); return nullptr;
}
for (unsigned i = 0; i < args.length(); i++) { if (args[i].isObject()) { if (!cx->runtime()->gc.selectForMarking(&args[i].toObject())) {
ReportOutOfMemory(cx); returnfalse;
}
}
}
if (args.length() != 1) {
RootedObject callee(cx, &args.callee());
ReportUsageErrorASCII(cx, callee, "Expecting a single argument"); returnfalse;
}
if (args[0].isObject()) { // Ensure that |zone| is collected during the next GC.
Zone* zone = UncheckedUnwrap(&args[0].toObject())->zone();
PrepareZoneForGC(cx, zone);
} elseif (args[0].isString()) { // This allows us to schedule the atoms zone for GC.
Zone* zone = args[0].toString()->zoneFromAnyThread(); if (!CurrentThreadCanAccessZone(zone)) {
RootedObject callee(cx, &args.callee());
ReportUsageErrorASCII(cx, callee, "Specified zone not accessible for GC"); returnfalse;
}
PrepareZoneForGC(cx, zone);
} else {
RootedObject callee(cx, &args.callee());
ReportUsageErrorASCII(cx, callee, "Bad argument - expecting object or string"); returnfalse;
}
RootedObject callee(cx, &args.callee()); if (args.length() != 2) {
ReportUsageErrorASCII(cx, callee, "Expected two arguments"); returnfalse;
}
if (!args[0].isObject()) {
ReportUsageErrorASCII(cx, callee, "Expected an object as the first argument"); returnfalse;
}
Zone* zone = UncheckedUnwrap(&args[0].toObject())->zone();
Maybe<bool> result;
gc::GCRuntime* gc = &cx->runtime()->gc; if (args[1].isSymbol()) {
result = Some(gc->atomMarking.atomIsMarked(zone, args[1].toSymbol()));
} elseif (args[1].isString()) {
JSString* str = args[1].toString(); if (str->isAtom()) {
result = Some(gc->atomMarking.atomIsMarked(zone, &str->asAtom()));
}
}
if (result.isNothing()) {
ReportUsageErrorASCII(cx, callee, "Expected an atom as the second argument"); returnfalse;
}
if (args.length() != 1 || !args[0].isGCThing() ||
!args[0].toGCThing()->zoneFromAnyThread()->isAtomsZone()) {
ReportUsageErrorASCII(cx, callee, "Expected an atom as the single argument"); returnfalse;
}
gc::TenuredCell* atom = &args[0].toGCThing()->asTenured(); if ((atom->is<JSString>() &&
atom->as<JSString>()->isPermanentAndMayBeShared()) ||
(atom->is<JS::Symbol>() &&
atom->as<JS::Symbol>()->isPermanentAndMayBeShared())) {
ReportUsageErrorASCII(
cx, callee, "Atom marking bitmap is not used for permanent atoms"); returnfalse;
}
if (atom->is<JSString>() && atom->as<JSString>()->asAtom().isPinned()) {
ReportUsageErrorASCII(cx, callee, "Atom marking bitmap is not used for pinned atoms"); returnfalse;
}
if (args.length() != 2) {
ReportUsageErrorASCII(cx, callee, "Expected two arguments"); returnfalse;
}
if (!args[0].isObject()) {
ReportUsageErrorASCII(cx, callee, "Expected an object as the first argument"); returnfalse;
}
Zone* zone = UncheckedUnwrap(&args[0].toObject())->zone();
if (!args[1].isInt32() || args[1].toInt32() < 0) {
ReportUsageErrorASCII(cx, callee, "Expected a positive integer as the second argument"); returnfalse;
}
size_t index = args[1].toInt32();
gc::GCRuntime* gc = &cx->runtime()->gc;
gc::CellColor color = gc->atomMarking.getAtomMarkColorForIndex(zone, index);
RootedString name(cx, JS_NewStringCopyZ(cx, gc::CellColorName(color))); if (!name) { returnfalse;
}
int32_t seed; if (!ToInt32(cx, args[0], &seed)) { returnfalse;
}
// Either one or the other of the seed arguments must be non-zero; // make this true no matter what value 'seed' has.
cx->realm()->savedStacks().setRNGState(seed, (seed + 1) * 33); return true;
}
if (args.length() != 1) {
JS_ReportErrorASCII(cx, "The function takes exactly one argument."); returnfalse;
} if (!args[0].isObject() || !IsCallable(args[0])) {
JS_ReportErrorASCII(cx, "The first argument should be a function."); returnfalse;
}
if (args.length() != 3) {
JS_ReportErrorASCII(cx, "The function takes exactly three arguments."); returnfalse;
} if (!args[0].isObject() || !IsCallable(args[0])) {
JS_ReportErrorASCII(cx, "The first argument should be a function."); returnfalse;
} if (!args[1].isObject() || !args[1].toObject().is<SavedFrame>()) {
JS_ReportErrorASCII(cx, "The second argument should be a SavedFrame."); returnfalse;
} if (!args[2].isString() || args[2].toString()->empty()) {
JS_ReportErrorASCII(cx, "The third argument should be a non-empty string."); returnfalse;
}
// Accept all filenames that start with "safe". In system code also accept // filenames starting with "system". auto testCb = [](JSContext* cx, constchar* filename) -> bool { if (strstr(filename, "safe") == filename) { return true;
} if (cx->realm()->isSystem() && strstr(filename, "system") == filename) { return true;
}
// Define |this|. We can't expose the MagicValue to JS, so we use // "<is_constructing>" in that case.
Rooted<Value> thisv(cx, args.thisv()); if (thisv.isMagic(JS_IS_CONSTRUCTING)) {
JSString* str = NewStringCopyZ<CanGC>(cx, "<is_constructing>"); if (!str) { returnfalse;
}
thisv.setString(str);
} if (!DefineDataProperty(cx, obj, cx->names().this_, thisv,
JSPROP_ENUMERATE)) { returnfalse;
}
Rooted<NativeObject*> obj(cx, &args[0].toObject().as<NativeObject>()); if (!NativeObject::setHasObjectFuse(cx, obj)) { returnfalse;
}
// The ObjectFuse is normally created lazily the first time it's needed for an // IC stub, but here we create it eagerly to simplify tests. if (!cx->zone()->objectFuses.getOrCreate(cx, obj)) { returnfalse;
}
Rooted<PlainObject*> props(cx, NewPlainObjectWithProto(cx, nullptr)); if (!props) { returnfalse;
}
// Add all properties to a Vector so that we can iterate over them in property // definition order.
Rooted<PropertyInfoWithKeyVector> propsVec(cx, PropertyInfoWithKeyVector(cx)); for (ShapePropertyIter<CanGC> iter(cx, obj->shape()); !iter.done(); iter++) { if (iter->hasSlot() && ObjectFuse::tracksPropertyKey(iter->key()) &&
!propsVec.append(*iter)) { returnfalse;
}
}
// For each property, define a property on |props| with the value a string // describing the property's current state (eg "Constant"). for (size_t i = propsVec.length(); i > 0; i--) {
PropertyInfoWithKey prop = propsVec[i - 1];
Rooted<PropertyKey> key(cx, prop.key());
JSString* s =
NewStringCopyZ<CanGC>(cx, objFuse->getPropertyStateString(prop)); if (!s) { returnfalse;
};
val.setString(s); if (!JS_DefinePropertyById(cx, props, key, val, JSPROP_ENUMERATE)) { returnfalse;
}
} if (!JS_DefineProperty(cx, result, "properties", props, JSPROP_ENUMERATE)) { returnfalse;
}
if (!ToIndex(cx, args.get(1), &indexStart)) { returnfalse;
}
Rooted<Value> options(cx); if (args.get(2).isObject()) {
options = args[2];
} else {
uint64_t idx; if (args.hasDefined(2)) { if (!ToIndex(cx, args.get(2), &idx)) { returnfalse;
}
indexEnd.emplace(idx);
}
options = args.get(3);
}
if (options.isObject()) {
Rooted<Value> v(cx);
Rooted<JSObject*> optObj(cx, &options.toObject()); if (!JS_GetProperty(cx, optObj, "tenured", &v)) { returnfalse;
} if (v.isBoolean()) {
requiredHeap.emplace(v.toBoolean() ? gc::Heap::Tenured
: gc::Heap::Default);
heap = *requiredHeap;
} if (!JS_GetProperty(cx, optObj, "suppress-contraction", &v)) { returnfalse;
}
suppressContraction = ToBoolean(v);
}
if (indexEnd.isNothing()) { // Read the length now that no more JS code can run.
indexEnd.emplace(src->length());
} if (indexStart > src->length() || *indexEnd > src->length() ||
indexStart >= *indexEnd) {
JS_ReportErrorASCII(cx, "invalid dependent string bounds"); returnfalse;
} if (!src->ensureLinear(cx)) { returnfalse;
}
Rooted<JSString*> result(
cx, js::NewDependentStringForTesting(
cx, src, indexStart, *indexEnd - indexStart,
suppressContraction ? JS::ContractBaseChain::AllowLong
: JS::ContractBaseChain::Contract,
heap)); if (!result) { returnfalse;
} if (!result->isDependent()) {
JS_ReportErrorASCII(cx, "resulting string is not dependent (too short?)"); returnfalse;
}
if (requiredHeap.isSome()) { if ((*requiredHeap == gc::Heap::Tenured) != result->isTenured()) { if (result->isTenured()) {
JS_ReportErrorASCII(cx, "nursery string created in tenured heap"); returnfalse;
} else {
JS_ReportErrorASCII(cx, "tenured string created in nursery heap"); returnfalse;
}
}
}
args.rval().setString(result); return true;
}
// Warning! This will let you create ropes that I'm not sure would be possible // otherwise, specifically: // // - a rope with a zero-length child // - a rope that would fit into an inline string // staticbool NewRope(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.get(0).isString() || !args.get(1).isString()) {
JS_ReportErrorASCII(cx, "newRope requires two string arguments."); returnfalse;
}
gc::Heap heap = js::gc::Heap::Default; if (args.get(2).isObject()) {
RootedObject options(cx, &args[2].toObject());
RootedValue v(cx); if (!JS_GetProperty(cx, options, "nursery", &v)) { returnfalse;
} if (!v.isUndefined() && !ToBoolean(v)) {
heap = js::gc::Heap::Tenured;
}
}
// Disallow creating ropes where one side is empty. if (left->empty() || right->empty()) {
JS_ReportErrorASCII(cx, "rope child mustn't be the empty string"); returnfalse;
}
// Disallow creating ropes which fit into inline strings. if (left->hasLatin1Chars() && right->hasLatin1Chars()) { if (JSInlineString::lengthFits<JS::Latin1Char>(length)) {
JS_ReportErrorASCII(cx, "Cannot create small non-inline ropes"); returnfalse;
}
} else { if (JSInlineString::lengthFits<char16_t>(length)) {
JS_ReportErrorASCII(cx, "Cannot create small non-inline ropes"); returnfalse;
}
}
staticbool CheckCanSimulateOOM(JSContext* cx) { if (js::oom::GetThreadType() != js::THREAD_TYPE_MAIN) {
JS_ReportErrorASCII(
cx, "Simulated OOM failure is only supported on the main thread"); returnfalse;
}
// Iterative failure testing: test a function by simulating failures at indexed // locations throughout the normal execution path and checking that the // resulting state of the environment is consistent with the error result. // // For example, trigger OOM at every allocation point and test that the function // either recovers and succeeds or raises an exception and fails.
bool IterativeFailureTest::test() { if (disableOOMFunctions) { return true;
}
if (!setup()) { returnfalse;
}
auto onExit = mozilla::MakeScopeExit([this] { teardown(); });
for (unsigned thread = threadStart; thread <= threadEnd; thread++) { if (!testThread(thread)) { returnfalse;
}
}
return true;
}
bool IterativeFailureTest::setup() { if (!CheckCanSimulateOOM(cx)) { returnfalse;
}
// Disallow nested tests. if (cx->runningOOMTest) {
JS_ReportErrorASCII(
cx, "Nested call to iterative failure test is not allowed."); returnfalse;
}
cx->runningOOMTest = true;
// Delazify the function here if necessary so we don't end up testing that. if (testFunction->isInterpreted() &&
!JSFunction::getOrCreateScript(cx, testFunction)) { returnfalse;
}
RootedValue result(cx); bool ok = JS_CallFunction(cx, cx->global(), testFunction,
HandleValueArray::empty(), &result);
failureWasSimulated = simulator.stopSimulating();
if (ok && cx->isExceptionPending()) {
MOZ_CRASH( "Thunk execution succeeded but an exception was raised - missing error " "check?");
}
if (!ok && !cx->isExceptionPending() && expectExceptionOnFailure) {
MOZ_CRASH( "Thunk execution failed but no exception was raised - missing call to " "js::ReportOutOfMemory()?");
}
// Note that it is possible that the function throws an exception unconnected // to the simulated failure, in which case we ignore it. More correct would be // to have the caller pass some kind of exception specification and to check // the exception against it. if (!failureWasSimulated && cx->isExceptionPending()) { if (!cx->getPendingException(exception)) { returnfalse;
}
}
cx->clearPendingException();
// Some tests create a new compartment or zone on every iteration. Our GC is // triggered by GC allocations and not by number of compartments or zones, so // these won't normally get cleaned up. The check here stops some tests // running out of memory. ("Gentlemen, you can't fight in here! This is the // War oom!") if (CountCompartments(cx) > compartmentCount + 100) {
JS_GC(cx);
compartmentCount = CountCompartments(cx);
}
}
bool IterativeFailureTest::initParams(const CallArgs& args) { if (args.length() < 1 || args.length() > 2) {
JS_ReportErrorASCII(cx, "function takes between 1 and 2 arguments."); returnfalse;
}
if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
JS_ReportErrorASCII(cx, "The first argument must be the function to test."); returnfalse;
}
testFunction = &args[0].toObject().as<JSFunction>();
if (args.length() == 2) { if (args[1].isBoolean()) {
expectExceptionOnFailure = args[1].toBoolean();
} elseif (args[1].isObject()) {
RootedObject options(cx, &args[1].toObject());
RootedValue value(cx);
if (!JS_GetProperty(cx, options, "expectExceptionOnFailure", &value)) { returnfalse;
} if (!value.isUndefined()) {
expectExceptionOnFailure = ToBoolean(value);
}
if (!JS_GetProperty(cx, options, "keepFailing", &value)) { returnfalse;
} if (!value.isUndefined()) {
keepFailing = ToBoolean(value);
}
} else {
JS_ReportErrorASCII(
cx, "The optional second argument must be an object or a boolean."); returnfalse;
}
}
// There are some places where we do fail without raising an exception, so // we can't expose this to the fuzzers by default. if (fuzzingSafe) {
expectExceptionOnFailure = false;
}
// Test all threads by default except worker threads.
threadStart = oom::FirstThreadTypeToTest;
threadEnd = oom::LastThreadTypeToTest;
// Test a single thread type if specified by the OOM_THREAD environment // variable. int threadOption = 0; if (EnvVarAsInt("OOM_THREAD", &threadOption)) { if (threadOption < oom::FirstThreadTypeToTest ||
threadOption > oom::LastThreadTypeToTest) {
JS_ReportErrorASCII(cx, "OOM_THREAD value out of range."); returnfalse;
}
staticbool GetWaitForAllPromise(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); if (!args.requireAtLeast(cx, "getWaitForAllPromise", 1)) { returnfalse;
} if (!args[0].isObject() || !args[0].toObject().is<ArrayObject>() ||
args[0].toObject().as<NativeObject>().isIndexed()) {
JS_ReportErrorASCII(
cx, "first argument must be a dense Array of Promise objects"); returnfalse;
}
Rooted<NativeObject*> list(cx, &args[0].toObject().as<NativeObject>());
RootedObjectVector promises(cx);
uint32_t count = list->getDenseInitializedLength(); if (!promises.resize(count)) { returnfalse;
}
for (uint32_t i = 0; i < count; i++) {
RootedValue elem(cx, list->getDenseElement(i)); if (!elem.isObject() || !elem.toObject().is<PromiseObject>()) {
JS_ReportErrorASCII(
cx, "Each entry in the passed-in Array must be a Promise"); returnfalse;
}
promises[i].set(&elem.toObject());
}
RootedObject resultPromise(cx, JS::GetWaitForAllPromise(cx, promises)); if (!resultPromise) { returnfalse;
}
// If profiler sampling has been suppressed, return an empty // stack. if (!cx->isProfilerSamplingEnabled()) {
args.rval().setObject(*stack); return true;
}
// NOP when not in IonMonkey
args.rval().setUndefined(); return true;
}
staticbool testingFunc_bailAfter(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); if (args.length() != 1 || !args[0].isInt32() || args[0].toInt32() < 0) {
JS_ReportErrorASCII(
cx, "Argument must be a positive number that fits in an int32"); returnfalse;
}
#ifdef DEBUG if (auto* jitRuntime = cx->runtime()->jitRuntime()) {
uint32_t bailAfter = args[0].toInt32(); bool enableBailAfter = bailAfter > 0; if (jitRuntime->ionBailAfterEnabled() != enableBailAfter) { // Force JIT code to be recompiled with (or without) instrumentation.
ReleaseAllJITCode(cx->gcContext());
jitRuntime->setIonBailAfterEnabled(enableBailAfter);
}
jitRuntime->setIonBailAfterCounter(bailAfter);
} #endif
// 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());
}
}
if (!jit::IsBaselineJitEnabled(cx)) {
return ReturnStringCopy(cx, args, "Baseline is disabled.");
}
// Use frame iterator to inspect caller.
FrameIter iter(cx);
// We may be invoked directly, not in a JS context, e.g. if inJit is added as
// a callback on the event queue. if (iter.done()) {
args.rval().setBoolean(false);
return true;
}
if (iter.hasScript()) {
// Detect repeated attempts to compile, resetting the counter if inJit
// succeeds. Note: This script may have be inlined into its caller. if (iter.isJSJit()) {
iter.script()->resetWarmUpResetCounter();
} elseif (iter.script()->getWarmUpResetCount() >= JitWarmupResetLimit) {
return ReturnStringCopy(
cx, args, "Compilation is being repeatedly prevented. Giving up.");
}
}
// Returns true for any JIT (including WASM).
MOZ_ASSERT_IF(iter.isJSJit(), cx->currentlyRunningInJit());
args.rval().setBoolean(cx->currentlyRunningInJit());
return true;
}
if (!jit::IsIonEnabled(cx)) {
return ReturnStringCopy(cx, args, "Ion is disabled.");
}
// Use frame iterator to inspect caller.
FrameIter iter(cx);
// We may be invoked directly, not in a JS context, e.g. if inIon is added as
// a callback on the event queue. if (iter.done()) {
args.rval().setBoolean(false);
return true;
}
if (iter.hasScript()) {
// Detect repeated attempts to compile, resetting the counter if inIon
// succeeds. Note: This script may have be inlined into its caller. if (iter.isIon()) {
iter.script()->resetWarmUpResetCounter();
} elseif (!iter.script()->canIonCompile()) {
return ReturnStringCopy(cx, args, "Unable to Ion-compile this script.");
} elseif (iter.script()->getWarmUpResetCount() >= JitWarmupResetLimit) {
return ReturnStringCopy(
cx, args, "Compilation is being repeatedly prevented. Giving up.");
}
}
// A JSObject that holds structured clone data, similar to the C++ class
// JSAutoStructuredCloneBuffer.
class CloneBufferObject : public NativeObject {
static const JSPropertySpec props_[3];
// A custom object that is serializable and transferable using
// the engine's custom hooks. The callbacks log their activity
// to a JSRuntime-wide log (tagging actions with IDs to distinguish them).
class CustomSerializableObject : public NativeObject {
static const size_t ID_SLOT = 0;
static const size_t DETACHED_SLOT = 1;
static const size_t BEHAVIOR_SLOT = 2;
static const size_t NUM_SLOTS = 3;
static constexpr size_t MAX_LOG_LEN = 100;
// The activity log should be specific to a JSRuntime.
struct ActivityLog {
uint32_t buffer[MAX_LOG_LEN];
size_t length = 0;
if ((obj = aObj->maybeUnwrapIf<CustomSerializableObject>())) {
obj->log('w');
// Write a regular clone as a <tag, id> pair, followed by <0, behavior>.
// Note that transferring will communicate the behavior via a different
// mechanism.
return JS_WriteUint32Pair(w, obj->tag(), obj->id()) &&
JS_WriteUint32Pair(w, 0, static_cast<uint32_t>(obj->behavior()));
}
auto b = static_cast<Behavior>(behaviorData);
Rooted<CustomSerializableObject*> obj(
cx, Create(cx, static_cast<int32_t>(id), b)); if (!obj) {
return nullptr;
}
obj->log('r'); if (obj->behavior() == Behavior::FailDuringRead) {
JS_ReportErrorASCII(cx, "Failed as requested in read during deserialization");
return nullptr;
}
return obj;
}
if ((obj = wrapped->maybeUnwrapIf<CustomSerializableObject>())) {
obj->log('?');
// For now, all CustomSerializable objects are considered to be
// transferable.
return true;
}
int32_t id = 0; if (args.get(0).isInt32()) {
id = args[0].toInt32(); if (id < 0) {
JS_ReportErrorASCII(cx, "id out of range");
return false;
}
}
CustomSerializableObject::Behavior behavior =
CustomSerializableObject::Behavior::Nothing; if (args.get(1).isInt32()) {
int32_t iv = args[1].toInt32();
constexpr int32_t min =
static_cast<int32_t>(CustomSerializableObject::Behavior::Nothing);
constexpr int32_t max = static_cast<int32_t>(
CustomSerializableObject::Behavior::FailDuringRead); if (iv < min || iv > max) {
JS_ReportErrorASCII(cx, "behavior out of range");
return false;
}
behavior = static_cast<CustomSerializableObject::Behavior>(iv);
}
if (!args.get(0).isObject() ||
!JS::IsArrayBufferObject(&args[0].toObject())) {
js::ReportUsageErrorASCII(cx, callee, "Argument must be an ArrayBuffer");
return false;
}
// Note: JS::StealArrayBufferContents will either return the stolen data or
// throw an exception.
void* contents = JS::StealArrayBufferContents(cx, obj); if (!contents) {
return false;
}
if (js::SupportDifferentialTesting()) {
// Always return 0 to get consistent output with and without --no-threads.
args.rval().setInt32(0);
return true;
}
// ShapeSnapshot holds information about an object's properties. This is used
// for checking object and shape changes between two points in time.
class ShapeSnapshot {
HeapPtr<JSObject*> object_;
HeapPtr<Shape*> shape_;
HeapPtr<BaseShape*> baseShape_;
ObjectFlags objectFlags_;
// A JSObject that holds a ShapeSnapshot.
class ShapeSnapshotObject : public NativeObject {
static constexpr size_t SnapshotSlot = 0;
static constexpr size_t ReservedSlots = 1;
bool hasSnapshot() const {
// The snapshot may not be present yet if we GC during initialization.
return !getReservedSlot(SnapshotSlot).isUndefined();
}
void ShapeSnapshot::checkSelf(JSContext* cx) const {
// Assertions based on a single snapshot.
// Non-dictionary shapes must not be mutated. if (!shape_->isDictionary()) {
MOZ_RELEASE_ASSERT(shape_->base() == baseShape_);
MOZ_RELEASE_ASSERT(shape_->objectFlags() == objectFlags_);
}
// Skip if the map no longer matches the snapshotted data. This can
// only happen for dictionary maps because they can be mutated or compacted
// after a shape change. if (!propMap->hasKey(propMapIndex) ||
PropertySnapshot(propMap, propMapIndex) != propSnapshot) {
MOZ_RELEASE_ASSERT(propMap->isDictionary());
MOZ_RELEASE_ASSERT(object_->shape() != shape_);
continue;
}
// Ensure ObjectFlags depending on property information are set if needed.
ObjectFlags expectedFlags = GetObjectFlagsForNewProperty(
shape_->getObjectClass(), shape_->objectFlags(), propSnapshot.key,
prop.flags(), cx);
MOZ_RELEASE_ASSERT(expectedFlags == objectFlags_);
// Accessors must have a PrivateGCThingValue(GetterSetter*) slot value. if (prop.isAccessorProperty()) {
Value slotVal = slots_[prop.slot()];
MOZ_RELEASE_ASSERT(slotVal.isPrivateGCThing());
MOZ_RELEASE_ASSERT(slotVal.toGCThing()->is<GetterSetter>());
}
// Data properties must not have a PrivateGCThingValue slot value. if (prop.isDataProperty()) {
Value slotVal = slots_[prop.slot()];
MOZ_RELEASE_ASSERT(!slotVal.isPrivateGCThing());
}
}
}
if (object_ != later.object_) {
// Snapshots are for different objects. Assert dictionary shapes aren't
// shared. if (object_->is<NativeObject>()) {
NativeObject* nobj = &object_->as<NativeObject>(); if (nobj->inDictionaryMode()) {
MOZ_RELEASE_ASSERT(nobj->shape() != later.shape_);
}
}
return;
}
// We have two snapshots for the same object. Check the shape information
// wasn't changed in invalid ways.
// If the Shape is still the same, the object must have the same BaseShape,
// ObjectFlags and property information. if (shape_ == later.shape_) {
MOZ_RELEASE_ASSERT(objectFlags_ == later.objectFlags_);
MOZ_RELEASE_ASSERT(baseShape_ == later.baseShape_);
MOZ_RELEASE_ASSERT(slots_.length() == later.slots_.length());
MOZ_RELEASE_ASSERT(properties_.length() == later.properties_.length());
for (size_t i = 0; i < properties_.length(); i++) {
MOZ_RELEASE_ASSERT(properties_[i] == later.properties_[i]);
// Non-configurable accessor properties and non-configurable, non-writable
// data properties shouldn't have had their slot mutated.
PropertyInfo prop = properties_[i].prop; if (!prop.configurable()) { if (prop.isAccessorProperty() ||
(prop.isDataProperty() && !prop.writable())) {
size_t slot = prop.slot();
MOZ_RELEASE_ASSERT(slots_[slot] == later.slots_[slot]);
}
}
}
}
// Object flags should not be lost. The exception is the Indexed flag, it
// can be cleared when densifying elements, so clear that flag first.
{
ObjectFlags flags = objectFlags_;
ObjectFlags flagsLater = later.objectFlags_;
flags.clearFlag(ObjectFlag::Indexed);
flagsLater.clearFlag(ObjectFlag::Indexed);
MOZ_RELEASE_ASSERT((flags.toRaw() & flagsLater.toRaw()) == flags.toRaw());
}
// If the HadGetterSetterChange flag wasn't set, all GetterSetter slots must
// be unchanged. if (!later.objectFlags_.hasFlag(ObjectFlag::HadGetterSetterChange)) { for (size_t i = 0; i < slots_.length(); i++) { if (slots_[i].isPrivateGCThing() &&
slots_[i].toGCThing()->is<GetterSetter>()) {
MOZ_RELEASE_ASSERT(i < later.slots_.length());
MOZ_RELEASE_ASSERT(later.slots_[i] == slots_[i]);
}
}
}
}
if (!args.get(0).isObject() ||
!args[0].toObject().is<ShapeSnapshotObject>()) {
JS_ReportErrorASCII(cx, "checkShapeSnapshot requires a snapshot argument");
return false;
}
// Get the object to use from the snapshot if the second argument is not an
// object.
RootedObject obj(cx); if (args.get(1).isObject()) {
obj = &args[1].toObject();
} else {
auto& snapshot = args[0].toObject().as<ShapeSnapshotObject>().snapshot();
obj = snapshot.object();
}
RootedObject otherSnapshot(cx, ShapeSnapshotObject::create(cx, obj)); if (!otherSnapshot) {
return false;
}
// An edge to a node from its predecessor in a path through the graph.
class BackEdge {
// The node from which this edge starts.
JS::ubi::Node predecessor_;
// No copy constructor or copying assignment.
BackEdge(const BackEdge&) = delete;
BackEdge& operator=(const BackEdge&) = delete;
};
// A path-finding handler class for use with JS::ubi::BreadthFirst.
struct FindPathHandler {
using NodeData = BackEdge;
using Traversal = JS::ubi::BreadthFirst<FindPathHandler>;
bool operator()(Traversal& traversal, JS::ubi::Node origin,
const JS::ubi::Edge& edge, BackEdge* backEdge, bool first) {
// We take care of each node the first time we visit it, so there's
// nothing to be done on subsequent visits. if (!first) {
return true;
}
// Record how we reached this node. This is the last edge on a
// shortest path to this node.
EdgeName edgeName =
DuplicateStringToArena(js::StringBufferArena, cx, edge.name.get()); if (!edgeName) {
return false;
}
*backEdge = BackEdge(origin, std::move(edgeName));
// Have we reached our final target node? if (edge.referent == target) {
// Record the path that got us here, which must be a shortest path. if (!recordPath(traversal, backEdge)) {
return false;
}
foundPath = true;
traversal.stop();
}
return true;
}
// We've found a path to our target. Walk the backlinks to produce the
// (reversed) path, saving the path in |nodes| and |edges|. |nodes| is
// rooted, so it can hold the path's nodes as we leave the scope of
// the AutoCheckCannotGC. Note that nodes are added to |visited| after we
// return from operator() so we have to pass the target BackEdge* to this
// function.
bool recordPath(Traversal& traversal, BackEdge* targetBackEdge) {
JS::ubi::Node here = target;
do {
BackEdge* backEdge = targetBackEdge; if (here != target) {
Traversal::NodeMap::Ptr p = traversal.visited.lookup(here);
MOZ_ASSERT(p);
backEdge = &p->value();
}
JS::ubi::Node predecessor = backEdge->predecessor(); if (!nodes.append(predecessor.exposeToJS()) ||
!edges.append(backEdge->forgetName())) {
return false;
}
here = predecessor;
} while (here != start);
return true;
}
JSContext* cx;
// The node we're starting from.
JS::ubi::Node start;
// The node we're looking for.
JS::ubi::Node target;
// True if we found a path to target, false if we didn't.
bool foundPath;
// The nodes and edges of the path --- should we find one. The path is
// stored in reverse order, because that's how it's easiest for us to
// construct it:
// - edges[i] is the name of the edge from nodes[i] to nodes[i-1].
// - edges[0] is the name of the edge from nodes[0] to the target.
// - The last node, nodes[n-1], is the start node.
MutableHandle<GCVector<Value>> nodes;
Vector<EdgeName>& edges;
};
// We don't ToString non-objects given as 'start' or 'target', because this
// test is all about object identity, and ToString doesn't preserve that.
// Non-GCThing endpoints don't make much sense. if (!args[0].isObject() && !args[0].isString() && !args[0].isSymbol()) {
ReportValueError(cx, JSMSG_UNEXPECTED_TYPE, JSDVG_SEARCH_STACK, args[0],
nullptr, "not an object, string, or symbol");
return false;
}
if (!args[1].isObject() && !args[1].isString() && !args[1].isSymbol()) {
ReportValueError(cx, JSMSG_UNEXPECTED_TYPE, JSDVG_SEARCH_STACK, args[0],
nullptr, "not an object, string, or symbol");
return false;
}
{
// We can't tolerate the GC moving things around while we're searching
// the heap. Check that nothing we do causes a GC.
JS::AutoCheckCannotGC autoCannotGC;
if (!traversal.traverse()) { if (!cx->isExceptionPending()) {
ReportOutOfMemory(cx);
}
return false;
}
if (!handler.foundPath) {
// We didn't find any paths from the start to the target.
args.rval().setUndefined();
return true;
}
}
// |nodes| and |edges| contain the path from |start| to |target|, reversed.
// Construct a JavaScript array describing the path from the start to the
// target. Each element has the form:
//
// {
// node: <object or string or symbol>,
// edge: <string describing outgoing edge from node>
// }
//
// or, if the node is some internal thing that isn't a proper JavaScript
// value:
//
// { node: undefined, edge: <string> }
size_t length = nodes.length();
Rooted<ArrayObject*> result(cx, NewDenseFullyAllocatedArray(cx, length)); if (!result) {
return false;
}
result->ensureDenseInitializedLength(0, length);
// Walk |nodes| and |edges| in the stored order, and construct the result
// array in start-to-target order. for (size_t i = 0; i < length; i++) {
// Build an object describing the node and edge.
RootedObject obj(cx, NewPlainObject(cx)); if (!obj) {
return false;
}
// Only define the "node" property if we're not fuzzing, to prevent the
// fuzzers from messing with internal objects that we don't want to expose
// to arbitrary JS. if (!fuzzingSafe) {
RootedValue wrapped(cx, nodes[i]); if (!cx->compartment()->wrap(cx, &wrapped)) {
return false;
}
if (!args.get(1).isUndefined()) { if (!args[1].isObject()) {
ReportValueError(cx, JSMSG_UNEXPECTED_TYPE, JSDVG_SEARCH_STACK, args[1],
nullptr, "not an options object");
return false;
}
RootedObject options(cx, &args[1].toObject());
bool exists; if (!JS_HasProperty(cx, options, "start", &exists)) {
return false;
} if (exists) { if (!JS_GetProperty(cx, options, "start", &start)) {
return false;
}
// Non-GCThing endpoints don't make much sense. if (!start.isGCThing()) {
ReportValueError(cx, JSMSG_UNEXPECTED_TYPE, JSDVG_SEARCH_STACK, start,
nullptr, "not a GC thing");
return false;
}
}
RootedValue v(cx, Int32Value(maxNumPaths)); if (!JS_HasProperty(cx, options, "maxNumPaths", &exists)) {
return false;
} if (exists) { if (!JS_GetProperty(cx, options, "maxNumPaths", &v)) {
return false;
} if (!JS::ToInt32(cx, v, &maxNumPaths)) {
return false;
}
} if (maxNumPaths <= 0) {
ReportValueError(cx, JSMSG_UNEXPECTED_TYPE, JSDVG_SEARCH_STACK, v,
nullptr, "not greater than 0");
return false;
}
}
// Ensure we have at least one target.
size_t length = objs->getDenseInitializedLength(); if (length == 0) {
ReportValueError(cx, JSMSG_UNEXPECTED_TYPE, JSDVG_SEARCH_STACK, args[0],
nullptr, "not a dense array object with one or more elements");
return false;
}
for (size_t i = 0; i < length; i++) {
RootedValue el(cx, objs->getDenseElement(i)); if (!el.isGCThing()) {
JS_ReportErrorASCII(cx, "Each target must be a GC thing");
return false;
}
}
// We accumulate the results into a GC-stable form, due to the fact that the
// JS::ubi::ShortestPaths lifetime (when operating on the live heap graph)
// is bounded within an AutoCheckCannotGC.
Rooted<GCVector<GCVector<GCVector<Value>>>> values(
cx, GCVector<GCVector<GCVector<Value>>>(cx));
Vector<Vector<Vector<JS::ubi::EdgeName>>> names(cx);
{
JS::ubi::Node root;
JS::ubi::RootList rootList(cx, true); if (start.isNull()) { auto [ok, nogc] = rootList.init();
(void)nogc; // Old compilers get anxious about nogc being unused. if (!ok) {
ReportOutOfMemory(cx); returnfalse;
}
root = JS::ubi::Node(&rootList);
} else {
root = JS::ubi::Node(start);
}
JS::AutoCheckCannotGC noGC(cx);
JS::ubi::NodeSet targets;
for (size_t i = 0; i < length; i++) {
RootedValue val(cx, objs->getDenseElement(i));
JS::ubi::Node node(val); if (!targets.put(node)) {
ReportOutOfMemory(cx); returnfalse;
}
}
auto maybeShortestPaths = JS::ubi::ShortestPaths::Create(
cx, noGC, maxNumPaths, root, std::move(targets)); if (maybeShortestPaths.isNothing()) {
ReportOutOfMemory(cx); returnfalse;
} auto& shortestPaths = *maybeShortestPaths;
for (size_t i = 0; i < length; i++) { if (!values.append(GCVector<GCVector<Value>>(cx)) ||
!names.append(Vector<Vector<JS::ubi::EdgeName>>(cx))) { returnfalse;
}
// CompileOption should be created in the target global's realm.
RootedObject global(cx);
Maybe<JS::CompileOptions> maybeOptions; if (args.hasDefined(1)) {
global = ToObject(cx, args[1]); if (!global) { returnfalse;
}
global = CheckedUnwrapDynamic(global, cx, /* stopAtWindowProxy = */ false); if (!global) {
JS_ReportErrorASCII(cx, "Permission denied to access global"); returnfalse;
} if (!global->is<GlobalObject>()) {
JS_ReportErrorASCII(cx, "Argument must be a global object"); returnfalse;
}
AutoStableStringChars linearChars(cx); if (!linearChars.initTwoByte(cx, str)) { returnfalse;
}
JS::SourceText<char16_t> srcBuf; if (!srcBuf.initMaybeBorrowed(cx, linearChars)) { returnfalse;
}
RootedObject varObj(cx);
{ // ExecuteInFrameScriptEnvironment requires the script be in the same // realm as the global. The script compilation should be done after // switching globals.
AutoRealm ar(cx, global);
RootedScript script(cx, JS::Compile(cx, options, srcBuf)); if (!script) { returnfalse;
}
JS::RootedObject obj(cx, JS_NewPlainObject(cx)); if (!obj) { returnfalse;
}
RootedObject lexicalScope(cx); if (!js::ExecuteInFrameScriptEnvironment(cx, obj, script, &lexicalScope)) { returnfalse;
}
{ // We can't tolerate the GC moving things around while we're using a // ubi::Node. Check that nothing we do causes a GC.
JS::AutoCheckCannotGC autoCannotGC;
staticbool ByteSizeOfScript(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); if (!args.requireAtLeast(cx, "byteSizeOfScript", 1)) { returnfalse;
} if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
JS_ReportErrorASCII(cx, "Argument must be a Function object"); returnfalse;
}
RootedFunction fun(cx, &args[0].toObject().as<JSFunction>()); if (fun->isNativeFun()) {
JS_ReportErrorASCII(cx, "Argument must be a scripted function"); returnfalse;
}
RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); if (!script) { returnfalse;
}
{ // We can't tolerate the GC moving things around while we're using a // ubi::Node. Check that nothing we do causes a GC.
JS::AutoCheckCannotGC autoCannotGC;
if (stencilObj->stencil()->getInitial()->isModule()) {
JS_ReportErrorASCII(cx, "evalStencil: Module stencil cannot be evaluated. Use " "instantiateModuleStencil instead"); returnfalse;
}
CompileOptions options(cx);
UniqueChars fileNameBytes;
Rooted<JS::Value> privateValue(cx);
Rooted<JSString*> elementAttributeName(cx); if (args.length() == 2) { if (!args[1].isObject()) {
JS_ReportErrorASCII(cx, "evalStencil: The 2nd argument must be an object"); returnfalse;
}
RootedObject opts(cx, &args[1].toObject());
if (!js::ParseCompileOptions(cx, options, opts, &fileNameBytes)) { returnfalse;
} if (!js::ParseDebugMetadata(cx, opts, &privateValue,
&elementAttributeName)) { returnfalse;
}
}
RootedString displayURL(cx);
RootedString sourceMapURL(cx);
UniqueChars fileNameBytes; bool isModule = false; if (args.length() == 2) { if (!args[1].isObject()) {
JS_ReportErrorASCII(
cx, "compileToStencilXDR: The 2nd argument must be an object"); returnfalse;
}
RootedObject opts(cx, &args[1].toObject());
if (!js::ParseCompileOptions(cx, options, opts, &fileNameBytes)) { returnfalse;
} if (!ParseCompileOptionsForModule(cx, options, opts, isModule)) { returnfalse;
} if (!js::ParseSourceOptions(cx, opts, &displayURL, &sourceMapURL)) { returnfalse;
}
}
/* Serialize the stencil to XDR. */
JS::TranscodeBuffer xdrBytes; auto result = JS::EncodeStencil(cx, stencil, xdrBytes); if (result == JS::TranscodeResult::Throw) { returnfalse;
} if (JS::IsTranscodeFailureResult(result)) {
JS_ReportErrorASCII(cx, "Encoding failure"); returnfalse;
}
CompileOptions options(cx);
UniqueChars fileNameBytes;
Rooted<JS::Value> privateValue(cx);
Rooted<JSString*> elementAttributeName(cx); if (args.length() == 2) { if (!args[1].isObject()) {
JS_ReportErrorASCII(cx, "evalStencilXDR: The 2nd argument must be an object"); returnfalse;
}
RootedObject opts(cx, &args[1].toObject());
if (!js::ParseCompileOptions(cx, options, opts, &fileNameBytes)) { returnfalse;
} if (!js::ParseDebugMetadata(cx, opts, &privateValue,
&elementAttributeName)) { returnfalse;
}
}
JS::TranscodeRange xdrRange(xdrObj->buffer(), xdrObj->bufferLength());
JS::DecodeOptions decodeOptions(options);
RefPtr<JS::Stencil> stencil; auto result =
JS::DecodeStencil(cx, decodeOptions, xdrRange, getter_AddRefs(stencil)); if (result == JS::TranscodeResult::Throw) { returnfalse;
} if (JS::IsTranscodeFailureResult(result)) {
JS_ReportErrorASCII(cx, "Decoding failure"); returnfalse;
}
if (stencil->getInitial()->isModule()) {
JS_ReportErrorASCII(cx, "evalStencilXDR: Module stencil cannot be evaluated. " "Use instantiateModuleStencilXDR instead"); returnfalse;
}
if (!js::ValidateLazinessOfStencilAndGlobal(cx, stencil.get())) { returnfalse;
}
if (!args.requireAtLeast(cx, "getExceptionInfo", 1)) { returnfalse;
}
if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
JS_ReportErrorASCII(cx, "getExceptionInfo: expected function argument"); returnfalse;
}
RootedValue rval(cx); if (JS_CallFunctionValue(cx, nullptr, args[0], JS::HandleValueArray::empty(),
&rval)) { // Function didn't throw.
args.rval().setNull(); return true;
}
// We currently don't support interrupts or forced returns. if (!cx->isExceptionPending()) {
JS_ReportErrorASCII(cx, "getExceptionInfo: unsupported exception status"); returnfalse;
}
if (gc->isIncrementalGCInProgress() &&
gc->hasZealMode(gc::ZealMode::IncrementalMarkingValidator)) {
JS_ReportErrorASCII(
cx, "Can't add to test mark queue during incremental GC if marking " "validation is enabled as this can cause failures"); returnfalse;
}
if (args.get(0).isString()) {
RootedString val(cx, args[0].toString()); if (!val->ensureLinear(cx)) { returnfalse;
} if (!gc->appendTestMarkQueue(StringValue(val))) {
JS_ReportOutOfMemory(cx); returnfalse;
}
} elseif (args.get(0).isObject()) { if (!gc->appendTestMarkQueue(args[0])) {
JS_ReportOutOfMemory(cx); returnfalse;
}
} else {
JS_ReportErrorASCII(cx, "Argument must be a string or object"); returnfalse;
}
staticbool 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"); returnfalse;
}
if (args.length() > 1) {
JS_ReportErrorASCII(cx, "Wrong number of arguments"); returnfalse;
}
if (!coverage::IsLCovEnabled()) {
JS_ReportErrorASCII(cx, "Coverage not enabled for process."); returnfalse;
}
RootedObject global(cx); if (args.hasDefined(0)) {
global = ToObject(cx, args[0]); if (!global) {
JS_ReportErrorASCII(cx, "Permission denied to access global"); returnfalse;
}
global = CheckedUnwrapDynamic(global, cx, /* stopAtWindowProxy = */ false); if (!global) {
ReportAccessDenied(cx); returnfalse;
} if (!global->is<GlobalObject>()) {
JS_ReportErrorASCII(cx, "Argument must be a global object"); returnfalse;
}
} else {
global = JS::CurrentGlobalOrNull(cx);
}
if (args.length() != 1) {
ReportUsageErrorASCII(cx, callee, "Wrong number of arguments"); returnfalse;
}
if (!args[0].isString() && !args[0].isUndefined()) {
ReportUsageErrorASCII(cx, callee, "First argument should be a string or undefined"); returnfalse;
}
if (args.length() != 1) {
ReportUsageErrorASCII(cx, callee, "Wrong number of arguments"); returnfalse;
}
if (!args[0].isString() && !args[0].isUndefined()) {
ReportUsageErrorASCII(cx, callee, "First argument should be a string or undefined"); returnfalse;
}
if (args[0].isString() && !args[0].toString()->empty()) {
Rooted<JSString*> str(cx, args[0].toString()); if (!str) { returnfalse;
}
auto timeZone = StringToTimeZone(cx, callee, str, AllowTimeZoneLink::No); if (!timeZone) { returnfalse;
}
cx->realm()->setTimeZoneOverride(timeZone.get());
} else { // Reset to use the system default time zone.
cx->realm()->setTimeZoneOverride(nullptr);
}
if (args.length() != 1) {
ReportUsageErrorASCII(cx, callee, "Wrong number of arguments"); returnfalse;
}
if (!args[0].isString() && !args[0].isUndefined()) {
ReportUsageErrorASCII(cx, callee, "First argument should be a string or undefined"); returnfalse;
}
if (args[0].isString() && !args[0].toString()->empty()) {
RootedString str(cx, args[0].toString());
UniqueChars locale = StringToLocale(cx, callee, str); if (!locale) { returnfalse;
}
if (args.length() != 1) {
ReportUsageErrorASCII(cx, callee, "Wrong number of arguments"); returnfalse;
}
if (!args[0].isString() && !args[0].isUndefined()) {
ReportUsageErrorASCII(cx, callee, "First argument should be a string or undefined"); returnfalse;
}
if (args[0].isString() && !args[0].toString()->empty()) {
Rooted<JSString*> str(cx, args[0].toString()); if (!str) { returnfalse;
}
auto locale = StringToLocale(cx, callee, str); if (!locale) { returnfalse;
}
cx->realm()->setLocaleOverride(locale.get());
} else { // Reset to use the system default locale.
cx->realm()->setLocaleOverride(nullptr);
}
// The std::chrono symbols are too new to be present in STL on all platforms we // care about, so use raw POSIX clock APIs when it might be necessary. #ifdefined(XP_UNIX) && !defined(XP_DARWIN) auto ComputeNow = [](const timespec& ts) { return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
};
timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { // Use a monotonic clock if available.
now = ComputeNow(ts);
} else { // Use a realtime clock as fallback. if (clock_gettime(CLOCK_REALTIME, &ts) != 0) { // Fail if no clock is available.
JS_ReportErrorASCII(cx, "can't retrieve system clock"); returnfalse;
}
now = ComputeNow(ts);
// Manually enforce atomicity on a non-monotonic clock.
{ static mozilla::Atomic<bool, mozilla::ReleaseAcquire> spinLock; while (!spinLock.compareExchange(false, true)) { continue;
}
staticdouble lastNow = -FLT_MAX;
now = lastNow = std::max(now, lastNow);
spinLock = false;
}
} #else
using std::chrono::duration_cast;
using std::chrono::milliseconds;
using std::chrono::steady_clock;
now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch())
.count(); #endif// XP_UNIX && !XP_DARWIN
if (!args[0].isString()) {
ReportUsageErrorASCII(cx, callee, "First argument must be a String"); returnfalse;
}
// Create the amounts array early so that the raw pointer into Uint8Array // data has as short a lifetime as possible
Rooted<ArrayObject*> array(cx, NewDenseFullyAllocatedArray(cx, 2)); if (!array) { returnfalse;
}
array->ensureDenseInitializedLength(0, 2);
JSObject* obj = args[1].isObject() ? &args[1].toObject() : nullptr;
Rooted<JS::Uint8Array> view(cx, JS::Uint8Array::unwrap(obj)); if (!view) {
ReportUsageErrorASCII(cx, callee, "Second argument must be a Uint8Array"); returnfalse;
}
mozilla::Span<uint8_t> span;
bool isSharedMemory = false;
{ // The hazard analysis does not track the data pointer, so it can neither // tell that `data` is dead if ReportUsageErrorASCII is called, nor that // its live range ends at the call to AsWritableChars(). Construct a // temporary scope to hide from the analysis. This should really be replaced // with a safer mechanism.
JS::AutoCheckCannotGC nogc(cx); if (!view.isDetached()) {
span = view.get().getData(&isSharedMemory, nogc);
}
}
if (isSharedMemory || // exclude views of SharedArrayBuffers
!span.data()) { // exclude views of detached ArrayBuffers
ReportUsageErrorASCII(
cx, callee, "Second argument must be an unshared, non-detached Uint8Array"); returnfalse;
}
JSScript* js::TestingFunctionArgumentToScript(
JSContext* cx, HandleValue v, JSFunction** funp /* = nullptr */) { if (v.isString()) { // To convert a string to a script, compile it. Parse it as an ES6 Program.
Rooted<JSString*> str(cx, v.toString());
AutoStableStringChars linearChars(cx); if (!linearChars.initTwoByte(cx, str)) { return nullptr;
}
SourceText<char16_t> source; if (!source.initMaybeBorrowed(cx, linearChars)) { return nullptr;
}
RootedScript script(cx); if (args.length() == 0) {
NonBuiltinScriptFrameIter iter(cx); if (iter.done()) {
ReportUsageErrorASCII(cx, callee, "no script argument and no script caller"); returnfalse;
}
script = iter.script();
} else {
script = TestingFunctionArgumentToScript(cx, args[0]); if (!script) { returnfalse;
}
}
bool forceDebug = false; if (args.length() > 1) { if (args.length() > 2) {
ReportUsageErrorASCII(cx, callee, "too many arguments"); returnfalse;
} if (!args[1].isBoolean() && !args[1].isUndefined()) {
ReportUsageErrorASCII(
cx, callee, "forceDebugInstrumentation argument should be boolean"); returnfalse;
}
forceDebug = ToBoolean(args[1]);
}
constchar* returnedStr = nullptr; do { // In order to check for differential behaviour, baselineCompile should have // the same output whether --no-baseline is used or not. if (js::SupportDifferentialTesting()) {
returnedStr = "skipped (differential testing)"; break;
}
AutoRealm ar(cx, script); if (script->isBaselineCompilingOffThread()) {
CancelOffThreadBaselineCompile(script);
}
if (script->hasBaselineScript()) { if (forceDebug && !script->baselineScript()->hasDebugInstrumentation()) { // There isn't an easy way to do this for a script that might be on // stack right now. See // js::jit::RecompileOnStackBaselineScriptsForDebugMode.
ReportUsageErrorASCII(
cx, callee, "unsupported case: recompiling script for debug mode"); returnfalse;
}
args.rval().setUndefined(); returntrue;
}
if (!jit::IsBaselineJitEnabled(cx)) {
returnedStr = "baseline disabled"; break;
} if (!jit::CanBaselineCompileScript(cx, script)) {
returnedStr = "can't compile"; break;
} if (!cx->zone()->ensureJitZoneExists(cx)) { returnfalse;
}
jit::BaselineOptions options = {
jit::BaselineOption::ForceMainThreadCompilation}; if (forceDebug) {
options.setFlag(jit::BaselineOption::ForceDebugInstrumentation);
}
jit::MethodStatus status = jit::BaselineCompile(cx, script, options); switch (status) { case jit::Method_Error: returnfalse; case jit::Method_CantCompile:
returnedStr = "can't compile"; break; case jit::Method_Skipped:
returnedStr = "skipped"; break; case jit::Method_Compiled:
args.rval().setUndefined();
}
} while (false);
if (returnedStr) { return ReturnStringCopy(cx, args, returnedStr);
}
if (!args.requireAtLeast(cx, "IsSmallFunction", 1)) { returnfalse;
}
HandleValue arg = args[0]; if (!arg.isObject() || !arg.toObject().is<JSFunction>()) {
ReportUsageErrorASCII(cx, callee, "First argument must be a function"); returnfalse;
}
RootedFunction fun(cx, &args[0].toObject().as<JSFunction>()); if (!fun->isInterpreted()) {
ReportUsageErrorASCII(cx, callee, "First argument must be an interpreted function"); returnfalse;
}
JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script) { returnfalse;
}
double x; if (!JS::ToNumber(cx, args.get(0), &x)) { returnfalse;
}
double y; if (!JS::ToNumber(cx, args.get(1), &y)) { returnfalse;
}
// Because C99 and ECMA specify different behavior for pow(), we need to wrap // the fdlibm call to make it ECMA compliant. if (!std::isfinite(y) && (x == 1.0 || x == -1.0)) {
args.rval().setNaN();
} else {
args.rval().setDouble(fdlibm_pow(x, y));
} returntrue;
}
// The stackTrace persists, so we can clear the flag here in case copying the // string fails
cx->unsetOOMStackTrace();
JSString* str = JS_NewStringCopyZ(cx, stackTrace); if (!str) { returnfalse;
}
args.rval().setString(str); returntrue;
}
// clang-format off staticconst JSFunctionSpecWithHelp TestingFunctions[] = {
JS_FN_HELP("gc", ::GC, 0, 0, "gc([obj] | 'zone' [, ('shrinking' | 'last-ditch') ])", " Run the garbage collector.\n" " The first parameter describes which zones to collect: if an object is\n" " given, GC only its zone. If 'zone' is given, GC any zones that were\n" " scheduled via schedulegc.\n" " The second parameter is optional and may be 'shrinking' to perform a\n" " shrinking GC or 'last-ditch' for a shrinking, last-ditch GC."),
JS_FN_HELP("minorgc", ::MinorGC, 0, 0, "minorgc([aboutToOverflow])", " Run a minor collector on the Nursery. When aboutToOverflow is true, marks\n" " the store buffer as about-to-overflow before collecting."),
JS_FN_HELP("maybegc", ::MaybeGC, 0, 0, "maybegc()", " Hint to the engine that now is an ok time to run the garbage collector.\n"),
JS_FN_HELP("gcparam", GCParameter, 2, 0, "gcparam(name [, value])", " Wrapper for JS_[GS]etGCParameter. The name is one of:" GC_PARAMETER_ARGS_LIST),
JS_FN_HELP("finishBackgroundFree", FinishBackgroundFree, 0, 0, "finishBackgroundFree()", " Wait for the GC's background free task to finish.\n"),
JS_FN_HELP("hasDisassembler", HasDisassembler, 0, 0, "hasDisassembler()", " Return true if a disassembler is present (for disnative and wasmDis)."),
JS_FN_HELP("disnative", DisassembleNative, 2, 0, "disnative(fun,[path])", " Disassemble a function into its native code. Optionally write the native code bytes to a file on disk.\n"),
JS_FN_HELP("disblic", DisassembleBaselineICs, 1, 0, "disblic(fun)", " Disassemble the baseline ICs for a function into native code.\n"),
JS_FN_HELP("relazifyFunctions", RelazifyFunctions, 0, 0, "relazifyFunctions(...)", " Perform a GC and allow relazification of functions. Accepts the same\n" " arguments as gc()."),
JS_FN_HELP("getBuildConfiguration", GetBuildConfiguration, 1, 0, "getBuildConfiguration([option])", " Query the options SpiderMonkey was built with, or return an object\n" " with the options if no argument is given."),
JS_FN_HELP("getRealmConfiguration", GetRealmConfiguration, 1, 0, "getRealmConfiguration([option])", " Query the runtime options SpiderMonkey is running with, or return an\n." " object with the options if no argument is given."),
JS_FN_HELP("isLcovEnabled", ::IsLCovEnabled, 0, 0, "isLcovEnabled()", " Return true if JS LCov support is enabled."),
JS_FN_HELP("trialInline", TrialInline, 0, 0, "trialInline()", " Perform trial-inlining for the caller's frame if it's a BaselineFrame."),
JS_FN_HELP("hasChild", HasChild, 0, 0, "hasChild(parent, child)", " Return true if |child| is a child of |parent|, as determined by a call to\n" " TraceChildren"),
JS_FN_HELP("setSavedStacksRNGState", SetSavedStacksRNGState, 1, 0, "setSavedStacksRNGState(seed)", " Set this compartment's SavedStacks' RNG state.\n"),
JS_FN_HELP("getSavedFrameCount", GetSavedFrameCount, 0, 0, "getSavedFrameCount()", " Return the number of SavedFrame instances stored in this compartment's\n" " SavedStacks cache."),
JS_FN_HELP("clearSavedFrames", ClearSavedFrames, 0, 0, "clearSavedFrames()", " Empty the current compartment's cache of SavedFrame objects, so that\n" " subsequent stack captures allocate fresh objects to represent frames.\n" " Clear the current stack's LiveSavedFrameCaches."),
JS_FN_HELP("saveStack", SaveStack, 0, 0, "saveStack([maxDepth [, compartment]])", " Capture a stack. If 'maxDepth' is given, capture at most 'maxDepth' number\n" " of frames. If 'compartment' is given, allocate the js::SavedFrame instances\n" " with the given object's compartment."),
JS_FN_HELP("captureFirstSubsumedFrame", CaptureFirstSubsumedFrame, 1, 0, "saveStack(object [, shouldIgnoreSelfHosted = true]])", " Capture a stack back to the first frame whose principals are subsumed by the\n" " object's compartment's principals. If 'shouldIgnoreSelfHosted' is given,\n" " control whether self-hosted frames are considered when checking principals."),
JS_FN_HELP("callFunctionFromNativeFrame", CallFunctionFromNativeFrame, 1, 0, "callFunctionFromNativeFrame(function)", " Call 'function' with a (C++-)native frame on stack.\n" " Required for testing that SaveStack properly handles native frames."),
JS_FN_HELP("callFunctionWithAsyncStack", CallFunctionWithAsyncStack, 0, 0, "callFunctionWithAsyncStack(function, stack, asyncCause)", " Call 'function', using the provided stack as the async stack responsible\n" " for the call, and propagate its return value or the exception it throws.\n" " The function is called with no arguments, and 'this' is 'undefined'. The\n" " specified |asyncCause| is attached to the provided stack frame."),
JS_FN_HELP("enableTrackAllocations", EnableTrackAllocations, 0, 0, "enableTrackAllocations()", " Start capturing the JS stack at every allocation. Note that this sets an\n" " object metadata callback that will override any other object metadata\n" " callback that may be set."),
JS_FN_HELP("disableTrackAllocations", DisableTrackAllocations, 0, 0, "disableTrackAllocations()", " Stop capturing the JS stack at every allocation."),
JS_FN_HELP("setTestFilenameValidationCallback", SetTestFilenameValidationCallback, 0, 0, "setTestFilenameValidationCallback()", " Set the filename validation callback to a callback that accepts only\n" " filenames starting with 'safe' or (only in system realms) 'system'."),
JS_FN_HELP("newObjectWithAddPropertyHook", NewObjectWithAddPropertyHook, 0, 0, "newObjectWithAddPropertyHook()", " Returns a new object with an addProperty JSClass hook. This hook\n" " increments the value of the _propertiesAdded data property on the object\n" " when a new property is added."),
JS_FN_HELP("newObjectWithCallHook", NewObjectWithCallHook, 0, 0, "newObjectWithCallHook()", " Returns a new object with call/construct JSClass hooks. These hooks return\n" " a new object that contains the Values supplied by the caller."),
JS_FN_HELP("newObjectWithManyReservedSlots", NewObjectWithManyReservedSlots, 0, 0, "newObjectWithManyReservedSlots()", " Returns a new object with many reserved slots. The slots are initialized to int32\n" " values. checkObjectWithManyReservedSlots can be used to check the slots still\n" " hold these values."),
JS_FN_HELP("checkObjectWithManyReservedSlots", CheckObjectWithManyReservedSlots, 1, 0, "checkObjectWithManyReservedSlots(obj)", " Checks the reserved slots set by newObjectWithManyReservedSlots still hold the expected\n" " values."),
JS_FN_HELP("addObjectFuse", AddObjectFuse, 1, 0, "addObjectFuse(object)", " Mark 'object' as having an ObjectFuse."),
JS_FN_HELP("getObjectFuseState", GetObjectFuseState, 1, 0, "getObjectFuseState(object)", " Returns a new object that contains information about the ObjectFuse of 'object'."),
JS_FN_HELP("getWatchtowerLog", GetWatchtowerLog, 0, 0, "getWatchtowerLog()", " Returns the Watchtower log recording object changes for objects for which\n" " addWatchtowerTarget was called. The internal log is cleared. The return\n" " value is an array of plain objects with the following properties:\n" " - kind: a string describing the kind of mutation, for example \"add-prop\"\n" " - object: the object being mutated\n" " - extra: an extra value, for example the name of the property being added"),
JS_FN_HELP("addWatchtowerTarget", AddWatchtowerTarget, 1, 0, "addWatchtowerTarget(object)", " Invoke the watchtower callback for changes to this object."),
JS_FN_HELP("newString", NewString, 2, 0, "newString(str[, options])", " Copies str's chars and returns a new string. Valid options:\n" " \n" " - tenured: allocate directly into the tenured heap.\n" " \n" " - twoByte: create a \"two byte\" string, not a latin1 string, regardless of the\n" " input string's characters. Latin1 will be used by default if possible\n" " (again regardless of the input string.)\n" " \n" " - newStringBuffer: create a new string that uses a refcounted StringBuffer for\n" " the characters.\n" " \n" " - shareStringBuffer: create a new string that shares str's StringBuffer.\n" " \n" " - external: create an external string. External strings are always twoByte and\n" " tenured.\n" " \n" " - maybeExternal: create an external string, unless the data fits within an\n" " inline string. Inline strings may be nursery-allocated.\n" " \n" " - capacity: create an extensible string with the given capacity"),
JS_FN_HELP("newDependentString", NewDependentString, 2, 0, "newDependentString(str, indexStart[, indexEnd] [, options])", " Essentially the same as str.substring() but insist on\n" " creating a dependent string and failing if not. Also has options to\n" " control the heap the string object is allocated into:\n" " \n" " - tenured: if true, allocate in the tenured heap or throw. If false,\n" " allocate in the nursery or throw.\n" " - suppress-contraction: prevent the optimization of using a base's base rather\n" " than creating a chain of dependent string bases."),
JS_FN_HELP("ensureLinearString", EnsureLinearString, 1, 0, "ensureLinearString(str)", " Ensures str is a linear (non-rope) string and returns it."),
JS_FN_HELP("representativeStringArray", RepresentativeStringArray, 0, 0, "representativeStringArray()", " Returns an array of strings that represent the various internal string\n" " types and character encodings."),
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
JS_FN_HELP("oomThreadTypes", OOMThreadTypes, 0, 0, "oomThreadTypes()", " Get the number of thread types that can be used as an argument for\n" " oomAfterAllocations() and oomAtAllocation()."),
JS_FN_HELP("oomAfterAllocations", OOMAfterAllocations, 2, 0, "oomAfterAllocations(count [,threadType])", " After 'count' js_malloc memory allocations, fail every following allocation\n" " (return nullptr). The optional thread type limits the effect to the\n" " specified type of helper thread."),
JS_FN_HELP("oomAtAllocation", OOMAtAllocation, 2, 0, "oomAtAllocation(count [,threadType])", " After 'count' js_malloc memory allocations, fail the next allocation\n" " (return nullptr). The optional thread type limits the effect to the\n" " specified type of helper thread."),
JS_FN_HELP("resetOOMFailure", ResetOOMFailure, 0, 0, "resetOOMFailure()", " Remove the allocation failure scheduled by either oomAfterAllocations() or\n" " oomAtAllocation() and return whether any allocation had been caused to fail."),
JS_FN_HELP("oomTest", OOMTest, 0, 0, "oomTest(function, [expectExceptionOnFailure = true | options])", " Test that the passed function behaves correctly under OOM conditions by\n" " repeatedly executing it and simulating allocation failure at successive\n" " allocations until the function completes without seeing a failure.\n" " By default this tests that an exception is raised if execution fails, but\n" " this can be disabled by passing false as the optional second parameter.\n" " This is also disabled when --fuzzing-safe is specified.\n" " Alternatively an object can be passed to set the following options:\n" " expectExceptionOnFailure: bool - as described above.\n" " keepFailing: bool - continue to fail after first simulated failure.\n" "\n" " WARNING: By design, oomTest assumes the test-function follows the same\n" " code path each time it is called, right up to the point where OOM occurs.\n" " If on iteration 70 it finishes and caches a unit of work that saves 65\n" " allocations the next time we run, then the subsequent 65 allocation\n" " points will go untested.\n" "\n" " Things in this category include lazy parsing and baseline compilation,\n" " so it is very easy to accidentally write an oomTest that only tests one\n" " or the other of those, and not the functionality you meant to test!\n" " To avoid lazy parsing, call the test function once first before passing\n" " it to oomTest. The jits can be disabled via the test harness.\n"),
JS_FN_HELP("stackTest", StackTest, 0, 0, "stackTest(function, [expectExceptionOnFailure = true])", " This function behaves exactly like oomTest with the difference that\n" " instead of simulating regular OOM conditions, it simulates the engine\n" " running out of stack space (failing recursion check).\n" "\n" " See the WARNING in help('oomTest').\n"),
JS_FN_HELP("interruptTest", InterruptTest, 0, 0, "interruptTest(function)", " This function simulates interrupts similar to how oomTest simulates OOM conditions." "\n" " See the WARNING in help('oomTest').\n"),
JS_FN_HELP("newRope", NewRope, 3, 0, "newRope(left, right[, options])", " Creates a rope with the given left/right strings.\n" " Available options:\n" " nursery: bool - force the string to be created in/out of the nursery, if possible.\n"),
JS_FN_HELP("isRope", IsRope, 1, 0, "isRope(str)", " Returns true if the parameter is a rope"),
JS_FN_HELP("settlePromiseNow", SettlePromiseNow, 1, 0, "settlePromiseNow(promise)", " 'Settle' a 'promise' immediately. This just marks the promise as resolved\n" " with a value of `undefined` and causes the firing of any onPromiseSettled\n" " hooks set on Debugger instances that are observing the given promise's\n" " global as a debuggee."),
JS_FN_HELP("getWaitForAllPromise", GetWaitForAllPromise, 1, 0, "getWaitForAllPromise(densePromisesArray)", " Calls the 'GetWaitForAllPromise' JSAPI function and returns the result\n" " Promise."),
JS_FN_HELP("resolvePromise", ResolvePromise, 2, 0, "resolvePromise(promise, resolution)", " Resolve a Promise by calling the JSAPI function JS::ResolvePromise."),
#ifdef NIGHTLY_BUILD
JS_FN_HELP("safeResolvePromise", SafeResolvePromise, 2, 0, "safeResolvePromise(promise, resolution)", " Resolve a Promise by calling the JSAPI function JS::SafeResolve, which\n" " implements the SafePromiseResolve abstract operation from the\n" " thenable-curtailment proposal."),
#endif // NIGHTLY_BUILD
JS_FN_HELP("rejectPromise", RejectPromise, 2, 0, "rejectPromise(promise, reason)", " Reject a Promise by calling the JSAPI function JS::RejectPromise."),
JS_FN_HELP("makeFinalizeObserver", MakeFinalizeObserver, 0, 0, "makeFinalizeObserver()", " Get a special object whose finalization increases the counter returned\n" " by the finalizeCount function."),
JS_FN_HELP("finalizeCount", FinalizeCount, 0, 0, "finalizeCount()", " Return the current value of the finalization counter that is incremented\n" " each time an object returned by the makeFinalizeObserver is finalized."),
JS_FN_HELP("resetFinalizeCount", ResetFinalizeCount, 0, 0, "resetFinalizeCount()", " Reset the value returned by finalizeCount()."),
JS_FN_HELP("unsetgczeal", UnsetGCZeal, 2, 0, "unsetgczeal(mode)", " Turn off the mode or modes given that were set with gczeal() or JS_GC_ZEAL\n" " and don't finish any ongoing collection that may be happening."),
JS_FN_HELP("schedulegc", ScheduleGC, 1, 0, "schedulegc([num])", " If num is given, schedule a GC after num allocations.\n" " Returns the number of allocations before the next trigger."),
JS_FN_HELP("selectforgc", SelectForGC, 0, 0, "selectforgc(obj1, obj2, ...)", " Schedule the given objects to be marked in the next GC slice."),
JS_FN_HELP("verifyprebarriers", VerifyPreBarriers, 0, 0, "verifyprebarriers()", " Start or end a run of the pre-write barrier verifier."),
JS_FN_HELP("verifypostbarriers", VerifyPostBarriers, 0, 0, "verifypostbarriers()", " Enable or disable the post-write barrier verifier."),
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."),
JS_FN_HELP("dumpGCArenaInfo", DumpGCArenaInfo, 0, 0, "dumpGCArenaInfo()", " Prints information about the different GC things and how they are arranged\n" " in arenas.\n"),
JS_FN_HELP("setMarkStackLimit", SetMarkStackLimit, 1, 0, "markStackLimit(limit)", " Sets a limit on the number of words used for the mark stack. Used to test OOM" " handling during marking.\n"),
#endif
JS_FN_HELP("gcstate", GCState, 0, 0, "gcstate([obj])", " Report the global GC state, or the GC state for the zone containing |obj|."),
JS_FN_HELP("schedulezone", ScheduleZoneForGC, 1, 0, "schedulezone([obj | string])", " If obj is given, schedule a GC of obj's zone.\n" " If string is given, schedule a GC of the string's zone if possible."),
JS_FN_HELP("startgc", StartGC, 1, 0, "startgc([n [, 'shrinking']])", " Start an incremental GC and run a slice that processes about n objects.\n" " If 'shrinking' is passesd as the optional second argument, perform a\n" " shrinking GC rather than a normal GC. If no zones have been selected with\n" " schedulezone(), a full GC will be performed."),
JS_FN_HELP("finishgc", FinishGC, 0, 0, "finishgc()", " Finish an in-progress incremental GC, if none is running then do nothing."),
JS_FN_HELP("gcslice", GCSlice, 1, 0, "gcslice([n [, options]])", " Start or continue an an incremental GC, running a slice that processes\n" " about n objects. Takes an optional options object, which may contain the\n" " following properties:\n" " dontStart: do not start a new incremental GC if one is not already\n" " running"),
JS_FN_HELP("abortgc", AbortGC, 1, 0, "abortgc()", " Abort the current incremental GC."),
JS_FN_HELP("isAtomMarked", IsAtomMarked, 2, 0, "isAtomMarked(obj, atom)", " Return whether |atom| is marked relative to the zone containing |obj|."),
JS_FN_HELP("getAtomMarkIndex", GetAtomMarkIndex, 1, 0, "getAtomMarkIndex(atom)", " Return the atom marking bitmap's index for |atom|."),
JS_FN_HELP("getAtomMarkColor", GetAtomMarkColor, 2, 0, "getAtomMarkColor(obj, index)", " Return the atom marking bitmap's mark color for |index| relative to the zone containing |obj|."),
JS_FN_HELP("setMallocMaxDirtyPageModifier", SetMallocMaxDirtyPageModifier, 1, 0, "setMallocMaxDirtyPageModifier(value)", " Change the maximum size of jemalloc's page cache. The value should be between\n" " -5 and 16 (inclusive). See moz_set_max_dirty_page_modifier.\n"),
JS_FN_HELP("fullcompartmentchecks", FullCompartmentChecks, 1, 0, "fullcompartmentchecks(true|false)", " If true, check for compartment mismatches before every GC."),
JS_FN_HELP("nondeterministicGetWeakMapSize", NondeterministicGetWeakMapSize, 1, 0, "nondeterministicGetWeakMapSize(weakmap)", " Returns the number of entries in the given WeakMap."),
JS_FN_HELP("nondeterministicGetWeakMapKeys", NondeterministicGetWeakMapKeys, 1, 0, "nondeterministicGetWeakMapKeys(weakmap)", " Return an array of the keys in the given WeakMap."),
JS_FN_HELP("grayBitsValid", GrayBitsValid, 0, 0, "grayBitsValid()", " Return whether the gray bits state is valid."),
JS_FN_HELP("setGrayBitsInvalid", SetGrayBitsInvalid, 0, 0, "setGrayBitsInvalid()", " Set the gray bits state to invalid."),
JS_FN_HELP("internalConst", InternalConst, 1, 0, "internalConst(name)", " Query an internal constant for the engine. See InternalConst source for\n" " the list of constant names."),
JS_FN_HELP("isProxy", IsProxy, 1, 0, "isProxy(obj)", " If true, obj is a proxy of some sort"),
JS_FN_HELP("dumpHeap", DumpHeap, 1, 0, "dumpHeap([filename])", " Dump reachable and unreachable objects to the named file, or to stdout. Objects\n" " in the nursery are ignored, so if you wish to include them, consider calling\n" " minorgc() first."),
JS_FN_HELP("terminate", Terminate, 0, 0, "terminate()", " Terminate JavaScript execution, as if we had run out of\n" " memory or been terminated by the slow script dialog."),
JS_FN_HELP("readGeckoProfilingStack", ReadGeckoProfilingStack, 0, 0, "readGeckoProfilingStack()", " Reads the JIT/Wasm stack using ProfilingFrameIterator. Skips non-JIT/Wasm frames."),
JS_FN_HELP("readGeckoInterpProfilingStack", ReadGeckoInterpProfilingStack, 0, 0, "readGeckoInterpProfilingStack()", " Reads the C++ interpreter profiling stack. Skips JIT/Wasm frames."),
JS_FN_HELP("enableOsiPointRegisterChecks", EnableOsiPointRegisterChecks, 0, 0, "enableOsiPointRegisterChecks()", " Emit extra code to verify live regs at the start of a VM call are not\n" " modified before its OsiPoint."),
JS_FN_HELP("displayName", DisplayName, 1, 0, "displayName(fn)", " Gets the display name for a function, which can possibly be a guessed or\n" " inferred name based on where the function was defined. This can be\n" " different from the 'name' property on the function."),
JS_FN_HELP("isAsmJSCompilationAvailable", IsAsmJSCompilationAvailable, 0, 0, "isAsmJSCompilationAvailable", " Returns whether asm.js compilation is currently available or whether it is disabled\n" " (e.g., by the debugger)."),
JS_FN_HELP("getJitCompilerOptions", GetJitCompilerOptions, 0, 0, "getJitCompilerOptions()", " Return an object describing some of the JIT compiler options.\n"),
JS_FN_HELP("isAsmJSModule", IsAsmJSModule, 1, 0, "isAsmJSModule(fn)", " Returns whether the given value is a function containing \"use asm\" that has been\n" " validated according to the asm.js spec."),
JS_FN_HELP("isAsmJSFunction", IsAsmJSFunction, 1, 0, "isAsmJSFunction(fn)", " Returns whether the given value is a nested function in an asm.js module that has been\n" " both compile- and link-time validated."),
JS_FN_HELP("isAvxPresent", IsAvxPresent, 0, 0, "isAvxPresent([minVersion])", " Returns whether AVX is present and enabled. If minVersion specified,\n" " use 1 - to check if AVX is enabled (default), 2 - if AVX2 is enabled."),
JS_FN_HELP("wasmIsSupported", WasmIsSupported, 0, 0, "wasmIsSupported()", " Returns a boolean indicating whether WebAssembly is supported on the current device."),
JS_FN_HELP("wasmIsSupportedByHardware", WasmIsSupportedByHardware, 0, 0, "wasmIsSupportedByHardware()", " Returns a boolean indicating whether WebAssembly is supported on the current hardware (regardless of whether we've enabled support)."),
JS_FN_HELP("wasmDebuggingEnabled", WasmDebuggingEnabled, 0, 0, "wasmDebuggingEnabled()", " Returns a boolean indicating whether WebAssembly debugging is supported on the current device;\n" " returns false also if WebAssembly is not supported"),
JS_FN_HELP("wasmStreamingEnabled", WasmStreamingEnabled, 0, 0, "wasmStreamingEnabled()", " Returns a boolean indicating whether WebAssembly caching is supported by the runtime."),
JS_FN_HELP("wasmCachingEnabled", WasmCachingEnabled, 0, 0, "wasmCachingEnabled()", " Returns a boolean indicating whether WebAssembly caching is supported by the runtime."),
JS_FN_HELP("wasmHugeMemorySupported", WasmHugeMemorySupported, 0, 0, "wasmHugeMemorySupported()", " Returns a boolean indicating whether WebAssembly supports using a large" " virtual memory reservation in order to elide bounds checks on this platform."),
JS_FN_HELP("wasmHugeMemoryEnabled", WasmHugeMemoryEnabled, 0, 0, "wasmHugeMemoryEnabled([addressType[, pageSizeBytes]])", " Returns a boolean indicating whether WebAssembly huge memory is enabled at" " runtime for the given address type (\"i32\" or \"i64\", default \"i32\") and" " page size in bytes (default 65536)."),
JS_FN_HELP("wasmMaxMemoryPages", WasmMaxMemoryPages, 1, 0, "wasmMaxMemoryPages(addressType)", " Returns an int with the maximum number of pages that can be allocated to a memory." " This is an implementation artifact that does depend on the address type, the hardware," " the operating system, the build configuration, and flags. The result is constant for" " a given combination of those; there is no guarantee that that size allocation will" " always succeed, only that it can succeed in principle. The addressType is a string," " 'i32' or 'i64'."),
JS_FN_HELP("getWasmSupportedFeatures", GetWasmSupportedFeatures, 0, 0, "getWasmSupportedFeatures()", " Get the wasm features SpiderMonkey was built with support for.\n"),
JS_FN_HELP("getWasmEnabledFeatures", GetWasmEnabledFeatures, 0, 0, "getWasmEnabledFeatures()", " Get the wasm features that are runtime enabled in SpiderMonkey.\n"),
#define WASM_FEATURE(NAME, ...) \
JS_FN_HELP("wasm"#NAME"Enabled", Wasm##NAME##Enabled, 0, 0, \ "wasm"#NAME"Enabled()", \ " Returns a boolean indicating whether the WebAssembly "#NAME" proposal is enabled."),
JS_FOR_WASM_FEATURES(WASM_FEATURE) #undef WASM_FEATURE
JS_FN_HELP("wasmThreadsEnabled", WasmThreadsEnabled, 0, 0, "wasmThreadsEnabled()", " Returns a boolean indicating whether the WebAssembly threads proposal is\n" " supported on the current device."),
JS_FN_HELP("wasmSimdEnabled", WasmSimdEnabled, 0, 0, "wasmSimdEnabled()", " Returns a boolean indicating whether WebAssembly SIMD proposal is\n" " supported by the current device."),
#ifdefined(ENABLE_WASM_SIMD) && defined(DEBUG)
JS_FN_HELP("wasmSimdAnalysis", WasmSimdAnalysis, 1, 0, "wasmSimdAnalysis(...)", " Unstable API for white-box testing.\n"), #endif
JS_FN_HELP("wasmGlobalFromArrayBuffer", WasmGlobalFromArrayBuffer, 2, 0, "wasmGlobalFromArrayBuffer(type, arrayBuffer)", " Create a WebAssembly.Global object from a provided ArrayBuffer. The type\n" " must be POD (i32, i64, f32, f64, v128). The buffer must be the same\n" " size as the type in bytes.\n"),
JS_FN_HELP("wasmGlobalExtractLane", WasmGlobalExtractLane, 3, 0, "wasmGlobalExtractLane(global, laneInterp, laneIndex)", " Extract a lane from a WebAssembly.Global object that contains a v128 value\n" " and return it as a new WebAssembly.Global object of the appropriate type.\n" " The supported laneInterp values are i32x4, i64x2, f32x4, and\n" " f64x2.\n"),
JS_FN_HELP("wasmGlobalsEqual", WasmGlobalsEqual, 2, 0, "wasmGlobalsEqual(globalA, globalB)", " Compares two WebAssembly.Global objects for if their types and values are\n" " equal. Mutability is not compared. Floating point values are compared for\n" " bitwise equality, not IEEE 754 equality.\n"),
JS_FN_HELP("wasmGlobalIsNaN", WasmGlobalIsNaN, 2, 0, "wasmGlobalIsNaN(global, flavor)", " Compares a floating point WebAssembly.Global object for if its value is a\n" " specific NaN flavor. Valid flavors are `arithmetic_nan` and `canonical_nan`.\n"),
JS_FN_HELP("wasmGlobalToString", WasmGlobalToString, 1, 0, "wasmGlobalToString(global)", " Returns a debug representation of the contents of a WebAssembly.Global\n" " object.\n"),
JS_FN_HELP("wasmLosslessInvoke", WasmLosslessInvoke, 1, 0, "wasmLosslessInvoke(wasmFunc, args...)", " Invokes the provided WebAssembly function using a modified conversion\n" " function that allows providing a param as a WebAssembly.Global and\n" " returning a result as a WebAssembly.Global.\n"),
JS_FN_HELP("wasmCompilersPresent", WasmCompilersPresent, 0, 0, "wasmCompilersPresent()", " Returns a string indicating the present wasm compilers: a comma-separated list\n" " of 'baseline', 'ion'. A compiler is present in the executable if it is compiled\n" " in and can generate code for the current architecture."),
JS_FN_HELP("wasmCompileMode", WasmCompileMode, 0, 0, "wasmCompileMode()", " Returns a string indicating the available wasm compilers: 'baseline', 'ion',\n" " 'baseline+ion', or 'none'. A compiler is available if it is present in the\n" " executable and not disabled by switches or runtime conditions. At most one\n" " baseline and one optimizing compiler can be available."),
JS_FN_HELP("wasmLazyTieringEnabled", WasmLazyTieringEnabled, 0, 0, "wasmLazyTieringEnabled()", " Returns a boolean indicating whether compilation will be performed\n" " using lazy tiering."),
JS_FN_HELP("wasmBaselineDisabledByFeatures", WasmBaselineDisabledByFeatures, 0, 0, "wasmBaselineDisabledByFeatures()", " If some feature is enabled at compile-time or run-time that prevents baseline\n" " from being used then this returns a truthy string describing the features that\n." " are disabling it. Otherwise it returns false."),
JS_FN_HELP("wasmIonDisabledByFeatures", WasmIonDisabledByFeatures, 0, 0, "wasmIonDisabledByFeatures()", " If some feature is enabled at compile-time or run-time that prevents Ion\n" " from being used then this returns a truthy string describing the features that\n." " are disabling it. Otherwise it returns false."),
JS_FN_HELP("wasmHasTier2CompilationCompleted", WasmHasTier2CompilationCompleted, 1, 0, "wasmHasTier2CompilationCompleted(module)", " Returns a boolean indicating whether a given module has finished compiled code for tier2. \n" "This will return true early if compilation isn't two-tiered. "),
JS_FN_HELP("wasmLoadedFromCache", WasmLoadedFromCache, 1, 0, "wasmLoadedFromCache(module)", " Returns a boolean indicating whether a given module was deserialized directly from a\n" " cache (as opposed to compiled from bytecode)."),
JS_FN_HELP("wasmBuiltinI8VecMul", WasmBuiltinI8VecMul, 0, 0, "wasmBuiltinI8VecMul()", " Returns a module that implements an i8 vector pairwise multiplication intrinsic."),
JS_FN_HELP("wasmGcReadField", WasmGcReadField, 2, 0, "wasmGcReadField(obj, index)", " Gets a field of a WebAssembly GC struct or array."),
JS_FN_HELP("wasmGcArrayLength", WasmGcArrayLength, 1, 0, "wasmGcArrayLength(arr)", " Gets the length of a WebAssembly GC array."),
#ifdef ENABLE_WASM_BRANCH_HINTING
JS_FN_HELP("wasmParsedBranchHints", WasmParsedBranchHints, 1, 0, "wasmParsedBranchHints(module)", " Returns a boolean indicating whether a given module has successfully parsed a\n" " custom branch hinting section."),
#endif// ENABLE_WASM_BRANCH_HINTING
JS_FN_HELP("largeArrayBufferSupported", LargeArrayBufferSupported, 0, 0, "largeArrayBufferSupported()", " Returns true if array buffers larger than 2GB can be allocated."),
JS_FN_HELP("isLazyFunction", IsLazyFunction, 1, 0, "isLazyFunction(fun)", " True if fun is a lazy JSFunction."),
JS_FN_HELP("isRelazifiableFunction", IsRelazifiableFunction, 1, 0, "isRelazifiableFunction(fun)", " True if fun is a JSFunction with a relazifiable JSScript."),
JS_FN_HELP("hasSameBytecodeData", HasSameBytecodeData, 2, 0, "hasSameBytecodeData(fun1, fun2)", " True if fun1 and fun2 share the same copy of bytecode data. This will\n" " delazify the function if necessary."),
JS_FN_HELP("enableShellAllocationMetadataBuilder", EnableShellAllocationMetadataBuilder, 0, 0, "enableShellAllocationMetadataBuilder()", " Use ShellAllocationMetadataBuilder to supply metadata for all newly created objects."),
JS_FN_HELP("getAllocationMetadata", GetAllocationMetadata, 1, 0, "getAllocationMetadata(obj)", " Get the metadata for an object."),
JS_INLINABLE_FN_HELP("bailout", testingFunc_bailout, 0, 0, TestBailout, "bailout()", " Force a bailout out of ionmonkey (if running in ionmonkey)."),
JS_FN_HELP("bailAfter", testingFunc_bailAfter, 1, 0, "bailAfter(number)", " 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()", " Returns true when called within (jit-)compiled code. When jit compilation is disabled this\n" " function returns an error string. This function returns false in all other cases.\n" " Depending on truthiness, you should continue to wait for compilation to happen or stop execution.\n"),
JS_FN_HELP("inIon", testingFunc_inIon, 0, 0, "inIon()", " Returns true when called within ion. When ion is disabled or when compilation is abnormally\n" " slow to start, this function returns an error string. Otherwise, this function returns false.\n" " This behaviour ensures that a falsy value means that we are not in ion, but expect a\n" " compilation to occur in the future. Conversely, a truthy value means that we are either in\n" " ion or that there is litle or no chance of ion ever compiling the current script."),
JS_FN_HELP("assertJitStackInvariants", TestingFunc_assertJitStackInvariants, 0, 0, "assertJitStackInvariants()", " Iterates the Jit stack and check that stack invariants hold."),
JS_FN_HELP("setIonCheckGraphCoherency", SetIonCheckGraphCoherency, 1, 0, "setIonCheckGraphCoherency(bool)", " Set whether Ion should perform graph consistency (DEBUG-only) assertions. These assertions\n" " are valuable and should be generally enabled, however they can be very expensive for large\n" " (wasm) programs."),
JS_FN_HELP("serialize", testingFunc_serialize, 1, 0, "serialize(data, [transferables, [policy]])", " Serialize 'data' using JS_WriteStructuredClone. Returns a structured\n" " clone buffer object. 'policy' may be an options hash. Valid keys:\n" " 'SharedArrayBuffer' - either 'allow' or 'deny' (the default)\n" " to specify whether SharedArrayBuffers may be serialized.\n" " 'scope' - SameProcess, DifferentProcess, or\n" " DifferentProcessForIndexedDB. Determines how some values will be\n" " serialized. Clone buffers may only be deserialized with a compatible\n" " scope. NOTE - For DifferentProcess/DifferentProcessForIndexedDB,\n" " must also set SharedArrayBuffer:'deny' if data contains any shared memory\n" " object."),
JS_FN_HELP("deserialize", Deserialize, 1, 0, "deserialize(clonebuffer[, opts])", " Deserialize data generated by serialize. 'opts' may be an options hash.\n" " Valid keys:\n" " 'SharedArrayBuffer' - either 'allow' or 'deny' (the default)\n" " to specify whether SharedArrayBuffers may be serialized.\n" " 'scope', which limits the clone buffers that are considered\n" " valid. Allowed values: ''SameProcess', 'DifferentProcess',\n" " and 'DifferentProcessForIndexedDB'. So for example, a\n" " DifferentProcessForIndexedDB clone buffer may be deserialized in any scope, but\n" " a SameProcess clone buffer cannot be deserialized in a\n" " DifferentProcess scope."),
JS_FN_HELP("detachArrayBuffer", DetachArrayBuffer, 1, 0, "detachArrayBuffer(buffer)", " Detach the given ArrayBuffer object from its memory, i.e. as if it\n" " had been transferred to a WebWorker."),
JS_FN_HELP("makeSerializable", MakeSerializable, 1, 0, "makeSerializable(numeric id, [behavior])", " Make a custom serializable, transferable object. It will have a single accessor\n" " obj.log that will give a history of all operations on all such objects in the\n" " current thread as an array [id, action, id, action, ...] where the id\n" " is the number passed into this function, and the action is one of:\n" " ? - the canTransfer() hook was called.\n" " w - the write() hook was called.\n" " W - the writeTransfer() hook was called.\n" " R - the readTransfer() hook was called.\n" " r - the read() hook was called.\n" " F - the freeTransfer() hook was called.\n" " The `behavior` parameter can be used to force a failure during processing:\n" " 1 - fail during readTransfer() hook\n" " 2 - fail during read() hook\n" " Set the log to null to clear it."),
JS_FN_HELP("ensureNonInline", EnsureNonInline, 1, 0, "ensureNonInline(view or buffer)", " Ensure that the memory for the given ArrayBuffer or ArrayBufferView\n" " is not inline."),
JS_FN_HELP("stealArrayBufferContents", StealArrayBufferContents, 1, 0, "stealArrayBufferContents(buffer)", " Steal the contents of the given ArrayBuffer using JS::StealArrayBufferContents\n" " and return a new ArrayBuffer wrapping the stolen contents. The original buffer\n" " is detached."),
JS_FN_HELP("pinArrayBufferOrViewLength", PinArrayBufferOrViewLength, 1, 0, "pinArrayBufferOrViewLength(view or buffer[, pin])", " Prevent or allow (if `pin` is false) changes to the length of the given\n" " ArrayBuffer or ArrayBufferView. `pin` defaults to true."),
JS_FN_HELP("JSONStringify", JSONStringify, 4, 0, "JSONStringify(value, behavior)", " Same as JSON.stringify(value), but allows setting behavior:\n" " Normal: the default\n" " FastOnly: throw if the fast path bails\n" " SlowOnly: skip the fast path entirely\n" " Compare: run both the fast and slow paths and compare the result. Crash if\n" " they do not match. If the fast path bails, no comparison is done."),
JS_FN_HELP("helperThreadCount", HelperThreadCount, 0, 0, "helperThreadCount()", " Returns the number of helper threads available for off-thread tasks."),
JS_FN_HELP("createShapeSnapshot", CreateShapeSnapshot, 1, 0, "createShapeSnapshot(obj)", " Returns an object containing a shape snapshot for use with\n" " checkShapeSnapshot.\n"),
JS_FN_HELP("checkShapeSnapshot", CheckShapeSnapshot, 2, 0, "checkShapeSnapshot(snapshot, [obj])", " Check shape invariants based on the given snapshot and optional object.\n" " If there's no object argument, the snapshot's object is used.\n"),
JS_FN_HELP("reportOutOfMemory", ReportOutOfMemory, 0, 0, "reportOutOfMemory()", " Report OOM, then clear the exception and return undefined. For crash testing."),
JS_FN_HELP("throwOutOfMemory", ThrowOutOfMemory, 0, 0, "throwOutOfMemory()", " Throw out of memory exception, for OOM handling testing."),
JS_FN_HELP("reportLargeAllocationFailure", ReportLargeAllocationFailure, 0, 0, "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."),
JS_FN_HELP("findPath", FindPath, 2, 0, "findPath(start, target)", " Return an array describing one of the shortest paths of GC heap edges from\n" " |start| to |target|, or |undefined| if |target| is unreachable from |start|.\n" " Each element of the array is either of the form:\n" " { node: <object or string>, edge: <string describing edge from node> }\n" " if the node is a JavaScript object or value; or of the form:\n" " { type: <string describing node>, edge: <string describing edge> }\n" " if the node is some internal thing that is not a proper JavaScript value\n" " (like a shape or a scope chain element). The destination of the i'th array\n" " element's edge is the node of the i+1'th array element; the destination of\n" " the last array element is implicitly |target|.\n"),
JS_FN_HELP("sharedMemoryEnabled", SharedMemoryEnabled, 0, 0, "sharedMemoryEnabled()", " Return true if SharedArrayBuffer and Atomics are enabled"),
JS_FN_HELP("sharedArrayRawBufferRefcount", SharedArrayRawBufferRefcount, 0, 0, "sharedArrayRawBufferRefcount(sab)", " Return the reference count of the SharedArrayRawBuffer object held by sab"),
#ifdef NIGHTLY_BUILD
JS_FN_HELP("objectAddress", ObjectAddress, 1, 0, "objectAddress(obj)", " Return the current address of the object. For debugging only--this\n" " address may change during a moving GC."),
JS_FN_HELP("scriptAddressForFunction", ScriptAddressForFunction, 1, 0, "scriptAddressForFunction(fun)", " Return the current address of a function's script."),
JS_FN_HELP("sharedAddress", SharedAddress, 1, 0, "sharedAddress(obj)", " Return the address of the shared storage of a SharedArrayBuffer."), #endif
JS_FN_HELP("hasInvalidatedTeleporting", HasInvalidatedTeleporting, 1, 0, "hasInvalidatedTeleporting(obj)", " Return true if the shape teleporting optimization has been disabled for |obj|."),
JS_FN_HELP("evalReturningScope", EvalReturningScope, 1, 0, "evalReturningScope(scriptStr, [global])", " Evaluate the script in a new scope and return the scope.\n" " If |global| is present, clone the script to |global| before executing."),
JS_FN_HELP("backtrace", DumpBacktrace, 1, 0, "backtrace()", " Dump out a brief backtrace."),
JS_FN_HELP("getBacktrace", GetBacktrace, 1, 0, "getBacktrace([options])", " Return the current stack as a string. Takes an optional options object,\n" " which may contain any or all of the boolean properties:\n" " options.args - show arguments to each function\n" " options.locals - show local variables in each frame\n" " options.thisprops - show the properties of the 'this' object of each frame\n"),
JS_FN_HELP("byteSize", ByteSize, 1, 0, "byteSize(value)", " Return the size in bytes occupied by |value|, or |undefined| if value\n" " is not allocated in memory.\n"),
JS_FN_HELP("byteSizeOfScript", ByteSizeOfScript, 1, 0, "byteSizeOfScript(f)", " Return the size in bytes occupied by the function |f|'s JSScript.\n"),
JS_FN_HELP("setImmutablePrototype", SetImmutablePrototype, 1, 0, "setImmutablePrototype(obj)", " Try to make obj's [[Prototype]] immutable, such that subsequent attempts to\n" " change it will fail. Return true if obj's [[Prototype]] was successfully made\n" " immutable (or if it already was immutable), false otherwise. Throws in case\n" " of internal error, or if the operation doesn't even make sense (for example,\n" " /* This Source Code Form issubjectto the terms ofthe Mozilla Public
JS_FN_HELP("allocationMarker", AllocationMarker, 0, 0,
)" Returnjava.lang.StringIndexOutOfBoundsException: Range [20, 19) out of bounds for length 63 "\".Suchobjectsareallocatedonlyby\n " to this function, never implicitly/java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75 "0, 0 0 ,0 ,0,0 ,0java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 55 " 0,, 0, ,0 0 ,0,0, , " java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
"setGCCallback" ,1,0,
setGCCallback\..\,options.), " Set; " dstPtr+ (as32 &xF)java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39 " 'majorGC' - a , nesting up to a given 'depth'n)java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75
java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 3
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 " sbInitialLen); "Add the to at every GC. Note\" " that the objects actually be marked the beginning of ,but\" " the slicethey will be marked so nothing will happen.)\" " \n" " Instead of an object, java.lang.StringIndexOutOfBoundsException: Range [51, 50) out of bounds for length 57 " 'yield' - cause the current marking slice java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 23 " exceededreturn true; " 'enter-weak-marking-mode' - divide the list into two segments. Theclass < { " java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 0 " marking mode may be entered java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 34 " abort-eak--' same above thenabortweak fall\" " the iterative .\" ' fully drainthe stack before .\n" "'et--lack' everything in the in the queue to markedblack.n"
with the GCuntil , forcen" "following in the mark queue to be marked gray.\n" " '
(getMarkQueue,GetMarkQueue0 java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50 "getMarkQueue()",
java.lang.StringIndexOutOfBoundsException: Range [73, 72) out of bounds for length 79 " returned values will be wrapped into the current compartment, so this loses\*requires portions in " some fidelity."),iffoundCycle) java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31 #endif// DEBUG
JS_FN_HELPwroteMember=; "nurseryStringsEnabled()", " Return whether strings are currently allocated in the nursery for the current\n" " global\n"),
JS_FN_HELPjava.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 "isNurseryAllocated !java.lang.StringIndexOutOfBoundsException: Range [21, 20) out of bounds for length 40
n,
JS_FN_HELP("// the length of an object for which JS// either an ArrayObject or a proxy wrapping one.
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
that java.lang.StringIndexOutOfBoundsException: Range [62, 61) out of bounds for length 80 " global\n") StringifyContextscx) {
gjava.lang.StringIndexOutOfBoundsException: Range [28, 27) out of bounds for length 48 "getLcovInfo(global)", " Generate LCOV tracefile forCycleDetector detect(scx obj); " the java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 0
#ifdef
JS_FN_HELP( "setRNGState(* SerializeJSONProper method is up into getting the java.lang.StringIndexOutOfBoundsException: Index 77 out of bounds for length 77 " Set this compartment's RNG state.\n"), #endif
) -java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75
java.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 19 " #endif
JS_FN_HELP(;
java.lang.StringIndexOutOfBoundsException: Range [72, 17) out of bounds for length 17
reflecting time\ " This is java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 5
java.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 60 " " "nput: must includereachable
uses compatible profiler\)java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 55
(isConstructor,IsConstructor, 1 , "isConstructor(value)", " Returns java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
JS_FN_HELP("getTimeZone INELIGIBLE_OBJECT " (PI " Get the current time zone.\n"),
JS_FN_HELP("getCoreCount", GetCoreCountclass { " numElements; " Get the numberelement(0, " means the number of hyperthreads on systems where that makes
JS_FN_HELP( "scriptedCallerGlobal uint32_t ( const {return element;} " Get the caller's global
JS_FN_HELP("objectGlobal", java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 0
)", " ;
JS_FN_HELP("isSameCompartment",java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7 "sSameCompartment(obj1, obj2),
returns theunwrappedobjectsaren " same-compartment. java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
" java.lang.StringIndexOutOfBoundsException: Range [68, 67) out of bounds for length 74
ompartment, " Returns the first global in obj's compartment.\ // See https://stackoverflow.com/a/52856349.
JS_FN_HELP("assertCorrectRealm",// that fails if it encounters any accessor properties, as they are not handled "assertCorrectRealm()", " Asserts cx-> // if any enumerable non-data properties are encountered.
JS_FN_HELP("globalLexicals", GlobalLexicals, 0, 0,
globalLexicalsjava.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
ancontainingcopyall lexicalbindings\ " //- no can beskipped.
JS_FN_HELP("baselineCompile", BaselineCompile, 2, 0, "baselineCompile([fun prop; " Baseline-compiles the given JS function or script.\n"
arguments baseline-compilesthecallersscript \" " that return sb.append("ull)java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29 " running thejava.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15
baselineCompile; vari0 <1 i+ }.n " / . " baselineCompile returned a MOZ_CRASH("houldvalidatedprintablevaluealready)
JS_FN_HELP("setBaselineHintjava.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
java.lang.StringIndexOutOfBoundsException: Range [20, 16) out of bounds for length 23 " Sets a baseline JIT hint for the given function, marking it for eager\n" " baseline compilation (>;
JS_FN_HELP("hasBaselineHint", HasBaselineHint, 1, 0, "hasBaselineHint(fun)", " Returns true }
JS_FN_HELPrecordIonCompilationForHintsRecordIonCompilationForHints ,
NativeObject obj=&p-toObject(.<NativeObject>) "() " Records Ion compilation hints return true; " The function must already be baseline /fast path.
JS_FN_HELP("hasMegamorphicIC", HasMegamorphicIC, 1, 0, "" " Returns true if any fallback stub in the function's JIT script is at " Megamorphic or // objects. For each object, first the dense elements are iterated, then the // handled separately in the FastSerializeJSONProperty code. "resetFallbackStubStates(fun)", " Resets all java.lang.StringIndexOutOfBoundsException: Range [0, 22) out of bounds for length 18
JS_FN_HELP("_FN_HELP(("",EncodeAsUtf8InBuffer, 2, 0 "encodeAsUtf8InBuffer(str,uint8Array)", " Encode as many whole code points from the string str into -sb.append(rawJSON)java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35 " Uint8Array as will completely fit in it, converting lone surrogates to\n" " REPLACEMENT CHARACTER* " number of 16-bit units read and |w| is java.lang.StringIndexOutOfBoundsException: Range [16, 15) out of bounds for length 80 " written."),
*Algorithm
JS_FN_HELP("clearKeptObjects", ClearKeptObjects, java.lang.StringIndexOutOfBoundsException: Range [0, 53) out of bounds for length 26 "clearKeptObjects()", "Perform the ECMAScript ClearKeptObjects operation, clearing the list of\n" "observed WeakRef targets that are kept alive until the next synchronous\n" "sequence of * wroteMember "WeakRefs.\n"),
JS_FN_HELP except "numberToDouble(number)", " Return the input number as double-typed number."),
JS_FN_HELP("getICUOptions", GetICUOptions, 0, 0, "java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 " Return an java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 3 false " unicode: a string containing the Unicode " locale: the ICU if (!anFastStringifyObject(.obj) java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42 " tzdata-sbappend(op.isArray ? [':''){ " timezone: the ICU default time zone, e.g. 'America auto&iter=top..DenseElementsIteratorForJSON>)java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 63 " cx>hasPendingInterrupt(:CallbackCanWait) java.lang.StringIndexOutOfBoundsException: Index 72 out of bounds for length 72 " uint32_t index =iter.etIndex(;
getAvailableLocalesOfGetAvailableLocalesOf0 "getAvailableLocalesOf(name)", " Return an array
"" ,1, , " ifstack.()> MAX_STACK_DEPTH -1 java.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 56 " Returns true if a scripted op =FastStackEntry&.oObject)as<>);
JS_FN_HELP("compileToStencil", CompileToStencil, 1, 0, "compileToStencil(string, [options])",
() " for it."),
JS_FN_HELP("evalStencil", EvalStencil, 1, 0, "evalStencil(stencil, } " Instantiates the // numerically, which this code does not support. These objects are " defines."),
(compileToStencilXDRCompileToStencilXDR 1,0 "compileToStencilXDR(string, [options])", " Parses the given string argument as js script, produces the stencil" " for it, XDR-encodes the stencil, and returns an object that contains the" " XDR return false;
java.lang.StringIndexOutOfBoundsException: Range [15, 14) out of bounds for length 54 "valStencilXDR(stencilXDR options]"java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40 " the stencil XDR ,and evaluates top- it" " defines."),
JS_FN_HELP("getExceptionInfo", GetExceptionInfo, 1, 0, "getExceptionInfo(fun)", "Calls given functionand returns information about it" " throws. Returns null if the function didn't throw an exception.")java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
c )java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32 "nukeCCW(wrapper)", " Nuke a CrossCompartmentWrapper, which turns it into a DeadProxyObject."),
JS_FN_HELP();
java.lang.StringIndexOutOfBoundsException: Range [30, 28) out of bounds for length 32 " Runs the realm: use replacer transform values. * " Only available in fuzzing or debug builds, so usage should be guarded. "),
JS_FN_HELP("assertRuntimeFuseInvariants", // is passed in. If we end up having to add elements " ; "Runs runtime' fuseinvariant checks -these will on failure." " Only available in fuzzing or debug builds, so usage should be guarded. "),
JS_FN_HELP "isCCW(object return falsejava.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25 " Return true if an object is a CCW."),
JS_FN_HELP("popAllFusesInRealm", PopAllFusesInRealm, 0, 0, "popAllFusesInRealm()", " Pops all the fuses in the current realm"),
JS_FN_HELP("getLastOOMStackTrace", GetLastOOMStackTrace, 0, 0, "getLastOOMStackTrace()", " Returns the stack !){ " or null if no OOM stack /* Step 7. */
JS_FN_HELP("popAllFusesInRuntime", } " !str)java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15 " Pops all the fuses in the java.lang.StringIndexOutOfBoundsException: Range [17, 18) out of bounds for length 17
JS_FN_HELP("getAllPrefNames", GetAllPrefNames, 0, 0, "getAllPrefNames()", " Returns an array containing the names of all JS prefs."),
stringifyBehavior:)java.lang.StringIndexOutOfBoundsException: Index 71 out of bounds for length 71
gname,
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
JS_FN_HELP("hadOutOfMemory", HadOutOfMemory, 0, 0, "hadOutOfMemory()", " Return the runtime's internal hadOutOfMemory flag that is set when\n"
exceptionp.)java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 63
JS_FN_HELP("supportDifferentialTesting", TestingFunc_SupportDifferentialTesting, 0, 0, "supportDifferentialTesting()", " Return the value of JS::JSAtom* slowJSON = scx.sb.finishAtom
java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2 // clang-format on
// clang-format off
JSFunctionSpecWithHelpFuzzingUnsafeTestingFunctions]= java.lang.StringIndexOutOfBoundsException: Index 71 out of bounds for length 71
JS_FN_HELP<ParseRecordObject,2 entries(oots) "getErrorNotes(error)", " Returns an array of error notes.") returnfalse;
JS_FN_HELP("setTimeZone", SetTimeZone, 1, 0, "setTimeZone(tzname)", " Set the 'TZ' environment variable to the given time zone and applies the new } " The time zone given is validated according to the current java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 3 " An empty string or undefined
JS_FN_HELP"getRealmTimeZone,GetRealmTimeZone ,java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54 "getRealmTimeZone()", " Get the time }
JS_FN_HELP(" RootedFieldValue,3 value(arrayRoots)java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
setRealmTimeZone(tzname)",
Setthetimezone thecurrent\" " The java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 " An empty string or undefined resets the if () {
JS_FN_HELPelementRecord valuetoObject)asParseRecordObject(; "setDefaultLocale(locale)", " Set the runtime default locale to the given value.\n" " An empty string or undefined resets the runtime locale to (newElement.sUndefined() { " :Theinput is validated,it beavalid BCP-language tag.",
JS_FN_HELP("getRealmLocale", GetRealmLocale, 0, 0, "getRealmLocale()" JS:PropertyAttribute:, " Get the locale for the current realm."),
JS_FN_HELP("setRealmLocale", SetRealmLocale, 1, 0, "setRealmLocale(locale)",
Set locale forthe current realm\" " The locale must be a valid BCP-47 locale identifier.\n" " empty or resets the realm locale the system efault .",
JS_FN_HELP("isCollectingDelazifications", IsCollectingDelazifications, if!isNullOrUndefined() "isCollectingDelazifications(fun)", " True if script for the function is collecting delazifications."),
JS_FN_HELP("isDelazificationPopulatedFor", IsDelazificationsPopulated, 1, "isDelazificationPopulatedFor(fun)", " True if fun is available in the shared stencils."),
JS_FN_HELP("waitForDelazificationOf",
Value >contextValr (context)); " Block main thread execution until the function is made available in the\n" " shared stencils. If this function isn't sharing stencils, return immediately."),
JS_FN_HELP("waitForDone", "waitForDone(obj)", " Loop calling `RunJobs` until the `done` value of `obj` is true"),
JS_FN_HELP(getInnerMostEnvironmentObject, GetInnerMostEnvironmentObject 0,0, "getInnerMostEnvironmentObject()", " Return the inner-most environment object for current execution."),
JS_FN_HELP("getEnclosingEnvironmentObject", java.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 28 "getEnclosingEnvironmentObject(env)", " Return the enclosing environment object for given environment object."),
g,GetEnvironmentObjectType1 , "getEnvironmentObjectType(env)", " Return a java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 14
JS_FN_HELP("shortestPaths", ShortestPaths, 3, 0, "shortestPaths(targets, options)", " if (!linear) { " shortest retaining paths for return false; " is (!linearChars.init(cx, linear)) { " \n" " maxNumPaths: The maximum number of paths returned in each of those arrays\n" " (default 3).\n" " :The object to start paths .If not given,\" " the starting * Step 1. */
&; "getFuseState()", " Return an object describing the calling realm's fuse java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 54 " as well java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
#ifdefined(static inline bool IsJSONWhitespace(char16_t ch) {
(dumpObject DumpObject,1,0java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46 "dumpObject(obj)", "
JS_FN_HELP("dumpValue", DumpValue, 1, 0,
java.lang.StringIndexOutOfBoundsException: Range [12, 10) out of bounds for length 15
aninternalrepresentation of a value."),
JS_FN_HELP("dumpValueToString", DumpValueToString, 1, 0, "dumpValue(v)", " Return a dump of an java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
JS_FN_HELP("java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 13 "stringRepresentation(str)", " Return a human-readable description of } #endif
(" , "java.lang.StringIndexOutOfBoundsException: Range [14, 13) out of bounds for length 37 " Stringify java.lang.StringIndexOutOfBoundsException: Range [49, 48) out of bounds for length 57 " 'stable', 'best', 'baseline', or 'ion'; the default is 'stable'. If the request\n" " cannot be satisfied then java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 " until background compilation is complete."), else
JS_FN_HELP("wasmDis", WasmDisassemble, 1, 0, "wasmDis(wasmObject[, options])\n", " Disassembles generated machine code from an exported WebAssembly function,\n" " or from all the functions defined instatic const JSPropertySpec json_static_[] = java.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 56 " The `options` is an object with the following optional static JSObject* CreateJSONObject(JSContext* cx, JSProtoKey ke) { " asString: boolean - if true, return a string rather than printing on stderr,\n" " the default is false.\n" " tier: string - one of 'stable', 'best', 'baseline', or 'ion'; the default static const JSONClassSpec ={ " 'stable'.\n" " kinds: string - if set, and the wasmObject is a module or instance, a JSCLASS_HAS_CACHED_PROTOJSProto_JSON), " comma-separated list of the following keys, the default is `Function`:\n" " Function - functions defined in the module\n" " InterpEntry - C++-to-wasm stubs\n" " JitEntry - jitted-js-to-wasm stubs\n" " ImportInterpExit - wasm-to-C++ stubs\n" " ImportJitExit - wasm-to-jitted-JS stubs\n" " all - all kinds, including obscure ones\n"),
JS_FN_HELP("wasmModuleToText", WasmModuleToText, 1, 0, "wasmModuleToText(wasmModule[, options])\n", " Converts a compiled wasm module to the wasm text format.\n"),
JS_FN_HELP("wasmDumpIon", WasmDumpIon, 2, 0, "wasmDumpIon(bytecode, funcIndex)\n", "wasmDumpIon(bytecode, funcIndex)" " Returns a dump of compiling a function in the specified module with Ion, in" " the iongraph JSON format."),
JS_FN_HELP("wasmFunctionTier", WasmFunctionTier, 1, 0, "wasmFunctionTier(wasmFunc)\n", " Returns the best compiled tier for a function. Either 'baseline' or 'optimized'."),
JS_FN_HELP("wasmMetadataAnalysis", wasmMetadataAnalysis, 1, 0, "wasmMetadataAnalysis(wasmObject)", " Prints an analysis of the size of metadata on this wasm object.\n"),
JS_FS_HELP_END
}; // clang-format on
// clang-format off staticconst JSFunctionSpecWithHelp PCCountProfilingTestingFunctions[] = {
JS_FN_HELP("start", PCCountProfiling_Start, 0, 0, "start()", " Start PC count profiling."),
JS_FN_HELP("stop", PCCountProfiling_Stop, 0, 0, "stop()", " Stop PC count profiling."),
JS_FN_HELP("purge", PCCountProfiling_Purge, 0, 0, "purge()", " Purge the collected PC count profiling data."),
JS_FN_HELP("count", PCCountProfiling_ScriptCount, 0, 0, "count()", " Return the number of profiled scripts."),
JS_FN_HELP("summary", PCCountProfiling_ScriptSummary, 1, 0, "summary(index)", " Return the PC count profiling summary for the given script index.\n" " The script index must be in the range [0, pc.count())."),
JS_FN_HELP("contents", PCCountProfiling_ScriptContents, 1, 0, "contents(index)", " Return the complete profiling contents for the given script index.\n" " The script index must be in the range [0, pc.count())."),
JS_FS_HELP_END
}; // clang-format on
// clang-format off staticconst JSFunctionSpecWithHelp FdLibMTestingFunctions[] = {
JS_FN_HELP("pow", FdLibM_Pow, 2, 0, "pow(x, y)", " Return x ** y."),
#ifdef FUZZING_JS_FUZZILLI
uint32_t js::FuzzilliHashDouble(double value) { // We shouldn't GC here as this is called directly from IC code.
AutoUnsafeCallWithABI unsafe;
uint64_t v = mozilla::BitwiseCast<uint64_t>(value); return static_cast<uint32_t>(v) + static_cast<uint32_t>(v >> 32);
}
uint32_t js::FuzzilliHashBigInt(BigInt* bigInt) { // We shouldn't GC here as this is called directly from IC code.
AutoUnsafeCallWithABI unsafe; return bigInt->hash();
}
void js::FuzzilliHashObject(JSContext* cx, JSObject* obj) { // called from IC and baseline/interpreter
uint32_t hash;
FuzzilliHashObjectInl(cx, obj, &hash);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.