From d57e75a979dfe1bf753c2116dbe99da78ca5376e Mon Sep 17 00:00:00 2001 From: Sandor Molnar Date: Mon, 13 Sep 2021 23:42:28 +0300 Subject: [PATCH] Backed out 11 changesets (bug 1730426) for causing assertion failures in src/vm/JSContext. Backed out changeset ef37ce0219ea (bug 1730426) Backed out changeset f1c824d4d39c (bug 1730426) Backed out changeset d2dadbfb2cca (bug 1730426) Backed out changeset 76ff766c5cdf (bug 1730426) Backed out changeset bf394cc4b7f3 (bug 1730426) Backed out changeset 4d27b63a0250 (bug 1730426) Backed out changeset b28009dee3ff (bug 1730426) Backed out changeset a22343e12ce4 (bug 1730426) Backed out changeset 8363cf2dbda3 (bug 1730426) Backed out changeset d89e8415905e (bug 1730426) Backed out changeset 9e42f1860492 (bug 1730426) --- js/public/Exception.h | 45 +------------ js/src/builtin/Boolean-inl.h | 2 +- js/src/builtin/TestingFunctions.cpp | 5 +- js/src/debugger/Debugger.cpp | 24 +++---- js/src/debugger/Debugger.h | 2 +- js/src/debugger/DebuggerMemory.cpp | 2 - js/src/frontend/ParserAtom.cpp | 1 + js/src/irregexp/RegExpAPI.cpp | 4 +- js/src/jit-test/tests/ion/bailout-oom-01.js | 36 ----------- js/src/jit/Bailouts.cpp | 5 -- js/src/jit/BaselineBailouts.cpp | 4 +- js/src/jit/BaselineCodeGen.cpp | 1 + js/src/jit/Ion.cpp | 6 +- js/src/jit/JitFrames.cpp | 8 +-- js/src/jsapi-tests/moz.build | 1 - js/src/jsapi-tests/testSlowScript.cpp | 70 +++++++++++++-------- js/src/jsapi-tests/testTypedArrays.cpp | 2 - js/src/jsapi.cpp | 40 +++++++----- js/src/jslibmath.h | 4 +- js/src/jsmath.cpp | 28 ++++----- js/src/jsnum.cpp | 3 + js/src/shell/js.cpp | 3 - js/src/vm/BytecodeUtil.cpp | 4 +- js/src/vm/Interpreter.cpp | 2 +- js/src/vm/JSContext.cpp | 46 +++++++------- js/src/vm/JSContext.h | 59 +++++++---------- js/src/vm/JSScript.cpp | 1 + js/src/vm/RegExpObject.cpp | 1 + js/src/vm/Runtime.cpp | 2 - js/src/vm/SavedStacks.cpp | 1 + js/src/vm/Shape.cpp | 2 + js/src/wasm/WasmCompile.cpp | 1 + js/src/wasm/WasmJS.cpp | 5 ++ js/src/wasm/WasmModule.cpp | 2 + js/src/wasm/WasmTable.cpp | 1 - js/xpconnect/src/XPCShellImpl.cpp | 1 - 36 files changed, 174 insertions(+), 250 deletions(-) delete mode 100644 js/src/jit-test/tests/ion/bailout-oom-01.js diff --git a/js/public/Exception.h b/js/public/Exception.h index 7e401e6a3255..baeba1d3ebc0 100644 --- a/js/public/Exception.h +++ b/js/public/Exception.h @@ -39,12 +39,6 @@ extern JS_PUBLIC_API void JS_SetPendingException( JSContext* cx, JS::HandleValue v, JS::ExceptionStackBehavior behavior = JS::ExceptionStackBehavior::Capture); -// Indicate that we are intentionally raising an interrupt/uncatchable -// exception. Returning false/nullptr without calling this will still be treated -// as an interrupt, but in the future the implicit behaviour may no longer be -// allowed. -extern JS_PUBLIC_API void JS_SetPendingInterrupt(JSContext* cx); - extern JS_PUBLIC_API void JS_ClearPendingException(JSContext* cx); /** @@ -59,41 +53,6 @@ extern JS_PUBLIC_API JSErrorReport* JS_ErrorFromException(JSContext* cx, namespace JS { -// When propagating an exception up the call stack, we store the underlying -// reason on the JSContext as one of the following enum values. -// -// NOTE: It is not yet a hard requirement for uncatchable exceptions to set -// status to Interrupt so rely on the last return value. If Interrupt is -// not set then the status will remain as None. -enum class ExceptionStatus { - // No expection status. - None, - - // Used by debugger when forcing an early return from a frame. This uses - // exception machinery, but at the right time is turned back into a normal - // non-error completion. - ForcedReturn, - - // An uncatchable exception that functions as an interrupt. This is used for - // watchdog mechanisms (like the slow-script notification) or the debugger - // API. It cannot be caught be JS catch blocks, but the debugger or event - // loops may still capture it. - Interrupt, - - // Throwing a (catchable) exception. Certain well-known exceptions are - // explicitly tracked for convenience. - Throwing, - OutOfMemory, - OverRecursed, -}; - -// Returns true if the status is a catchable exception. Formerly this was -// indicated by the `JSContext::throwing` flag. -static MOZ_ALWAYS_INLINE bool IsCatchableExceptionStatus( - ExceptionStatus status) { - return status >= ExceptionStatus::Throwing; -} - // This class encapsulates a (pending) exception and the corresponding optional // SavedFrame stack object captured when the pending exception was set // on the JSContext. This fuzzily correlates with a `throw` statement in JS, @@ -141,7 +100,9 @@ class MOZ_STACK_CLASS ExceptionStack { class JS_PUBLIC_API AutoSaveExceptionState { private: JSContext* context; - ExceptionStatus status; + bool wasPropagatingForcedReturn; + bool wasOverRecursed; + bool wasThrowing; RootedValue exceptionValue; RootedObject exceptionStack; diff --git a/js/src/builtin/Boolean-inl.h b/js/src/builtin/Boolean-inl.h index cc4093500f32..6f333d145394 100644 --- a/js/src/builtin/Boolean-inl.h +++ b/js/src/builtin/Boolean-inl.h @@ -18,7 +18,7 @@ namespace js { inline bool EmulatesUndefined(JSObject* obj) { // This may be called off the main thread. It's OK not to expose the object // here as it doesn't escape. - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); JSObject* actual = MOZ_LIKELY(!obj->is()) ? obj : UncheckedUnwrapWithoutExpose(obj); diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 03ae3eb4f01c..08b9f1d0b1b5 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -2464,6 +2464,9 @@ static bool GCSlice(JSContext* cx, unsigned argc, Value* vp) { if (args.length() >= 1) { uint32_t work = 0; if (!ToUint32(cx, args[0], &work)) { + RootedObject callee(cx, &args.callee()); + ReportUsageErrorASCII(cx, callee, + "The work budget parameter |n| must be an integer"); return false; } budget = SliceBudget(WorkBudget(work)); @@ -3680,7 +3683,7 @@ static bool Terminate(JSContext* cx, unsigned arg, Value* vp) { fprintf(stderr, "terminate called\n"); } - cx->setInterrupting(); + JS_ClearPendingException(cx); return false; } diff --git a/js/src/debugger/Debugger.cpp b/js/src/debugger/Debugger.cpp index f3e949f04dc1..52e846842ecb 100644 --- a/js/src/debugger/Debugger.cpp +++ b/js/src/debugger/Debugger.cpp @@ -300,7 +300,7 @@ static void PropagateForcedReturn(JSContext* cx, AbstractFramePtr frame, return false; case ResumeMode::Terminate: - cx->setInterrupting(); + cx->clearPendingException(); return false; case ResumeMode::Return: @@ -1018,7 +1018,7 @@ NativeResumeMode DebugAPI::slowPathOnNativeCall(JSContext* cx, return NativeResumeMode::Abort; case ResumeMode::Terminate: - cx->setInterrupting(); + cx->clearPendingException(); return NativeResumeMode::Abort; case ResumeMode::Return: @@ -1114,22 +1114,15 @@ bool DebugAPI::slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame, // The onPop handler and associated clean up logic should not run multiple // times on the same frame. If slowPathOnLeaveFrame has already been // called, the frame will not be present in the Debugger frame maps. - Rooted frames(cx); + Rooted frames( + cx, Debugger::DebuggerFrameVector(cx)); if (!Debugger::getDebuggerFrames(frame, &frames)) { - // There is at least one match Debugger.Frame we failed to process, so drop - // the pending exception and raise an out-of-memory instead. - if (!frameOk) { - cx->clearPendingException(); - } - ReportOutOfMemory(cx); return false; } if (frames.empty()) { return frameOk; } - // Convert current exception state into a Completion and clear exception off - // of the JSContext. completion = Completion::fromJSFramePop(cx, frame, pc, frameOk); ResumeMode resumeMode = ResumeMode::Continue; @@ -1951,7 +1944,6 @@ Completion Completion::fromJSResult(JSContext* cx, bool ok, const Value& rv) { } if (!cx->isExceptionPending()) { - cx->clearInterrupt(); return Completion(Terminate()); } @@ -2603,9 +2595,9 @@ bool DebugAPI::onSingleStep(JSContext* cx) { // Build list of Debugger.Frame instances referring to this frame with // onStep handlers. - Rooted frames(cx); + Rooted frames( + cx, Debugger::DebuggerFrameVector(cx)); if (!Debugger::getDebuggerFrames(iter.abstractFramePtr(), &frames)) { - ReportOutOfMemory(cx); return false; } @@ -3110,6 +3102,7 @@ bool Debugger::updateExecutionObservabilityOfFrames( { jit::JitContext jctx(cx, nullptr); if (!jit::RecompileOnStackBaselineScriptsForDebugMode(cx, obs, observing)) { + ReportOutOfMemory(cx); return false; } } @@ -6437,13 +6430,12 @@ bool Debugger::replaceFrameGuts(JSContext* cx, AbstractFramePtr from, }); // Forward live Debugger.Frame objects. - Rooted frames(cx); + Rooted frames(cx, DebuggerFrameVector(cx)); if (!getDebuggerFrames(from, &frames)) { // An OOM here means that all Debuggers' frame maps still contain // entries for 'from' and no entries for 'to'. Since the 'from' frame // will be gone, they are removed by terminateDebuggerFramesOnExit // above. - ReportOutOfMemory(cx); return false; } diff --git a/js/src/debugger/Debugger.h b/js/src/debugger/Debugger.h index 2a3a0a2a32eb..c017e2ab6a4d 100644 --- a/js/src/debugger/Debugger.h +++ b/js/src/debugger/Debugger.h @@ -944,7 +944,7 @@ class Debugger : private mozilla::LinkedListElement { * |frame|. |global| is |frame|'s global object; if nullptr or omitted, we * compute it ourselves from |frame|. */ - using DebuggerFrameVector = GCVector; + using DebuggerFrameVector = GCVector; [[nodiscard]] static bool getDebuggerFrames( AbstractFramePtr frame, MutableHandle frames); diff --git a/js/src/debugger/DebuggerMemory.cpp b/js/src/debugger/DebuggerMemory.cpp index f2c9d0e1168a..f179d2d2f1ba 100644 --- a/js/src/debugger/DebuggerMemory.cpp +++ b/js/src/debugger/DebuggerMemory.cpp @@ -394,7 +394,6 @@ bool DebuggerMemory::CallData::takeCensus() { JS::ubi::RootedCount rootCount(cx, rootType->makeCount()); if (!rootCount) { - ReportOutOfMemory(cx); return false; } JS::ubi::CensusHandler handler(census, rootCount, @@ -407,7 +406,6 @@ bool DebuggerMemory::CallData::takeCensus() { for (WeakGlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty(); r.popFront()) { if (!census.targetZones.put(r.front()->zone())) { - ReportOutOfMemory(cx); return false; } } diff --git a/js/src/frontend/ParserAtom.cpp b/js/src/frontend/ParserAtom.cpp index 18bd5acc1697..5ed237088258 100644 --- a/js/src/frontend/ParserAtom.cpp +++ b/js/src/frontend/ParserAtom.cpp @@ -105,6 +105,7 @@ JSAtom* ParserAtom::instantiate(JSContext* cx, ParserAtomIndex index, atom = AtomizeChars(cx, hash(), twoByteChars(), length()); } if (!atom) { + js::ReportOutOfMemory(cx); return nullptr; } if (!atomCache.setAtomAt(cx, index, atom)) { diff --git a/js/src/irregexp/RegExpAPI.cpp b/js/src/irregexp/RegExpAPI.cpp index f957ffdd4ec7..69263729f7a4 100644 --- a/js/src/irregexp/RegExpAPI.cpp +++ b/js/src/irregexp/RegExpAPI.cpp @@ -490,7 +490,6 @@ enum class AssembleResult { masm = MakeUnique(cx->isolate, zone); } if (!masm) { - ReportOutOfMemory(cx); return AssembleResult::OutOfMemory; } @@ -565,7 +564,6 @@ enum class AssembleResult { static_cast(masm.get())->tables(); for (uint32_t i = 0; i < tables.length(); i++) { if (!re->addTable(std::move(tables[i]))) { - ReportOutOfMemory(cx); return AssembleResult::OutOfMemory; } } @@ -672,7 +670,7 @@ bool CompilePattern(JSContext* cx, MutableHandleRegExpShared re, JS_ReportErrorASCII(cx, "regexp too big"); return false; case AssembleResult::OutOfMemory: - MOZ_ASSERT(cx->isThrowingOutOfMemory()); + ReportOutOfMemory(cx); return false; case AssembleResult::Success: break; diff --git a/js/src/jit-test/tests/ion/bailout-oom-01.js b/js/src/jit-test/tests/ion/bailout-oom-01.js deleted file mode 100644 index b56b323774f4..000000000000 --- a/js/src/jit-test/tests/ion/bailout-oom-01.js +++ /dev/null @@ -1,36 +0,0 @@ -// |jit-test| --no-threads; --fast-warmup; skip-if: !('oomTest' in this) - -setJitCompilerOption("ion.warmup.trigger", 20); -gczeal(0); - -var nonce = 0; - -function doTest() { - // Block Warp/Ion compile. - with ({}) {}; - - nonce += 1; - - // Fresh function and script. - let fn = new Function("arg", ` - /* {nonce} */ - var r1 = []; - var r2 = []; - return (() => arg + 1)(); - `); - - // Warm up JITs. - for (var i = 0; i < 20; ++i) { - assertEq(fn(i), i + 1); - } - - // Trigger bailout. - fn(); -} - -// Warmup doTest already. -doTest(); -doTest(); - -// OOM test the JIT compilation and bailout. -oomTest(doTest); diff --git a/js/src/jit/Bailouts.cpp b/js/src/jit/Bailouts.cpp index 34f5aff9d810..f155e3efd64c 100644 --- a/js/src/jit/Bailouts.cpp +++ b/js/src/jit/Bailouts.cpp @@ -210,8 +210,6 @@ bool jit::ExceptionHandlerBailout(JSContext* cx, MOZ_ASSERT_IF(!excInfo.propagatingIonExceptionForDebugMode(), cx->isExceptionPending()); - JS::AutoSaveExceptionState savedExc(cx); - JitActivation* act = cx->activation()->asJit(); uint8_t* prevExitFP = act->jsExitFP(); auto restoreExitFP = @@ -242,9 +240,6 @@ bool jit::ExceptionHandlerBailout(JSContext* cx, rfe->target = cx->runtime()->jitRuntime()->getBailoutTail().value; rfe->bailoutInfo = bailoutInfo; } else { - // Drop the exception that triggered the bailout and instead propagate the - // failure caused by processing the bailout (eg. OOM). - savedExc.drop(); MOZ_ASSERT(!bailoutInfo); MOZ_ASSERT(cx->isExceptionPending()); } diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index f194baaf1aab..e92d2b7cc3eb 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -1515,9 +1515,6 @@ bool jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation, MOZ_ASSERT(*bailoutInfo == nullptr); MOZ_ASSERT(iter.isBailoutJS()); - // Caller should have saved the exception while we perform the bailout. - MOZ_ASSERT(!cx->isExceptionPending()); - TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx); TraceLogStopEvent(logger, TraceLogger_IonMonkey); TraceLogStartEvent(logger, TraceLogger_Baseline); @@ -1606,6 +1603,7 @@ bool jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation, // recovered ahead of the bailout. SnapshotIterator snapIter(iter, activation->bailoutData()->machineState()); if (!snapIter.initInstructionResults(recoverBailout)) { + ReportOutOfMemory(cx); return false; } diff --git a/js/src/jit/BaselineCodeGen.cpp b/js/src/jit/BaselineCodeGen.cpp index ca3003e7033f..c82223820ff8 100644 --- a/js/src/jit/BaselineCodeGen.cpp +++ b/js/src/jit/BaselineCodeGen.cpp @@ -265,6 +265,7 @@ MethodStatus BaselineCompiler::compile() { traceLoggerToggleOffsets_.length()), JS::DeletePolicy(cx->runtime())); if (!baselineScript) { + ReportOutOfMemory(cx); return Method_Error; } diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 3fd4be83f340..264c5acf4680 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -1618,7 +1618,7 @@ static AbortReason IonCompile(JSContext* cx, HandleScript script, auto alloc = cx->make_unique(TempAllocator::PreferredLifoChunkSize); if (!alloc) { - return AbortReason::Error; + return AbortReason::Alloc; } TempAllocator* temp = alloc->new_(alloc.get()); @@ -1629,11 +1629,11 @@ static AbortReason IonCompile(JSContext* cx, HandleScript script, JitContext jctx(cx, temp); if (!cx->realm()->ensureJitRealmExists(cx)) { - return AbortReason::Error; + return AbortReason::Alloc; } if (!cx->realm()->jitRealm()->ensureIonStubsExist(cx)) { - return AbortReason::Error; + return AbortReason::Alloc; } MIRGraph* graph = alloc->new_(temp); diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index 294ebfbf4bd2..abfc1ca783fb 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -524,7 +524,7 @@ again: } // We may be propagating a forced return from a debugger hook function. - if (cx->isPropagatingForcedReturn()) { + if (MOZ_UNLIKELY(cx->isPropagatingForcedReturn())) { cx->clearPropagatingForcedReturn(); frameOk = true; } @@ -1440,11 +1440,7 @@ RInstructionResults::~RInstructionResults() { bool RInstructionResults::init(JSContext* cx, uint32_t numResults) { if (numResults) { results_ = cx->make_unique(); - if (!results_) { - return false; - } - if (!results_->growBy(numResults)) { - ReportOutOfMemory(cx); + if (!results_ || !results_->growBy(numResults)) { return false; } diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build index ab85620504ca..282fa69859b0 100644 --- a/js/src/jsapi-tests/moz.build +++ b/js/src/jsapi-tests/moz.build @@ -107,7 +107,6 @@ UNIFIED_SOURCES += [ "testSetPropertyIgnoringNamedGetter.cpp", "testSharedImmutableStringsCache.cpp", "testSliceBudget.cpp", - "testSlowScript.cpp", "testSourcePolicy.cpp", "testSparseBitmap.cpp", "testStencil.cpp", diff --git a/js/src/jsapi-tests/testSlowScript.cpp b/js/src/jsapi-tests/testSlowScript.cpp index 154120eed154..fd4898c27772 100644 --- a/js/src/jsapi-tests/testSlowScript.cpp +++ b/js/src/jsapi-tests/testSlowScript.cpp @@ -9,8 +9,7 @@ static bool InterruptCallback(JSContext* cx) { return false; } static unsigned sRemain; -static bool RequestInterruptCallback(JSContext* cx, unsigned argc, - JS::Value* vp) { +static bool RequestInterruptCallback(JSContext* cx, unsigned argc, jsval* vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); if (!sRemain--) { JS_RequestInterruptCallback(cx); @@ -24,48 +23,65 @@ BEGIN_TEST(testSlowScript) { JS_DefineFunction(cx, global, "requestInterruptCallback", RequestInterruptCallback, 0, 0); - CHECK( - test("while (true)" - " for (i in [0,0,0,0])" - " requestInterruptCallback();")); + test( + "while (true)" + " for (i in [0,0,0,0])" + " requestInterruptCallback();"); - CHECK( - test("while (true)" - " for (i in [0,0,0,0])" - " for (j in [0,0,0,0])" - " requestInterruptCallback();")); + test( + "while (true)" + " for (i in [0,0,0,0])" + " for (j in [0,0,0,0])" + " requestInterruptCallback();"); - CHECK( - test("while (true)" - " for (i in [0,0,0,0])" - " for (j in [0,0,0,0])" - " for (k in [0,0,0,0])" - " requestInterruptCallback();")); + test( + "while (true)" + " for (i in [0,0,0,0])" + " for (j in [0,0,0,0])" + " for (k in [0,0,0,0])" + " requestInterruptCallback();"); - CHECK( - test("function* f() { while (true) yield requestInterruptCallback() }" - "for (i of f()) ;")); + test( + "function f() { while (true) yield requestInterruptCallback() }" + "for (i in f()) ;"); - CHECK( - test("function* f() { while (true) yield 1 }" - "for (i of f())" - " requestInterruptCallback();")); + test( + "function f() { while (true) yield 1 }" + "for (i in f())" + " requestInterruptCallback();"); + + test( + "(function() {" + " while (true)" + " let (x = 1) { eval('requestInterruptCallback()'); }" + "})()"); return true; } bool test(const char* bytes) { - JS::RootedValue v(cx); + jsval v; + + JS_SetOptions(cx, JS_GetOptions(cx) & + ~(JSOPTION_METHODJIT | JSOPTION_METHODJIT_ALWAYS)); + sRemain = 0; + CHECK(!evaluate(bytes, __FILE__, __LINE__, &v)); + CHECK(!JS_IsExceptionPending(cx)); + + sRemain = 1000; + CHECK(!evaluate(bytes, __FILE__, __LINE__, &v)); + CHECK(!JS_IsExceptionPending(cx)); + + JS_SetOptions( + cx, JS_GetOptions(cx) | JSOPTION_METHODJIT | JSOPTION_METHODJIT_ALWAYS); sRemain = 0; CHECK(!evaluate(bytes, __FILE__, __LINE__, &v)); CHECK(!JS_IsExceptionPending(cx)); - JS_ClearPendingException(cx); sRemain = 1000; CHECK(!evaluate(bytes, __FILE__, __LINE__, &v)); CHECK(!JS_IsExceptionPending(cx)); - JS_ClearPendingException(cx); return true; } diff --git a/js/src/jsapi-tests/testTypedArrays.cpp b/js/src/jsapi-tests/testTypedArrays.cpp index 08b3af5d6254..1531f4754eb3 100644 --- a/js/src/jsapi-tests/testTypedArrays.cpp +++ b/js/src/jsapi-tests/testTypedArrays.cpp @@ -117,7 +117,6 @@ bool TestPlainTypedArray(JSContext* cx) { { RootedObject notArray(cx, Create(cx, SIZE_MAX)); CHECK(!notArray); - JS_ClearPendingException(cx); } RootedObject array(cx, Create(cx, 7)); @@ -171,7 +170,6 @@ bool TestArrayFromBuffer(JSContext* cx) { { RootedObject notArray(cx, CreateWithBuffer(cx, buffer, UINT32_MAX, -1)); CHECK(!notArray); - JS_ClearPendingException(cx); } RootedObject array(cx, CreateWithBuffer(cx, buffer, 0, -1)); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 38a6c454edf8..ab14accc0a63 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3685,34 +3685,45 @@ JS_PUBLIC_API void JS_SetPendingException(JSContext* cx, HandleValue value, } } -JS_PUBLIC_API void JS_SetPendingInterrupt(JSContext* cx) { - cx->setInterrupting(); -} - JS_PUBLIC_API void JS_ClearPendingException(JSContext* cx) { AssertHeapIsIdle(); cx->clearPendingException(); } JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext* cx) - : context(cx), status(cx->status), exceptionValue(cx), exceptionStack(cx) { + : context(cx), + wasPropagatingForcedReturn(cx->propagatingForcedReturn_), + wasOverRecursed(cx->overRecursed_), + wasThrowing(cx->throwing), + exceptionValue(cx), + exceptionStack(cx) { AssertHeapIsIdle(); CHECK_THREAD(cx); - if (IsCatchableExceptionStatus(status)) { + if (wasPropagatingForcedReturn) { + cx->clearPropagatingForcedReturn(); + } + if (wasOverRecursed) { + cx->overRecursed_ = false; + } + if (wasThrowing) { exceptionValue = cx->unwrappedException(); exceptionStack = cx->unwrappedExceptionStack(); + cx->clearPendingException(); } - cx->clearPendingException(); } void JS::AutoSaveExceptionState::drop() { - status = JS::ExceptionStatus::None; + wasPropagatingForcedReturn = false; + wasOverRecursed = false; + wasThrowing = false; exceptionValue.setUndefined(); exceptionStack = nullptr; } void JS::AutoSaveExceptionState::restore() { - context->status = status; + context->propagatingForcedReturn_ = wasPropagatingForcedReturn; + context->overRecursed_ = wasOverRecursed; + context->throwing = wasThrowing; context->unwrappedException() = exceptionValue; if (exceptionStack) { context->unwrappedExceptionStack() = &exceptionStack->as(); @@ -3721,14 +3732,13 @@ void JS::AutoSaveExceptionState::restore() { } JS::AutoSaveExceptionState::~AutoSaveExceptionState() { - // NOTE: An interrupt/uncatchable exception or a debugger-forced-return may be - // clobbered here by the saved exception. If that is not desired, this - // state should be dropped before the destructor fires. if (!context->isExceptionPending()) { - if (status != JS::ExceptionStatus::None) { - context->status = status; + if (wasPropagatingForcedReturn) { + context->setPropagatingForcedReturn(); } - if (IsCatchableExceptionStatus(status)) { + if (wasThrowing) { + context->overRecursed_ = wasOverRecursed; + context->throwing = true; context->unwrappedException() = exceptionValue; if (exceptionStack) { context->unwrappedExceptionStack() = &exceptionStack->as(); diff --git a/js/src/jslibmath.h b/js/src/jslibmath.h index f7790540df60..77be814b1409 100644 --- a/js/src/jslibmath.h +++ b/js/src/jslibmath.h @@ -17,7 +17,7 @@ namespace js { inline double NumberDiv(double a, double b) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); if (b == 0) { if (a == 0 || mozilla::IsNaN(a)) { return JS::GenericNaN(); @@ -32,7 +32,7 @@ inline double NumberDiv(double a, double b) { } inline double NumberMod(double a, double b) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); if (b == 0) { return JS::GenericNaN(); } diff --git a/js/src/jsmath.cpp b/js/src/jsmath.cpp index 3467fa0251d2..e167a5c291a0 100644 --- a/js/src/jsmath.cpp +++ b/js/src/jsmath.cpp @@ -137,7 +137,7 @@ bool js::math_atan(JSContext* cx, unsigned argc, Value* vp) { } double js::ecmaAtan2(double y, double x) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); return fdlibm::atan2(y, x); } @@ -165,7 +165,7 @@ bool js::math_atan2(JSContext* cx, unsigned argc, Value* vp) { } double js::math_ceil_impl(double x) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); return fdlibm::ceil(x); } @@ -243,7 +243,7 @@ bool js::math_exp(JSContext* cx, unsigned argc, Value* vp) { } double js::math_floor_impl(double x) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); return fdlibm::floor(x); } @@ -320,7 +320,7 @@ bool js::math_fround(JSContext* cx, unsigned argc, Value* vp) { } double js::math_log_impl(double x) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); return fdlibm::log(x); } @@ -334,7 +334,7 @@ bool js::math_log(JSContext* cx, unsigned argc, Value* vp) { } double js::math_max_impl(double x, double y) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); // Math.max(num, NaN) => NaN, Math.max(-0, +0) => +0 if (x > y || IsNaN(x) || (x == y && IsNegative(y))) { @@ -359,7 +359,7 @@ bool js::math_max(JSContext* cx, unsigned argc, Value* vp) { } double js::math_min_impl(double x, double y) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); // Math.min(num, NaN) => NaN, Math.min(-0, +0) => -0 if (x < y || IsNaN(x) || (x == y && IsNegativeZero(x))) { @@ -404,7 +404,7 @@ bool js::minmax_impl(JSContext* cx, bool max, HandleValue a, HandleValue b, } double js::powi(double x, int32_t y) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); uint32_t n = Abs(y); double m = x; double p = 1; @@ -431,7 +431,7 @@ double js::powi(double x, int32_t y) { } double js::ecmaPow(double x, double y) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); /* * Use powi if the exponent is an integer-valued double. We don't have to @@ -553,7 +553,7 @@ template double js::GetBiggestNumberLessThan<>(double x); template float js::GetBiggestNumberLessThan<>(float x); double js::math_round_impl(double x) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); int32_t ignored; if (NumberEqualsInt32(x, &ignored)) { @@ -608,7 +608,7 @@ double js::math_sin_fdlibm_impl(double x) { double js::math_sin_native_impl(double x) { MOZ_ASSERT(!sUseFdlibmForSinCosTan); - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); return sin(x); } @@ -628,7 +628,7 @@ bool js::math_sin(JSContext* cx, unsigned argc, Value* vp) { } double js::math_sqrt_impl(double x) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); return sqrt(x); } @@ -751,7 +751,7 @@ bool js::math_atanh(JSContext* cx, unsigned argc, Value* vp) { } double js::ecmaHypot(double x, double y) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); return fdlibm::hypot(x, y); } @@ -847,7 +847,7 @@ bool js::math_hypot_handle(JSContext* cx, HandleValueArray args, } double js::math_trunc_impl(double x) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); return fdlibm::trunc(x); } @@ -877,7 +877,7 @@ bool js::math_trunc(JSContext* cx, unsigned argc, Value* vp) { } double js::math_sign_impl(double x) { - AutoUnsafeCallWithABI unsafe; + AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions); if (mozilla::IsNaN(x)) { return GenericNaN(); diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index aaf5b7e6373f..f80da60fcc03 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -944,6 +944,7 @@ static bool num_toString(JSContext* cx, unsigned argc, Value* vp) { } JSString* str = NumberToStringWithBase(cx, d, base); if (!str) { + JS_ReportOutOfMemory(cx); return false; } args.rval().setString(str); @@ -961,6 +962,7 @@ static bool num_toLocaleString(JSContext* cx, unsigned argc, Value* vp) { RootedString str(cx, NumberToStringWithBase(cx, d, 10)); if (!str) { + JS_ReportOutOfMemory(cx); return false; } @@ -1291,6 +1293,7 @@ static bool num_toPrecision(JSContext* cx, unsigned argc, Value* vp) { if (!args.hasDefined(0)) { JSString* str = NumberToStringWithBase(cx, d, 10); if (!str) { + JS_ReportOutOfMemory(cx); return false; } args.rval().setString(str); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index f1ddfd2bab5d..aa65986a4885 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2617,7 +2617,6 @@ static bool Evaluate(JSContext* cx, unsigned argc, Value* vp) { ? JS_ExecuteScript(cx, script, args.rval()) : JS_ExecuteScript(cx, envChain, script, args.rval()))) { if (catchTermination && !JS_IsExceptionPending(cx)) { - cx->clearInterrupt(); JSAutoRealm ar1(cx, callerGlobal); JSString* str = JS_NewStringCopyZ(cx, "terminated"); if (!str) { @@ -3148,8 +3147,6 @@ static bool Quit(JSContext* cx, unsigned argc, Value* vp) { js::StopDrainingJobQueue(cx); sc->exitCode = code; sc->quitting = true; - - cx->setInterrupting(); return false; } diff --git a/js/src/vm/BytecodeUtil.cpp b/js/src/vm/BytecodeUtil.cpp index f8cae32a4117..dd1df20a6c99 100644 --- a/js/src/vm/BytecodeUtil.cpp +++ b/js/src/vm/BytecodeUtil.cpp @@ -2963,7 +2963,6 @@ static bool GenerateLcovInfo(JSContext* cx, JS::Realm* realm, CollectedScripts result(&queue); IterateScripts(cx, realm, &result, &CollectedScripts::consider); if (!result.ok) { - ReportOutOfMemory(cx); return false; } } @@ -2989,7 +2988,6 @@ static bool GenerateLcovInfo(JSContext* cx, JS::Realm* realm, } if (!coverage::CollectScriptCoverage(script, false)) { - ReportOutOfMemory(cx); return false; } @@ -3051,6 +3049,7 @@ JS_PUBLIC_API UniqueChars js::GetCodeCoverageSummaryAll(JSContext* cx, for (RealmsIter realm(cx->runtime()); !realm.done(); realm.next()) { if (!GenerateLcovInfo(cx, realm, out)) { + JS_ReportOutOfMemory(cx); return nullptr; } } @@ -3067,6 +3066,7 @@ JS_PUBLIC_API UniqueChars js::GetCodeCoverageSummary(JSContext* cx, } if (!GenerateLcovInfo(cx, cx->realm(), out)) { + JS_ReportOutOfMemory(cx); return nullptr; } diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index bdc444ffb17f..4e9b2bd5e07e 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1220,7 +1220,7 @@ again: UnwindIteratorsForUncatchableException(cx, regs); // We may be propagating a forced return from a debugger hook function. - if (cx->isPropagatingForcedReturn()) { + if (MOZ_UNLIKELY(cx->isPropagatingForcedReturn())) { cx->clearPropagatingForcedReturn(); ok = true; } diff --git a/js/src/vm/JSContext.cpp b/js/src/vm/JSContext.cpp index 161eeb48465b..b10d34459d64 100644 --- a/js/src/vm/JSContext.cpp +++ b/js/src/vm/JSContext.cpp @@ -306,8 +306,6 @@ JS_PUBLIC_API void js::ReportOutOfMemory(JSContext* cx) { RootedValue oomMessage(cx, StringValue(cx->names().outOfMemory)); cx->setPendingException(oomMessage, nullptr); - MOZ_ASSERT(cx->status == JS::ExceptionStatus::Throwing); - cx->status = JS::ExceptionStatus::OutOfMemory; } mozilla::GenericErrorResult js::ReportOutOfMemoryResult(JSContext* cx) { @@ -315,7 +313,7 @@ mozilla::GenericErrorResult js::ReportOutOfMemoryResult(JSContext* cx) { return cx->alreadyReportedOOM(); } -JS_PUBLIC_API void js::ReportOverRecursed(JSContext* maybecx) { +void js::ReportOverRecursed(JSContext* maybecx, unsigned errorNumber) { /* * We cannot make stack depth deterministic across different * implementations (e.g. JIT vs. interpreter will differ in @@ -329,18 +327,11 @@ JS_PUBLIC_API void js::ReportOverRecursed(JSContext* maybecx) { } if (maybecx) { - if (maybecx->isHelperThreadContext()) { - maybecx->addPendingOverRecursed(); + if (!maybecx->isHelperThreadContext()) { + JS_ReportErrorNumberASCII(maybecx, GetErrorMessage, nullptr, errorNumber); + maybecx->overRecursed_ = true; } else { - // If ReportError fails (due to OOM) the resulting error is OOM rather - // than OverRecursed. - JS_ReportErrorNumberASCII(maybecx, GetErrorMessage, nullptr, - JSMSG_OVER_RECURSED); - if (!maybecx->isThrowingOutOfMemory()) { - MOZ_ASSERT(maybecx->unwrappedException().isObject()); - MOZ_ASSERT(maybecx->status == JS::ExceptionStatus::Throwing); - maybecx->status = JS::ExceptionStatus::OverRecursed; - } + maybecx->addPendingOverRecursed(); } #ifdef DEBUG maybecx->hadOverRecursed_ = true; @@ -348,6 +339,10 @@ JS_PUBLIC_API void js::ReportOverRecursed(JSContext* maybecx) { } } +JS_PUBLIC_API void js::ReportOverRecursed(JSContext* maybecx) { + ReportOverRecursed(maybecx, JSMSG_OVER_RECURSED); +} + void js::ReportAllocationOverflow(JSContext* cx) { if (!cx) { return; @@ -837,7 +832,6 @@ void InternalJobQueue::runJobs(JSContext* cx) { if (!JS::Call(cx, UndefinedHandleValue, job, args, &rval)) { // Nothing we can do about uncatchable exceptions. if (!cx->isExceptionPending()) { - cx->clearInterrupt(); continue; } RootedValue exn(cx); @@ -984,12 +978,14 @@ JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options) tempLifoAlloc_(this, (size_t)TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), debuggerMutations(this, 0), ionPcScriptCache(this, nullptr), - status(this, JS::ExceptionStatus::None), + throwing(this, false), unwrappedException_(this), unwrappedExceptionStack_(this), + overRecursed_(this, false), #ifdef DEBUG hadOverRecursed_(this, false), #endif + propagatingForcedReturn_(this, false), reportGranularity(this, JS_DEFAULT_JITREPORT_GRANULARITY), resolvingList(this, nullptr), #ifdef DEBUG @@ -1125,7 +1121,8 @@ void JSContext::setPendingException(HandleValue v, HandleSavedFrame stack) { #endif // defined(NIGHTLY_BUILD) // overRecursed_ is set after the fact by ReportOverRecursed. - this->status = JS::ExceptionStatus::Throwing; + this->overRecursed_ = false; + this->throwing = true; this->unwrappedException() = v; this->unwrappedExceptionStack() = stack; } @@ -1144,20 +1141,20 @@ void JSContext::setPendingExceptionAndCaptureStack(HandleValue value) { } bool JSContext::getPendingException(MutableHandleValue rval) { - MOZ_ASSERT(isExceptionPending()); + MOZ_ASSERT(throwing); rval.set(unwrappedException()); if (zone()->isAtomsZone()) { return true; } RootedSavedFrame stack(this, unwrappedExceptionStack()); - JS::ExceptionStatus prevStatus = status; + bool wasOverRecursed = overRecursed_; clearPendingException(); if (!compartment()->wrap(this, rval)) { return false; } this->check(rval); setPendingException(rval, stack); - status = prevStatus; + overRecursed_ = wasOverRecursed; return true; } @@ -1165,13 +1162,16 @@ SavedFrame* JSContext::getPendingExceptionStack() { return unwrappedExceptionStack(); } +bool JSContext::isThrowingOutOfMemory() { + return throwing && IsOutOfMemoryException(this, unwrappedException()); +} + bool JSContext::isClosingGenerator() { - return isExceptionPending() && - unwrappedException().isMagic(JS_GENERATOR_CLOSING); + return throwing && unwrappedException().isMagic(JS_GENERATOR_CLOSING); } bool JSContext::isThrowingDebuggeeWouldRun() { - return isExceptionPending() && unwrappedException().isObject() && + return throwing && unwrappedException().isObject() && unwrappedException().toObject().is() && unwrappedException().toObject().as().type() == JSEXN_DEBUGGEEWOULDRUN; diff --git a/js/src/vm/JSContext.h b/js/src/vm/JSContext.h index 99a7023abe7d..a9a54c48283f 100644 --- a/js/src/vm/JSContext.h +++ b/js/src/vm/JSContext.h @@ -130,6 +130,8 @@ class InternalJobQueue : public JS::JobQueue { class AutoLockScriptData; +void ReportOverRecursed(JSContext* cx, unsigned errorNumber); + /* Thread Local Storage slot for storing the context for a thread. */ extern MOZ_THREAD_LOCAL(JSContext*) TlsContext; @@ -411,8 +413,7 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext, friend class JS::AutoSaveExceptionState; friend class js::jit::DebugModeOSRVolatileJitFrameIter; - friend void js::ReportOutOfMemory(JSContext*); - friend void js::ReportOverRecursed(JSContext*); + friend void js::ReportOverRecursed(JSContext*, unsigned errorNumber); public: inline JS::Result<> boolToResult(bool ok); @@ -670,8 +671,8 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext, js::ContextData> ionPcScriptCache; private: - // Indicates if an exception is pending and the reason for it. - js::ContextData status; + /* Exception state -- the exception member is a GC root by definition. */ + js::ContextData throwing; /* is there a pending exception? */ js::ContextData> unwrappedException_; /* most-recently-thrown exception */ js::ContextData> @@ -691,6 +692,10 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext, return unwrappedExceptionStack_.ref().get(); } + // True if the exception currently being thrown is by result of + // ReportOverRecursed. See Debugger::slowPathOnExceptionUnwind. + js::ContextData overRecursed_; + #ifdef DEBUG // True if this context has ever called ReportOverRecursed. js::ContextData hadOverRecursed_; @@ -702,6 +707,11 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext, } #endif + private: + // True if propagating a forced return from an interrupt handler during + // debug mode. + js::ContextData propagatingForcedReturn_; + public: js::ContextData reportGranularity; /* see vm/Probes.h */ @@ -795,26 +805,13 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext, inline void minorGC(JS::GCReason reason); public: - bool isExceptionPending() const { - return JS::IsCatchableExceptionStatus(status); - } - - void setInterrupting() { - MOZ_ASSERT(status == JS::ExceptionStatus::None); - status = JS::ExceptionStatus::Interrupt; - } - void clearInterrupt() { - // NOTE: Calling `setInterrupting` is still optional, but certainly there - // should not be any catchable exception pending. - MOZ_ASSERT(status == JS::ExceptionStatus::None || - status == JS::ExceptionStatus::Interrupt); - status = JS::ExceptionStatus::None; - } + bool isExceptionPending() const { return throwing; } [[nodiscard]] bool getPendingException(JS::MutableHandleValue rval); js::SavedFrame* getPendingExceptionStack(); + bool isThrowingOutOfMemory(); bool isThrowingDebuggeeWouldRun(); bool isClosingGenerator(); @@ -822,28 +819,16 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext, void setPendingExceptionAndCaptureStack(JS::HandleValue v); void clearPendingException() { - status = JS::ExceptionStatus::None; + throwing = false; + overRecursed_ = false; unwrappedException().setUndefined(); unwrappedExceptionStack() = nullptr; } - bool isThrowingOutOfMemory() const { - return status == JS::ExceptionStatus::OutOfMemory; - } - bool isThrowingOverRecursed() const { - return status == JS::ExceptionStatus::OverRecursed; - } - bool isPropagatingForcedReturn() const { - return status == JS::ExceptionStatus::ForcedReturn; - } - void setPropagatingForcedReturn() { - MOZ_ASSERT(status == JS::ExceptionStatus::None); - status = JS::ExceptionStatus::ForcedReturn; - } - void clearPropagatingForcedReturn() { - MOZ_ASSERT(status == JS::ExceptionStatus::ForcedReturn); - status = JS::ExceptionStatus::None; - } + bool isThrowingOverRecursed() const { return throwing && overRecursed_; } + bool isPropagatingForcedReturn() const { return propagatingForcedReturn_; } + void setPropagatingForcedReturn() { propagatingForcedReturn_ = true; } + void clearPropagatingForcedReturn() { propagatingForcedReturn_ = false; } /* * See JS_SetTrustedPrincipals in jsapi.h. diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp index c73bf38eaef4..af84728fe1b3 100644 --- a/js/src/vm/JSScript.cpp +++ b/js/src/vm/JSScript.cpp @@ -1423,6 +1423,7 @@ bool JSScript::initScriptCounts(JSContext* cx) { // Allocate the ScriptCounts. UniqueScriptCounts sc = cx->make_unique(std::move(base)); if (!sc) { + ReportOutOfMemory(cx); return false; } diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 934fed963749..dcbc4e4890b5 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -981,6 +981,7 @@ RegExpShared* RegExpZone::get(JSContext* cx, HandleAtom source, new (shared) RegExpShared(source, flags); if (!p.add(cx, set_, Key(source, flags), shared)) { + ReportOutOfMemory(cx); return nullptr; } diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 96912e0e16bc..e2091966a02a 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -482,8 +482,6 @@ static bool HandleInterrupt(JSContext* cx, bool invokeCallback) { chars = u"(stack not available)"; } WarnNumberUC(cx, JSMSG_TERMINATED, chars); - - cx->setInterrupting(); return false; } diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index 47f8c3078a48..d58e9997a9ee 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -1492,6 +1492,7 @@ bool SavedStacks::insertFrames(JSContext* cx, MutableHandleSavedFrame frame, nullptr, // parent (not known yet) principals, iter.mutedErrors(), framePtr, iter.pc(), &activation)) { + ReportOutOfMemory(cx); return false; } diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 7f89e865f304..d843285fe666 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -954,6 +954,7 @@ Shape* SharedShape::new_(JSContext* cx, Handle base, Handle map, uint32_t mapLength) { Shape* shape = Allocate(cx); if (!shape) { + ReportOutOfMemory(cx); return nullptr; } @@ -967,6 +968,7 @@ Shape* DictionaryShape::new_(JSContext* cx, Handle base, uint32_t mapLength) { Shape* shape = Allocate(cx); if (!shape) { + ReportOutOfMemory(cx); return nullptr; } diff --git a/js/src/wasm/WasmCompile.cpp b/js/src/wasm/WasmCompile.cpp index 78535971f69a..2e513ac90813 100644 --- a/js/src/wasm/WasmCompile.cpp +++ b/js/src/wasm/WasmCompile.cpp @@ -143,6 +143,7 @@ SharedCompileArgs CompileArgs::build(JSContext* cx, CompileArgs* target = cx->new_(std::move(scriptedCaller)); if (!target) { + ReportOutOfMemory(cx); return nullptr; } diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp index 4c20086f64e7..94765a3a1b48 100644 --- a/js/src/wasm/WasmJS.cpp +++ b/js/src/wasm/WasmJS.cpp @@ -2904,6 +2904,7 @@ WasmTableObject* WasmTableObject::create(JSContext* cx, uint32_t initialLength, SharedTable table = Table::create(cx, td, obj); if (!table) { + ReportOutOfMemory(cx); return nullptr; } @@ -4242,6 +4243,8 @@ bool WasmFunctionConstruct(JSContext* cx, unsigned argc, Value* vp) { return false; } if (!ParseValTypeArguments(cx, parametersVal, params)) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, + JSMSG_WASM_BAD_ARG_TYPE); return false; } @@ -4251,6 +4254,8 @@ bool WasmFunctionConstruct(JSContext* cx, unsigned argc, Value* vp) { return false; } if (!ParseValTypeArguments(cx, resultsVal, results)) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, + JSMSG_WASM_BAD_ARG_TYPE); return false; } diff --git a/js/src/wasm/WasmModule.cpp b/js/src/wasm/WasmModule.cpp index 2f6a9734a2a3..dd17b82d33c6 100644 --- a/js/src/wasm/WasmModule.cpp +++ b/js/src/wasm/WasmModule.cpp @@ -885,6 +885,7 @@ bool Module::instantiateLocalTable(JSContext* cx, const TableDesc& td, } else { table = Table::create(cx, td, /* HandleWasmTableObject = */ nullptr); if (!table) { + ReportOutOfMemory(cx); return false; } } @@ -1138,6 +1139,7 @@ static bool CreateExportObject( propertyAttr |= JSPROP_READONLY | JSPROP_PERMANENT; } if (!exportObj) { + ReportOutOfMemory(cx); return false; } diff --git a/js/src/wasm/WasmTable.cpp b/js/src/wasm/WasmTable.cpp index 27c0b45c03c9..b14856de205c 100644 --- a/js/src/wasm/WasmTable.cpp +++ b/js/src/wasm/WasmTable.cpp @@ -74,7 +74,6 @@ SharedTable Table::create(JSContext* cx, const TableDesc& desc, case TableRepr::Ref: { TableAnyRefVector objects; if (!objects.resize(desc.initialLength)) { - ReportOutOfMemory(cx); return nullptr; } return SharedTable( diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index 0b1c928e9c70..f6be050e1a1b 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -423,7 +423,6 @@ static bool Quit(JSContext* cx, unsigned argc, Value* vp) { gQuitting = true; // exit(0); - JS_SetPendingInterrupt(cx); return false; }