commit 3aebb6379edcbff17a326efe55a49aedeb54f9b8
parent 9d7920d565f5b935bd800ac3cb9a6f0261d2a97f
Author: Atila Butkovits <abutkovits@mozilla.com>
Date: Tue, 4 Nov 2025 02:34:36 +0200
Revert "Bug 1989115 - Remove UnsafeABIStrictness::AllowThrownExceptions r=mgaudet" for causing failures at Printer.cpp.
This reverts commit 1131839caa75339b375d8997ae46840a69aa4f78.
Revert "Bug 1989115 - Implement OOM stack trace capture r=jandem"
This reverts commit 51f685e3a63038eb4b7550d1e11194ec8eab0ce2.
Revert "Bug 1989115 - Add FixedBufferPrinter r=mgaudet"
This reverts commit be6b5737dce2b1f0de100036026dc92c39a01189.
Revert "Bug 1989115 - Track unsafe call with ABI state in release r=mgaudet,rhunt"
This reverts commit ce1cb61ef9dcc89f90cc41a4c6e6526cc9852415.
Diffstat:
11 files changed, 38 insertions(+), 287 deletions(-)
diff --git a/js/public/Printer.h b/js/public/Printer.h
@@ -323,28 +323,6 @@ class JS_PUBLIC_API JSSprinter : public StringPrinter {
JSString* release(JSContext* cx) { return releaseJS(cx); }
};
-// FixedBufferPrinter, print to a fixed-size buffer. The string in the buffer
-// will always be null-terminated after being passed to the constructor.
-class FixedBufferPrinter final : public GenericPrinter {
- private:
- // The first char in the buffer where put will append the next string
- char* buffer_;
- // The remaining size available in the buffer
- size_t size_;
-
- public:
- constexpr FixedBufferPrinter(char* buf, size_t size)
- : buffer_(buf), size_(size) {
- MOZ_ASSERT(buffer_);
- memset(buffer_, 0, size_);
- }
-
- // Puts |len| characters from |s| at the current position.
- // If the buffer fills up, this won't do anything.
- void put(const char* s, size_t len) override;
- using GenericPrinter::put; // pick up |put(const char* s);|
-};
-
// Fprinter, print a string directly into a file.
class JS_PUBLIC_API Fprinter final : public GenericPrinter {
private:
diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
@@ -10037,32 +10037,6 @@ static bool TestingFunc_SupportDifferentialTesting(JSContext* cx, unsigned argc,
return true;
}
-static bool GetLastOOMStackTrace(JSContext* cx, unsigned argc, Value* vp) {
- CallArgs args = CallArgsFromVp(argc, vp);
-
- if (!cx->hasOOMStackTrace()) {
- args.rval().setNull();
- return true;
- }
-
- const char* stackTrace = cx->getOOMStackTrace();
- if (!stackTrace) {
- args.rval().setNull();
- return true;
- }
-
- JSString* str = JS_NewStringCopyZ(cx, stackTrace);
- if (!str) {
- return false;
- }
-
- // Clear the stored OOM stack trace after retrieving it once.
- cx->unsetOOMStackTrace();
-
- args.rval().setString(str);
- return true;
-}
-
// clang-format off
static const JSFunctionSpecWithHelp TestingFunctions[] = {
JS_FN_HELP("gc", ::GC, 0, 0,
@@ -11181,12 +11155,6 @@ JS_FN_HELP("isSmallFunction", IsSmallFunction, 1, 0,
"popAllFusesInRealm()",
" Pops all the fuses in the current realm"),
- JS_FN_HELP("getLastOOMStackTrace", GetLastOOMStackTrace, 0, 0,
-"getLastOOMStackTrace()",
-" Returns the stack trace captured from the most recent out-of-memory exception,\n"
-" or null if no OOM stack trace is available. The stack trace shows the JavaScript\n"
-" call stack at the time the out-of-memory condition occurred."),
-
JS_FN_HELP("popAllFusesInRuntime", PopAllFusesInRuntime, 0, 0,
"popAllFusesInRuntime()",
" Pops all the fuses in the runtime"),
diff --git a/js/src/jit-test/tests/test_oom_comprehensive.js b/js/src/jit-test/tests/test_oom_comprehensive.js
@@ -1,32 +0,0 @@
-// |jit-test| --setpref=experimental.capture_oom_stack_trace=true; skip-if: !this.hasOwnProperty("getLastOOMStackTrace")
-
-function testStack() {
- function deepFunction() {
- function evenDeeper() {
- throwOutOfMemory();
- }
- return evenDeeper();
- }
- return deepFunction();
-}
-
-// Clear any existing trace
-var initialTrace = getLastOOMStackTrace();
-assertEq(initialTrace, null);
-
-try {
- testStack();
- assertEq(true, false, "Expected an OOM exception");
-} catch (e) {
- print("✓ Exception caught: " + e);
-
- // Check for captured stack trace
- var finalTrace = getLastOOMStackTrace();
- assertEq(finalTrace !== null, true, "Expected a stack trace after OOM");
-
- print(finalTrace);
-
- // Detailed analysis
- var lines = finalTrace.split('\n').filter(line => line.trim());
- assertEq(finalTrace.includes("#"), true);
-}
-\ No newline at end of file
diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
@@ -4885,6 +4885,7 @@ void MacroAssembler::setupAlignedABICall() {
dynamicAlignment_ = false;
}
+#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
void MacroAssembler::wasmCheckUnsafeCallWithABIPre() {
// Set the JSContext::inUnsafeCallWithABI flag.
loadPtr(Address(InstanceReg, wasm::Instance::offsetOfCx()),
@@ -4894,7 +4895,6 @@ void MacroAssembler::wasmCheckUnsafeCallWithABIPre() {
store32(Imm32(1), flagAddr);
}
-#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
void MacroAssembler::wasmCheckUnsafeCallWithABIPost() {
// Check JSContext::inUnsafeCallWithABI was cleared as expected.
Label ok;
@@ -4986,6 +4986,7 @@ void MacroAssembler::callWithABINoProfiler(void* fun, ABIType result,
uint32_t stackAdjust;
callWithABIPre(&stackAdjust);
+#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
if (check == CheckUnsafeCallWithABI::Check) {
// Set the JSContext::inUnsafeCallWithABI flag.
push(ReturnReg);
@@ -4996,6 +4997,7 @@ void MacroAssembler::callWithABINoProfiler(void* fun, ABIType result,
// On arm64, SP may be < PSP now (that's OK).
// eg testcase: tests/bug1375074.js
}
+#endif
call(ImmPtr(fun));
@@ -5027,9 +5029,13 @@ CodeOffset MacroAssembler::callWithABI(wasm::BytecodeOffset bytecode,
// The instance register is used in builtin thunks and must be set.
bool needsBuiltinThunk = wasm::NeedsBuiltinThunk(imm);
+#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
// The builtin thunk exits the JIT activation, if we don't have one we must
// use AutoUnsafeCallWithABI inside the builtin and check that here.
bool checkUnsafeCallWithABI = !needsBuiltinThunk;
+#else
+ bool checkUnsafeCallWithABI = false;
+#endif
if (needsBuiltinThunk || checkUnsafeCallWithABI) {
if (instanceOffset) {
loadPtr(Address(getStackPointer(), *instanceOffset + stackAdjust),
@@ -5039,9 +5045,11 @@ CodeOffset MacroAssembler::callWithABI(wasm::BytecodeOffset bytecode,
}
}
+#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
if (checkUnsafeCallWithABI) {
wasmCheckUnsafeCallWithABIPre();
}
+#endif
CodeOffset raOffset = call(
wasm::CallSiteDesc(bytecode.offset(), wasm::CallSiteKind::Symbolic), imm);
@@ -6390,12 +6398,14 @@ CodeOffset MacroAssembler::wasmCallBuiltinInstanceMethod(
MOZ_CRASH("Unknown abi passing style for pointer");
}
+#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
// The builtin thunk exits the JIT activation, if we don't have one we must
// use AutoUnsafeCallWithABI inside the builtin and check that here.
bool checkUnsafeCallWithABI = !wasm::NeedsBuiltinThunk(builtin);
if (checkUnsafeCallWithABI) {
wasmCheckUnsafeCallWithABIPre();
}
+#endif
CodeOffset ret = call(desc, builtin);
diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h
@@ -838,9 +838,9 @@ class MacroAssembler : public MacroAssemblerSpecific {
void callWithABIPost(uint32_t stackAdjust, ABIType result,
bool callFromWasm = false) PER_ARCH;
+#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
// Set the JSContext::inUnsafeCallWithABI flag using InstanceReg.
void wasmCheckUnsafeCallWithABIPre();
-#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
// Check JSContext::inUnsafeCallWithABI was cleared as expected.
void wasmCheckUnsafeCallWithABIPost();
#endif
diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build
@@ -108,7 +108,6 @@ UNIFIED_SOURCES += [
"testParserAtom.cpp",
"testPersistentRooted.cpp",
"testPreserveJitCode.cpp",
- "testPrinter.cpp",
"testPrintf.cpp",
"testPrivateGCThingValue.cpp",
"testProfileStrings.cpp",
diff --git a/js/src/jsapi-tests/testPrinter.cpp b/js/src/jsapi-tests/testPrinter.cpp
@@ -1,111 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "js/Printer.h" // FixedBufferPrinter
-
-#include "jsapi-tests/tests.h"
-
-using namespace js;
-
-struct TestBuffer {
- const char ASCII_ACK = (char)6;
-
- char* buffer;
- size_t size;
-
- // len is the buffer size, including terminating null
- explicit TestBuffer(const size_t len) : buffer(new char[len + 3]), size(len) {
- buffer[size] = ASCII_ACK; // to detect overflow
- buffer[size + 1] = ASCII_ACK;
- buffer[size + 2] = ASCII_ACK;
- }
-
- ~TestBuffer() { delete[] buffer; }
-
- // test has written past the end of the buffer
- bool hasOverflowed() {
- return buffer[size] != ASCII_ACK || buffer[size + 1] != ASCII_ACK ||
- buffer[size + 2] != ASCII_ACK;
- }
-
- bool matches(const char* expected) { return strcmp(buffer, expected) == 0; }
-};
-
-BEGIN_TEST(testFixedBufferPrinter) {
- // empty buffer
- {
- TestBuffer actual(0);
- FixedBufferPrinter fbp(actual.buffer, 0);
- fbp.put("will not fit");
- CHECK(!actual.hasOverflowed());
- }
- // buffer is initially null-terminated
- {
- TestBuffer actual(10);
- // make sure the buffer is not null-terminated
- memset(actual.buffer, '!', actual.size);
- FixedBufferPrinter fbp(actual.buffer, 10);
- CHECK(!actual.hasOverflowed());
- CHECK(actual.matches(""));
- }
- // one put that fits
- {
- TestBuffer actual(50);
- FixedBufferPrinter fbp(actual.buffer, actual.size);
- const char* expected = "expected string fits";
- fbp.put(expected);
- CHECK(!actual.hasOverflowed());
- CHECK(actual.matches(expected));
- }
- // unterminated string in put
- {
- TestBuffer actual(50);
- FixedBufferPrinter fbp(actual.buffer, actual.size);
- const char* expected = "okBAD";
- fbp.put(expected, 2);
- CHECK(!actual.hasOverflowed());
- CHECK(actual.matches("ok"));
- }
- // one put that more than fills the buffer
- {
- TestBuffer actual(16);
- FixedBufferPrinter fbp(actual.buffer, actual.size);
- const char* expected = "expected string overflow";
- fbp.put(expected);
- CHECK(!actual.hasOverflowed());
- CHECK(actual.matches("expected string"));
- }
- // maintains position over multiple puts that fit
- {
- TestBuffer actual(16);
- FixedBufferPrinter fbp(actual.buffer, actual.size);
- fbp.put("expected ");
- fbp.put("string");
- CHECK(actual.matches("expected string"));
- }
- // multiple puts, last one more than fills the buffer
- {
- TestBuffer actual(9);
- FixedBufferPrinter fbp(actual.buffer, actual.size);
- fbp.put("expected");
- fbp.put("overflow");
- CHECK(!actual.hasOverflowed());
- CHECK(actual.matches("expected"));
- }
- // put after buffer is full doesn't overflow
- {
- TestBuffer actual(2);
- FixedBufferPrinter fbp(actual.buffer, actual.size);
- fbp.put("exp");
- fbp.put("overflow");
- CHECK(!actual.hasOverflowed());
- CHECK(actual.matches("e"));
- }
-
- return true;
-}
-END_TEST(testFixedBufferPrinter)
diff --git a/js/src/vm/JSContext.cpp b/js/src/vm/JSContext.cpp
@@ -57,9 +57,7 @@
#include "util/NativeStack.h"
#include "util/Text.h"
#include "util/WindowsWrapper.h"
-#include "js/friend/DumpFunctions.h" // for stack trace utilities
-#include "js/Printer.h" // for FixedBufferPrinter
-#include "vm/BytecodeUtil.h" // JSDVG_IGNORE_STACK
+#include "vm/BytecodeUtil.h" // JSDVG_IGNORE_STACK
#include "vm/ErrorObject.h"
#include "vm/ErrorReporting.h"
#include "vm/FrameIter.h"
@@ -281,13 +279,6 @@ void JSContext::onOutOfMemory() {
runtime()->hadOutOfMemory = true;
gc::AutoSuppressGC suppressGC(this);
- // Capture stack trace before doing anything else that might use memory.
- // If we're in an unsafe ABI context, we don't need to capture a stack trace
- // because the function will explicitly recover from OOM.
- if (!inUnsafeCallWithABI) {
- captureOOMStackTrace();
- }
-
/* Report the oom. */
if (JS::OutOfMemoryCallback oomCallback = runtime()->oomCallback) {
oomCallback(this, runtime()->oomCallbackData);
@@ -1212,8 +1203,10 @@ JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
activation_(this, nullptr),
profilingActivation_(nullptr),
noExecuteDebuggerTop(this, nullptr),
+#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
inUnsafeCallWithABI(this, false),
hasAutoUnsafeCallWithABI(this, false),
+#endif
#ifdef DEBUG
liveArraySortDataInstances(this, 0),
#endif
@@ -1275,18 +1268,10 @@ JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
canSkipEnqueuingJobs(this, false),
promiseRejectionTrackerCallback(this, nullptr),
promiseRejectionTrackerCallbackData(this, nullptr),
- oomStackTraceBuffer_(this, nullptr),
- oomStackTraceBufferValid_(this, false),
insideExclusiveDebuggerOnEval(this, nullptr),
microTaskQueues(this) {
MOZ_ASSERT(static_cast<JS::RootingContext*>(this) ==
JS::RootingContext::get(this));
-
- if (JS::Prefs::experimental_capture_oom_stack_trace()) {
- // Allocate pre-allocated buffer for OOM stack traces
- oomStackTraceBuffer_ =
- static_cast<char*>(js_calloc(OOMStackTraceBufferSize));
- }
}
#ifdef ENABLE_WASM_JSPI
@@ -1326,41 +1311,9 @@ JSContext::~JSContext() {
irregexp::DestroyIsolate(isolate.ref());
}
- // Free the pre-allocated OOM stack trace buffer
- if (oomStackTraceBuffer_) {
- js_free(oomStackTraceBuffer_);
- }
-
TlsContext.set(nullptr);
}
-void JSContext::unsetOOMStackTrace() { oomStackTraceBufferValid_ = false; }
-
-const char* JSContext::getOOMStackTrace() const {
- if (!oomStackTraceBufferValid_ || !oomStackTraceBuffer_) {
- return nullptr;
- }
- return oomStackTraceBuffer_;
-}
-
-bool JSContext::hasOOMStackTrace() const { return oomStackTraceBufferValid_; }
-
-void JSContext::captureOOMStackTrace() {
- // Clear any existing stack trace
- oomStackTraceBufferValid_ = false;
-
- if (!oomStackTraceBuffer_) {
- return; // Buffer not available
- }
-
- // Write directly to pre-allocated buffer to avoid any memory allocation
- FixedBufferPrinter fbp(oomStackTraceBuffer_, OOMStackTraceBufferSize);
- js::DumpBacktrace(this, fbp);
- MOZ_ASSERT(strlen(oomStackTraceBuffer_) < OOMStackTraceBufferSize);
-
- oomStackTraceBufferValid_ = true;
-}
-
void JSContext::setRuntime(JSRuntime* rt) {
MOZ_ASSERT(!resolvingList);
MOZ_ASSERT(!compartment());
@@ -1730,6 +1683,8 @@ void JSContext::suspendExecutionTracing() {
#endif
+#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
+
AutoUnsafeCallWithABI::AutoUnsafeCallWithABI(UnsafeABIStrictness strictness)
: cx_(TlsContext.get()),
nested_(cx_ ? cx_->hasAutoUnsafeCallWithABI : false),
@@ -1738,7 +1693,6 @@ AutoUnsafeCallWithABI::AutoUnsafeCallWithABI(UnsafeABIStrictness strictness)
// This is a helper thread doing Ion or Wasm compilation - nothing to do.
return;
}
-#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
switch (strictness) {
case UnsafeABIStrictness::NoExceptions:
MOZ_ASSERT(!JS_IsExceptionPending(cx_));
@@ -1747,8 +1701,10 @@ AutoUnsafeCallWithABI::AutoUnsafeCallWithABI(UnsafeABIStrictness strictness)
case UnsafeABIStrictness::AllowPendingExceptions:
checkForPendingException_ = !JS_IsExceptionPending(cx_);
break;
+ case UnsafeABIStrictness::AllowThrownExceptions:
+ checkForPendingException_ = false;
+ break;
}
-#endif
cx_->hasAutoUnsafeCallWithABI = true;
}
@@ -1757,16 +1713,16 @@ AutoUnsafeCallWithABI::~AutoUnsafeCallWithABI() {
if (!cx_) {
return;
}
-#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
MOZ_ASSERT(cx_->hasAutoUnsafeCallWithABI);
- MOZ_ASSERT_IF(checkForPendingException_, !JS_IsExceptionPending(cx_));
-#endif
if (!nested_) {
cx_->hasAutoUnsafeCallWithABI = false;
cx_->inUnsafeCallWithABI = false;
}
+ MOZ_ASSERT_IF(checkForPendingException_, !JS_IsExceptionPending(cx_));
}
+#endif // JS_CHECK_UNSAFE_CALL_WITH_ABI
+
#ifdef __wasi__
JS_PUBLIC_API void js::IncWasiRecursionDepth(JSContext* cx) {
++JS::RootingContext::get(cx)->wasiRecursionDepth;
diff --git a/js/src/vm/JSContext.h b/js/src/vm/JSContext.h
@@ -442,9 +442,11 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext,
return offsetof(JSContext, jitActivation);
}
+#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
static size_t offsetOfInUnsafeCallWithABI() {
return offsetof(JSContext, inUnsafeCallWithABI);
}
+#endif
public:
js::InterpreterStack& interpreterStack() {
@@ -483,8 +485,10 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext,
*/
js::ContextData<js::EnterDebuggeeNoExecute*> noExecuteDebuggerTop;
+#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
js::ContextData<uint32_t> inUnsafeCallWithABI;
js::ContextData<bool> hasAutoUnsafeCallWithABI;
+#endif
#ifdef DEBUG
js::ContextData<uint32_t> liveArraySortDataInstances;
@@ -684,12 +688,6 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext,
#endif
}
- // OOM stack trace buffer management
- void unsetOOMStackTrace();
- const char* getOOMStackTrace() const;
- bool hasOOMStackTrace() const;
- void captureOOMStackTrace();
-
js::ContextData<int32_t> reportGranularity; /* see vm/Probes.h */
js::ContextData<js::AutoResolving*> resolvingList;
@@ -962,14 +960,6 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext,
promiseRejectionTrackerCallback;
js::ContextData<void*> promiseRejectionTrackerCallbackData;
- // Pre-allocated buffer for storing out-of-memory stack traces.
- // This buffer is allocated during context initialization to avoid
- // allocation during OOM conditions. The buffer stores a formatted
- // stack trace string that can be retrieved by privileged JavaScript.
- static constexpr size_t OOMStackTraceBufferSize = 4096;
- js::ContextData<char*> oomStackTraceBuffer_;
- js::ContextData<bool> oomStackTraceBufferValid_;
-
JSObject* getIncumbentGlobal(JSContext* cx);
bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job,
js::HandleObject promise,
@@ -1194,7 +1184,11 @@ class MOZ_RAII AutoNoteExclusiveDebuggerOnEval {
}
};
-enum UnsafeABIStrictness { NoExceptions, AllowPendingExceptions };
+enum UnsafeABIStrictness {
+ NoExceptions,
+ AllowPendingExceptions,
+ AllowThrownExceptions
+};
// Should be used in functions called directly from JIT code (with
// masm.callWithABI). This assert invariants in debug builds. Resets
@@ -1212,17 +1206,22 @@ enum UnsafeABIStrictness { NoExceptions, AllowPendingExceptions };
// the function is not called with a pending exception, and that it does not
// throw an exception itself.
class MOZ_RAII AutoUnsafeCallWithABI {
+#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
JSContext* cx_;
bool nested_;
-#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
bool checkForPendingException_;
#endif
JS::AutoCheckCannotGC nogc;
public:
+#ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI
explicit AutoUnsafeCallWithABI(
UnsafeABIStrictness strictness = UnsafeABIStrictness::NoExceptions);
~AutoUnsafeCallWithABI();
+#else
+ explicit AutoUnsafeCallWithABI(
+ UnsafeABIStrictness unused_ = UnsafeABIStrictness::NoExceptions) {}
+#endif
};
template <typename T>
diff --git a/js/src/vm/Printer.cpp b/js/src/vm/Printer.cpp
@@ -497,14 +497,6 @@ void LSprinter::clear() {
hadOOM_ = false;
}
-void FixedBufferPrinter::put(const char* s, size_t len) {
- snprintf(buffer_, size_, "%.*s", int(len), s);
- size_t written = std::min(len, size_);
- MOZ_ASSERT(size_ - written >= 0);
- size_ -= written;
- buffer_ += written;
-}
-
void LSprinter::put(const char* s, size_t len) {
if (hadOutOfMemory()) {
return;
diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml
@@ -8997,13 +8997,6 @@
mirror: always
set_spidermonkey_pref: startup
- # Capture stack traces for OOM
-- name: javascript.options.experimental.capture_oom_stack_trace
- type: bool
- value: true
- mirror: always
- set_spidermonkey_pref: startup
-
#endif // NIGHTLY_BUILD
# Whether to Baseline-compile self-hosted functions the first time they are