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)
This commit is contained in:
Sandor Molnar 2021-09-13 23:42:28 +03:00
Родитель a0e14016f8
Коммит d57e75a979
36 изменённых файлов: 174 добавлений и 250 удалений

Просмотреть файл

@ -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;

Просмотреть файл

@ -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<WrapperObject>())
? obj
: UncheckedUnwrapWithoutExpose(obj);

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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<Debugger::DebuggerFrameVector> frames(cx);
Rooted<Debugger::DebuggerFrameVector> 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<Debugger::DebuggerFrameVector> frames(cx);
Rooted<Debugger::DebuggerFrameVector> 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<DebuggerFrameVector> frames(cx);
Rooted<DebuggerFrameVector> 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;
}

Просмотреть файл

@ -944,7 +944,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger> {
* |frame|. |global| is |frame|'s global object; if nullptr or omitted, we
* compute it ourselves from |frame|.
*/
using DebuggerFrameVector = GCVector<DebuggerFrame*, 0, SystemAllocPolicy>;
using DebuggerFrameVector = GCVector<DebuggerFrame*>;
[[nodiscard]] static bool getDebuggerFrames(
AbstractFramePtr frame, MutableHandle<DebuggerFrameVector> frames);

Просмотреть файл

@ -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;
}
}

Просмотреть файл

@ -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)) {

Просмотреть файл

@ -490,7 +490,6 @@ enum class AssembleResult {
masm = MakeUnique<RegExpBytecodeGenerator>(cx->isolate, zone);
}
if (!masm) {
ReportOutOfMemory(cx);
return AssembleResult::OutOfMemory;
}
@ -565,7 +564,6 @@ enum class AssembleResult {
static_cast<SMRegExpMacroAssembler*>(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;

Просмотреть файл

@ -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);

Просмотреть файл

@ -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());
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -265,6 +265,7 @@ MethodStatus BaselineCompiler::compile() {
traceLoggerToggleOffsets_.length()),
JS::DeletePolicy<BaselineScript>(cx->runtime()));
if (!baselineScript) {
ReportOutOfMemory(cx);
return Method_Error;
}

Просмотреть файл

@ -1618,7 +1618,7 @@ static AbortReason IonCompile(JSContext* cx, HandleScript script,
auto alloc =
cx->make_unique<LifoAlloc>(TempAllocator::PreferredLifoChunkSize);
if (!alloc) {
return AbortReason::Error;
return AbortReason::Alloc;
}
TempAllocator* temp = alloc->new_<TempAllocator>(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_<MIRGraph>(temp);

Просмотреть файл

@ -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<Values>();
if (!results_) {
return false;
}
if (!results_->growBy(numResults)) {
ReportOutOfMemory(cx);
if (!results_ || !results_->growBy(numResults)) {
return false;
}

Просмотреть файл

@ -107,7 +107,6 @@ UNIFIED_SOURCES += [
"testSetPropertyIgnoringNamedGetter.cpp",
"testSharedImmutableStringsCache.cpp",
"testSliceBudget.cpp",
"testSlowScript.cpp",
"testSourcePolicy.cpp",
"testSparseBitmap.cpp",
"testStencil.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;
}

Просмотреть файл

@ -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));

Просмотреть файл

@ -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<SavedFrame>();
@ -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<SavedFrame>();

Просмотреть файл

@ -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();
}

Просмотреть файл

@ -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();

Просмотреть файл

@ -944,6 +944,7 @@ static bool num_toString(JSContext* cx, unsigned argc, Value* vp) {
}
JSString* str = NumberToStringWithBase<CanGC>(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<CanGC>(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<CanGC>(cx, d, 10);
if (!str) {
JS_ReportOutOfMemory(cx);
return false;
}
args.rval().setString(str);

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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<OOM> js::ReportOutOfMemoryResult(JSContext* cx) {
@ -315,7 +313,7 @@ mozilla::GenericErrorResult<OOM> 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<ErrorObject>() &&
unwrappedException().toObject().as<ErrorObject>().type() ==
JSEXN_DEBUGGEEWOULDRUN;

Просмотреть файл

@ -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<js::UniquePtr<js::jit::PcScriptCache>> ionPcScriptCache;
private:
// Indicates if an exception is pending and the reason for it.
js::ContextData<JS::ExceptionStatus> status;
/* Exception state -- the exception member is a GC root by definition. */
js::ContextData<bool> throwing; /* is there a pending exception? */
js::ContextData<JS::PersistentRooted<JS::Value>>
unwrappedException_; /* most-recently-thrown exception */
js::ContextData<JS::PersistentRooted<js::SavedFrame*>>
@ -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<bool> overRecursed_;
#ifdef DEBUG
// True if this context has ever called ReportOverRecursed.
js::ContextData<bool> 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<bool> propagatingForcedReturn_;
public:
js::ContextData<int32_t> 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.

Просмотреть файл

@ -1423,6 +1423,7 @@ bool JSScript::initScriptCounts(JSContext* cx) {
// Allocate the ScriptCounts.
UniqueScriptCounts sc = cx->make_unique<ScriptCounts>(std::move(base));
if (!sc) {
ReportOutOfMemory(cx);
return false;
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -954,6 +954,7 @@ Shape* SharedShape::new_(JSContext* cx, Handle<BaseShape*> base,
Handle<SharedPropMap*> map, uint32_t mapLength) {
Shape* shape = Allocate<Shape>(cx);
if (!shape) {
ReportOutOfMemory(cx);
return nullptr;
}
@ -967,6 +968,7 @@ Shape* DictionaryShape::new_(JSContext* cx, Handle<BaseShape*> base,
uint32_t mapLength) {
Shape* shape = Allocate<Shape>(cx);
if (!shape) {
ReportOutOfMemory(cx);
return nullptr;
}

Просмотреть файл

@ -143,6 +143,7 @@ SharedCompileArgs CompileArgs::build(JSContext* cx,
CompileArgs* target = cx->new_<CompileArgs>(std::move(scriptedCaller));
if (!target) {
ReportOutOfMemory(cx);
return nullptr;
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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(

Просмотреть файл

@ -423,7 +423,6 @@ static bool Quit(JSContext* cx, unsigned argc, Value* vp) {
gQuitting = true;
// exit(0);
JS_SetPendingInterrupt(cx);
return false;
}