mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-29 20:07:30 +09:00
Issue #2089 - Use JS engine stack if necessary when reporting errors
Based-on: m-c 996060
This commit is contained in:
parent
0216108195
commit
6b50dd5d06
21 changed files with 209 additions and 69 deletions
|
|
@ -224,16 +224,23 @@ ProcessNameForCollectorLog()
|
|||
|
||||
namespace xpc {
|
||||
|
||||
// This handles JS Exceptions (via ExceptionStackOrNull), as well as DOM and XPC
|
||||
// Exceptions.
|
||||
// This handles JS Exceptions (via ExceptionStackOrNull), DOM and XPC
|
||||
// Exceptions, and arbitrary values that were associated with a stack by the
|
||||
// JS engine when they were thrown, as specified by exceptionStack.
|
||||
//
|
||||
// Note that the returned object is _not_ wrapped into the compartment of
|
||||
// exceptionValue.
|
||||
JSObject*
|
||||
FindExceptionStackForConsoleReport(nsPIDOMWindowInner* win,
|
||||
JS::HandleValue exceptionValue)
|
||||
JS::HandleValue exceptionValue,
|
||||
JS::HandleObject exceptionStack)
|
||||
{
|
||||
if (!exceptionValue.isObject()) {
|
||||
// Use the stack provided by the JS engine, if available. This will not be
|
||||
// a wrapper.
|
||||
if (exceptionStack) {
|
||||
return exceptionStack;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -257,6 +264,10 @@ FindExceptionStackForConsoleReport(nsPIDOMWindowInner* win,
|
|||
// Not a DOM Exception, try XPC Exception.
|
||||
UNWRAP_OBJECT(Exception, exceptionObject, exception);
|
||||
if (!exception) {
|
||||
// As above, use the stack provided by the JS engine, if available.
|
||||
if (exceptionStack) {
|
||||
return exceptionStack;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -421,10 +432,12 @@ public:
|
|||
ScriptErrorEvent(nsPIDOMWindowInner* aWindow,
|
||||
JS::RootingContext* aRootingCx,
|
||||
xpc::ErrorReport* aReport,
|
||||
JS::Handle<JS::Value> aError)
|
||||
JS::Handle<JS::Value> aError,
|
||||
JS::Handle<JSObject*> aErrorStack)
|
||||
: mWindow(aWindow)
|
||||
, mReport(aReport)
|
||||
, mError(aRootingCx, aError)
|
||||
, mErrorStack(aRootingCx, aErrorStack)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
|
|
@ -471,7 +484,7 @@ public:
|
|||
|
||||
if (status != nsEventStatus_eConsumeNoDefault) {
|
||||
JS::Rooted<JSObject*> stack(rootingCx,
|
||||
xpc::FindExceptionStackForConsoleReport(win, mError));
|
||||
xpc::FindExceptionStackForConsoleReport(win, mError, mErrorStack));
|
||||
mReport->LogToConsoleWithStack(stack);
|
||||
}
|
||||
|
||||
|
|
@ -481,7 +494,8 @@ public:
|
|||
private:
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
RefPtr<xpc::ErrorReport> mReport;
|
||||
JS::PersistentRootedValue mError;
|
||||
JS::PersistentRootedValue mError;
|
||||
JS::PersistentRootedObject mErrorStack;
|
||||
|
||||
static bool sHandlingScriptError;
|
||||
};
|
||||
|
|
@ -494,9 +508,10 @@ namespace xpc {
|
|||
|
||||
void
|
||||
DispatchScriptErrorEvent(nsPIDOMWindowInner *win, JS::RootingContext* rootingCx,
|
||||
xpc::ErrorReport *xpcReport, JS::Handle<JS::Value> exception)
|
||||
xpc::ErrorReport *xpcReport, JS::Handle<JS::Value> exception,
|
||||
JS::Handle<JSObject*> exceptionStack)
|
||||
{
|
||||
nsContentUtils::AddScriptRunner(new ScriptErrorEvent(win, rootingCx, xpcReport, exception));
|
||||
nsContentUtils::AddScriptRunner(new ScriptErrorEvent(win, rootingCx, xpcReport, exception, exceptionStack));
|
||||
}
|
||||
|
||||
} /* namespace xpc */
|
||||
|
|
|
|||
|
|
@ -577,8 +577,9 @@ AutoJSAPI::ReportException()
|
|||
}
|
||||
JSAutoCompartment ac(cx(), errorGlobal);
|
||||
JS::Rooted<JS::Value> exn(cx());
|
||||
JS::Rooted<JSObject*> exnStack(cx());
|
||||
js::ErrorReport jsReport(cx());
|
||||
if (StealException(&exn) &&
|
||||
if (StealExceptionAndStack(&exn, &exnStack) &&
|
||||
jsReport.init(cx(), exn, js::ErrorReport::WithSideEffects)) {
|
||||
if (mIsMainThread) {
|
||||
RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
|
||||
|
|
@ -595,10 +596,10 @@ AutoJSAPI::ReportException()
|
|||
inner ? inner->WindowID() : 0);
|
||||
if (inner && jsReport.report()->errorNumber != JSMSG_OUT_OF_MEMORY) {
|
||||
JS::RootingContext* rcx = JS::RootingContext::get(cx());
|
||||
DispatchScriptErrorEvent(inner, rcx, xpcReport, exn);
|
||||
DispatchScriptErrorEvent(inner, rcx, xpcReport, exn, exnStack);
|
||||
} else {
|
||||
JS::Rooted<JSObject*> stack(cx(),
|
||||
xpc::FindExceptionStackForConsoleReport(inner, exn));
|
||||
xpc::FindExceptionStackForConsoleReport(inner, exn, exnStack));
|
||||
xpcReport->LogToConsoleWithStack(stack);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -638,9 +639,16 @@ AutoJSAPI::PeekException(JS::MutableHandle<JS::Value> aVal)
|
|||
bool
|
||||
AutoJSAPI::StealException(JS::MutableHandle<JS::Value> aVal)
|
||||
{
|
||||
JS::Rooted<JSObject*> stack(cx());
|
||||
return StealExceptionAndStack(aVal, &stack);
|
||||
}
|
||||
|
||||
bool AutoJSAPI::StealExceptionAndStack(JS::MutableHandle<JS::Value> aVal,
|
||||
JS::MutableHandle<JSObject*> aStack) {
|
||||
if (!PeekException(aVal)) {
|
||||
return false;
|
||||
}
|
||||
aStack.set(JS::GetPendingExceptionStack(cx()));
|
||||
JS_ClearPendingException(cx());
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -274,6 +274,12 @@ public:
|
|||
// into the current compartment.
|
||||
MOZ_MUST_USE bool StealException(JS::MutableHandle<JS::Value> aVal);
|
||||
|
||||
// As for StealException(), but put the saved frames for any stack trace
|
||||
// associated with the point the exception was thrown into aStack.
|
||||
// aVal will be in the current compartment, but aStack might not be.
|
||||
MOZ_MUST_USE bool StealExceptionAndStack(JS::MutableHandle<JS::Value> aVal,
|
||||
JS::MutableHandle<JSObject*> aStack);
|
||||
|
||||
// Peek the current exception from the JS engine, without stealing it.
|
||||
// Callers must ensure that HasException() is true, and that cx() is in a
|
||||
// non-null compartment.
|
||||
|
|
|
|||
|
|
@ -941,7 +941,7 @@ HandleDebugTrap(JSContext* cx, BaselineFrame* frame, uint8_t* retAddr, bool* mus
|
|||
return jit::DebugEpilogue(cx, frame, pc, true);
|
||||
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
cx->setPendingExceptionAndCaptureStack(rval);
|
||||
return false;
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -6219,12 +6219,16 @@ JS_GetPendingException(JSContext* cx, MutableHandleValue vp)
|
|||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetPendingException(JSContext* cx, HandleValue value)
|
||||
JS_SetPendingException(JSContext* cx, HandleValue value, JS::ExceptionStackBehavior behavior)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
releaseAssertSameCompartment(cx, value);
|
||||
cx->setPendingException(value);
|
||||
if (behavior == JS::ExceptionStackBehavior::Capture) {
|
||||
cx->setPendingExceptionAndCaptureStack(value);
|
||||
} else {
|
||||
cx->setPendingException(value, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
|
|
@ -6234,12 +6238,20 @@ JS_ClearPendingException(JSContext* cx)
|
|||
cx->clearPendingException();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
JS::GetPendingExceptionStack(JSContext* cx)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
return cx->getPendingExceptionStack();
|
||||
}
|
||||
|
||||
JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext* cx)
|
||||
: context(cx),
|
||||
wasPropagatingForcedReturn(cx->propagatingForcedReturn_),
|
||||
wasOverRecursed(cx->overRecursed_),
|
||||
wasThrowing(cx->throwing),
|
||||
exceptionValue(cx)
|
||||
exceptionValue(cx),
|
||||
exceptionStack(cx)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
|
|
@ -6249,10 +6261,21 @@ JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext* cx)
|
|||
cx->overRecursed_ = false;
|
||||
if (wasThrowing) {
|
||||
exceptionValue = cx->unwrappedException_;
|
||||
exceptionStack = cx->unwrappedExceptionStack_;
|
||||
cx->clearPendingException();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JS::AutoSaveExceptionState::drop()
|
||||
{
|
||||
wasPropagatingForcedReturn = false;
|
||||
wasOverRecursed = false;
|
||||
wasThrowing = false;
|
||||
exceptionValue.setUndefined();
|
||||
exceptionStack = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
JS::AutoSaveExceptionState::restore()
|
||||
{
|
||||
|
|
@ -6260,6 +6283,9 @@ JS::AutoSaveExceptionState::restore()
|
|||
context->overRecursed_ = wasOverRecursed;
|
||||
context->throwing = wasThrowing;
|
||||
context->unwrappedException_ = exceptionValue;
|
||||
if (exceptionStack) {
|
||||
context->unwrappedExceptionStack_ = &exceptionStack->as<SavedFrame>();
|
||||
}
|
||||
drop();
|
||||
}
|
||||
|
||||
|
|
@ -6272,6 +6298,9 @@ JS::AutoSaveExceptionState::~AutoSaveExceptionState()
|
|||
context->overRecursed_ = wasOverRecursed;
|
||||
context->throwing = true;
|
||||
context->unwrappedException_ = exceptionValue;
|
||||
if (exceptionStack) {
|
||||
context->unwrappedExceptionStack_ = &exceptionStack->as<SavedFrame>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5762,8 +5762,22 @@ JS_IsExceptionPending(JSContext* cx);
|
|||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetPendingException(JSContext* cx, JS::MutableHandleValue vp);
|
||||
|
||||
namespace JS {
|
||||
|
||||
enum class ExceptionStackBehavior: bool {
|
||||
// Do not capture any stack.
|
||||
DoNotCapture,
|
||||
|
||||
// Capture the current JS stack when setting the exception. It may be
|
||||
// retrieved by JS::GetPendingExceptionStack.
|
||||
Capture
|
||||
};
|
||||
|
||||
} // namespace JS
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_SetPendingException(JSContext* cx, JS::HandleValue v);
|
||||
JS_SetPendingException(JSContext* cx, JS::HandleValue v,
|
||||
JS::ExceptionStackBehavior behavior = JS::ExceptionStackBehavior::Capture);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_ClearPendingException(JSContext* cx);
|
||||
|
|
@ -5790,6 +5804,7 @@ class JS_PUBLIC_API(AutoSaveExceptionState)
|
|||
bool wasOverRecursed;
|
||||
bool wasThrowing;
|
||||
RootedValue exceptionValue;
|
||||
RootedObject exceptionStack;
|
||||
|
||||
public:
|
||||
/*
|
||||
|
|
@ -5808,12 +5823,7 @@ class JS_PUBLIC_API(AutoSaveExceptionState)
|
|||
* Discard any stored exception state.
|
||||
* If this is called, the destructor is a no-op.
|
||||
*/
|
||||
void drop() {
|
||||
wasPropagatingForcedReturn = false;
|
||||
wasOverRecursed = false;
|
||||
wasThrowing = false;
|
||||
exceptionValue.setUndefined();
|
||||
}
|
||||
void drop();
|
||||
|
||||
/*
|
||||
* Replace cx's exception state with the stored exception state. Then
|
||||
|
|
@ -5823,6 +5833,18 @@ class JS_PUBLIC_API(AutoSaveExceptionState)
|
|||
void restore();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the SavedFrame stack object captured when the pending exception was set
|
||||
* on the JSContext. This fuzzily correlates with a `throw` statement in JS,
|
||||
* although arbitrary JSAPI consumers or VM code may also set pending exceptions
|
||||
* via `JS_SetPendingException`.
|
||||
*
|
||||
* This is not the same stack as `e.stack` when `e` is an `Error` object. (That
|
||||
* would be JS::ExceptionStackOrNull).
|
||||
*/
|
||||
MOZ_MUST_USE JS_PUBLIC_API(JSObject*)
|
||||
GetPendingExceptionStack(JSContext* cx);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
/* Deprecated API. Use AutoSaveExceptionState instead. */
|
||||
|
|
|
|||
|
|
@ -241,7 +241,8 @@ js::ReportOutOfMemory(ExclusiveContext* cxArg)
|
|||
if (JS::OutOfMemoryCallback oomCallback = cx->runtime()->oomCallback)
|
||||
oomCallback(cx, cx->runtime()->oomCallbackData);
|
||||
|
||||
cx->setPendingException(StringValue(cx->names().outOfMemory));
|
||||
RootedValue oomMessage(cx, StringValue(cx->names().outOfMemory));
|
||||
cx->setPendingException(oomMessage, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1013,6 +1014,7 @@ JSContext::JSContext(JSRuntime* parentRuntime)
|
|||
JSRuntime(parentRuntime),
|
||||
throwing(false),
|
||||
unwrappedException_(this),
|
||||
unwrappedExceptionStack_(this),
|
||||
overRecursed_(false),
|
||||
propagatingForcedReturn_(false),
|
||||
liveVolatileJitFrameIterators_(nullptr),
|
||||
|
|
@ -1038,6 +1040,24 @@ JSContext::~JSContext()
|
|||
MOZ_ASSERT(!resolvingList);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSContext::setPendingExceptionAndCaptureStack(HandleValue value)
|
||||
{
|
||||
static const size_t MAX_REPORTED_STACK_DEPTH = 1u << 7;
|
||||
|
||||
RootedObject stack(this);
|
||||
if (!CaptureCurrentStack(this, &stack, JS::StackCapture(JS::MaxFrames(MAX_REPORTED_STACK_DEPTH)))) {
|
||||
clearPendingException();
|
||||
}
|
||||
|
||||
RootedSavedFrame nstack(this);
|
||||
if (stack) {
|
||||
nstack = &stack->as<SavedFrame>();
|
||||
}
|
||||
setPendingException(value, nstack);
|
||||
}
|
||||
|
||||
bool
|
||||
JSContext::getPendingException(MutableHandleValue rval)
|
||||
{
|
||||
|
|
@ -1045,16 +1065,23 @@ JSContext::getPendingException(MutableHandleValue rval)
|
|||
rval.set(unwrappedException_);
|
||||
if (IsAtomsCompartment(compartment()))
|
||||
return true;
|
||||
RootedSavedFrame stack(this, unwrappedExceptionStack_);
|
||||
bool wasOverRecursed = overRecursed_;
|
||||
clearPendingException();
|
||||
if (!compartment()->wrap(this, rval))
|
||||
return false;
|
||||
assertSameCompartment(this, rval);
|
||||
setPendingException(rval);
|
||||
setPendingException(rval, stack);
|
||||
overRecursed_ = wasOverRecursed;
|
||||
return true;
|
||||
}
|
||||
|
||||
SavedFrame*
|
||||
JSContext::getPendingExceptionStack()
|
||||
{
|
||||
return unwrappedExceptionStack_;
|
||||
}
|
||||
|
||||
bool
|
||||
JSContext::isThrowingOutOfMemory()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -369,6 +369,7 @@ struct JSContext : public js::ExclusiveContext,
|
|||
/* Exception state -- the exception member is a GC root by definition. */
|
||||
bool throwing; /* is there a pending exception? */
|
||||
JS::PersistentRooted<JS::Value> unwrappedException_; /* most-recently-thrown exception */
|
||||
JS::PersistentRooted<js::SavedFrame*> unwrappedExceptionStack_; /* stack when the exception was thrown */
|
||||
|
||||
// True if the exception currently being thrown is by result of
|
||||
// ReportOverRecursed. See Debugger::slowPathOnExceptionUnwind.
|
||||
|
|
@ -495,17 +496,21 @@ struct JSContext : public js::ExclusiveContext,
|
|||
|
||||
MOZ_MUST_USE
|
||||
bool getPendingException(JS::MutableHandleValue rval);
|
||||
|
||||
js::SavedFrame* getPendingExceptionStack();
|
||||
|
||||
bool isThrowingOutOfMemory();
|
||||
bool isThrowingDebuggeeWouldRun();
|
||||
bool isClosingGenerator();
|
||||
|
||||
void setPendingException(const js::Value& v);
|
||||
void setPendingException(JS::HandleValue v, js::HandleSavedFrame stack);
|
||||
void setPendingExceptionAndCaptureStack(JS::HandleValue v);
|
||||
|
||||
void clearPendingException() {
|
||||
throwing = false;
|
||||
overRecursed_ = false;
|
||||
unwrappedException_.setUndefined();
|
||||
unwrappedExceptionStack_ = nullptr;
|
||||
}
|
||||
|
||||
bool isThrowingOverRecursed() const { return throwing && overRecursed_; }
|
||||
|
|
|
|||
|
|
@ -368,12 +368,13 @@ ExclusiveContext::typeLifoAlloc()
|
|||
} /* namespace js */
|
||||
|
||||
inline void
|
||||
JSContext::setPendingException(const js::Value& v)
|
||||
JSContext::setPendingException(JS::HandleValue v, js::HandleSavedFrame stack)
|
||||
{
|
||||
// overRecursed_ is set after the fact by ReportOverRecursed.
|
||||
this->overRecursed_ = false;
|
||||
this->throwing = true;
|
||||
this->unwrappedException_ = v;
|
||||
this->unwrappedExceptionStack_ = stack;
|
||||
// We don't use assertSameCompartment here to allow
|
||||
// js::SetPendingExceptionCrossContext to work.
|
||||
MOZ_ASSERT_IF(v.isObject(), v.toObject().compartment() == compartment());
|
||||
|
|
|
|||
|
|
@ -361,13 +361,13 @@ struct SuppressErrorsGuard
|
|||
}
|
||||
};
|
||||
|
||||
// Cut off the stack if it gets too deep (most commonly for infinite recursion
|
||||
// errors).
|
||||
static const size_t MAX_REPORTED_STACK_DEPTH = 1u << 7;
|
||||
|
||||
static bool
|
||||
CaptureStack(JSContext* cx, MutableHandleObject stack)
|
||||
{
|
||||
// Cut off the stack if it gets too deep (most commonly for infinite recursion
|
||||
// errors).
|
||||
static const size_t MAX_REPORTED_STACK_DEPTH = 1u << 7;
|
||||
|
||||
return CaptureCurrentStack(cx, stack,
|
||||
JS::StackCapture(JS::MaxFrames(MAX_REPORTED_STACK_DEPTH)));
|
||||
}
|
||||
|
|
@ -699,7 +699,12 @@ js::ErrorToException(JSContext* cx, JSErrorReport* reportp,
|
|||
return;
|
||||
|
||||
// Throw it.
|
||||
cx->setPendingException(ObjectValue(*errObject));
|
||||
RootedValue errValue(cx, ObjectValue(*errObject));
|
||||
RootedSavedFrame nstack(cx);
|
||||
if (stack) {
|
||||
nstack = &stack->as<SavedFrame>();
|
||||
}
|
||||
cx->setPendingException(errValue, nstack);
|
||||
|
||||
// Flag the error report passed in to indicate an exception was raised.
|
||||
reportp->flags |= JSREPORT_EXCEPTION;
|
||||
|
|
|
|||
|
|
@ -971,8 +971,10 @@ js::ThrowStopIteration(JSContext* cx)
|
|||
// StopIteration isn't a constructor, but it's stored in GlobalObject
|
||||
// as one, out of laziness. Hence the GetBuiltinConstructor call here.
|
||||
RootedObject ctor(cx);
|
||||
if (GetBuiltinConstructor(cx, JSProto_StopIteration, &ctor))
|
||||
cx->setPendingException(ObjectValue(*ctor));
|
||||
if (GetBuiltinConstructor(cx, JSProto_StopIteration, &ctor)) {
|
||||
RootedValue ctorval(cx, ObjectValue(*ctor));
|
||||
cx->setPendingExceptionAndCaptureStack(ctorval);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1261,12 +1263,13 @@ js::UnwindIteratorForException(JSContext* cx, HandleObject obj)
|
|||
{
|
||||
RootedValue v(cx);
|
||||
bool getOk = cx->getPendingException(&v);
|
||||
RootedSavedFrame stack(cx, cx->getPendingExceptionStack());
|
||||
cx->clearPendingException();
|
||||
if (!CloseIterator(cx, obj))
|
||||
return false;
|
||||
if (!getOk)
|
||||
return false;
|
||||
cx->setPendingException(v);
|
||||
cx->setPendingException(v, stack);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -408,12 +408,15 @@ ErrorCopier::~ErrorCopier()
|
|||
{
|
||||
RootedValue exc(cx);
|
||||
if (cx->getPendingException(&exc) && exc.isObject() && exc.toObject().is<ErrorObject>()) {
|
||||
RootedSavedFrame stack(cx, cx->getPendingExceptionStack());
|
||||
cx->clearPendingException();
|
||||
ac.reset();
|
||||
Rooted<ErrorObject*> errObj(cx, &exc.toObject().as<ErrorObject>());
|
||||
JSObject* copyobj = CopyErrorObject(cx, errObj);
|
||||
if (copyobj)
|
||||
cx->setPendingException(ObjectValue(*copyobj));
|
||||
if (copyobj) {
|
||||
RootedValue rootedCopy(cx, ObjectValue(*copyobj));
|
||||
cx->setPendingException(rootedCopy, stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -848,7 +848,7 @@ Debugger::slowPathOnEnterFrame(JSContext* cx, AbstractFramePtr frame)
|
|||
break;
|
||||
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
cx->setPendingExceptionAndCaptureStack(rval);
|
||||
break;
|
||||
|
||||
case JSTRAP_ERROR:
|
||||
|
|
@ -960,7 +960,7 @@ Debugger::slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode
|
|||
return true;
|
||||
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(value);
|
||||
cx->setPendingExceptionAndCaptureStack(value);
|
||||
return false;
|
||||
|
||||
case JSTRAP_ERROR:
|
||||
|
|
@ -993,7 +993,7 @@ Debugger::slowPathOnDebuggerStatement(JSContext* cx, AbstractFramePtr frame)
|
|||
break;
|
||||
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
cx->setPendingExceptionAndCaptureStack(rval);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -1028,7 +1028,7 @@ Debugger::slowPathOnExceptionUnwind(JSContext* cx, AbstractFramePtr frame)
|
|||
break;
|
||||
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
cx->setPendingExceptionAndCaptureStack(rval);
|
||||
break;
|
||||
|
||||
case JSTRAP_ERROR:
|
||||
|
|
@ -1321,7 +1321,7 @@ public:
|
|||
|
||||
bool operator()(JSContext* cx) override
|
||||
{
|
||||
cx->setPendingException(exn_);
|
||||
cx->setPendingExceptionAndCaptureStack(exn_);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1753,6 +1753,7 @@ Debugger::fireExceptionUnwind(JSContext* cx, MutableHandleValue vp)
|
|||
MOZ_ASSERT(hook->isCallable());
|
||||
|
||||
RootedValue exc(cx);
|
||||
RootedSavedFrame stack(cx, cx->getPendingExceptionStack());
|
||||
if (!cx->getPendingException(&exc))
|
||||
return JSTRAP_ERROR;
|
||||
cx->clearPendingException();
|
||||
|
|
@ -1772,7 +1773,7 @@ Debugger::fireExceptionUnwind(JSContext* cx, MutableHandleValue vp)
|
|||
bool ok = js::Call(cx, fval, object, scriptFrame, wrappedExc, &rv);
|
||||
JSTrapStatus st = processHandlerResult(ac, ok, rv, iter.abstractFramePtr(), iter.pc(), vp);
|
||||
if (st == JSTRAP_CONTINUE)
|
||||
cx->setPendingException(exc);
|
||||
cx->setPendingException(exc, stack);
|
||||
return st;
|
||||
}
|
||||
|
||||
|
|
@ -2005,13 +2006,7 @@ Debugger::onSingleStep(JSContext* cx, MutableHandleValue vp)
|
|||
* onStep handlers mess with that (other than by returning a resumption
|
||||
* value).
|
||||
*/
|
||||
RootedValue exception(cx, UndefinedValue());
|
||||
bool exceptionPending = cx->isExceptionPending();
|
||||
if (exceptionPending) {
|
||||
if (!cx->getPendingException(&exception))
|
||||
return JSTRAP_ERROR;
|
||||
cx->clearPendingException();
|
||||
}
|
||||
JS::AutoSaveExceptionState savedExc(cx);
|
||||
|
||||
/*
|
||||
* Build list of Debugger.Frame instances referring to this frame with
|
||||
|
|
@ -2070,13 +2065,13 @@ Debugger::onSingleStep(JSContext* cx, MutableHandleValue vp)
|
|||
bool ok = js::Call(cx, fval, frame, &rval);
|
||||
JSTrapStatus st = dbg->processHandlerResult(ac, ok, rval, iter.abstractFramePtr(),
|
||||
iter.pc(), vp);
|
||||
if (st != JSTRAP_CONTINUE)
|
||||
if (st != JSTRAP_CONTINUE) {
|
||||
savedExc.drop();
|
||||
return st;
|
||||
}
|
||||
}
|
||||
|
||||
vp.setUndefined();
|
||||
if (exceptionPending)
|
||||
cx->setPendingException(exception);
|
||||
return JSTRAP_CONTINUE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -158,9 +158,12 @@ ForOfIterator::closeThrow()
|
|||
MOZ_ASSERT(iterator);
|
||||
|
||||
RootedValue completionException(cx_);
|
||||
RootedSavedFrame completionExceptionStack(cx_);
|
||||
if (cx_->isExceptionPending()) {
|
||||
if (!GetAndClearException(cx_, &completionException))
|
||||
if (!GetAndClearExceptionAndStack(cx_, &completionException, &completionExceptionStack)) {
|
||||
completionException.setUndefined();
|
||||
completionExceptionStack = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Steps 1-2 (implicit)
|
||||
|
|
@ -172,7 +175,7 @@ ForOfIterator::closeThrow()
|
|||
|
||||
// Step 4.
|
||||
if (returnVal.isUndefined()) {
|
||||
cx_->setPendingException(completionException);
|
||||
cx_->setPendingException(completionException, completionExceptionStack);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +198,7 @@ ForOfIterator::closeThrow()
|
|||
}
|
||||
|
||||
// Step 6.
|
||||
cx_->setPendingException(completionException);
|
||||
cx_->setPendingException(completionException, completionExceptionStack);
|
||||
|
||||
// Steps 7-9 (skipped).
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ js::GeneratorThrowOrClose(JSContext* cx, AbstractFramePtr frame, Handle<Generato
|
|||
HandleValue arg, uint32_t resumeKind)
|
||||
{
|
||||
if (resumeKind == GeneratorObject::THROW) {
|
||||
cx->setPendingException(arg);
|
||||
cx->setPendingExceptionAndCaptureStack(arg);
|
||||
genObj->setRunning();
|
||||
} else {
|
||||
MOZ_ASSERT(resumeKind == GeneratorObject::CLOSE);
|
||||
|
|
@ -143,7 +143,8 @@ js::GeneratorThrowOrClose(JSContext* cx, AbstractFramePtr frame, Handle<Generato
|
|||
MOZ_ASSERT(arg.isUndefined());
|
||||
}
|
||||
|
||||
cx->setPendingException(MagicValue(JS_GENERATOR_CLOSING));
|
||||
RootedValue closing(cx, MagicValue(JS_GENERATOR_CLOSING));
|
||||
cx->setPendingException(closing, nullptr);
|
||||
genObj->setClosing();
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1883,7 +1883,7 @@ CASE(EnableInterruptsPseudoOpcode)
|
|||
goto error;
|
||||
goto successful_return_continuation;
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
cx->setPendingExceptionAndCaptureStack(rval);
|
||||
goto error;
|
||||
default:;
|
||||
}
|
||||
|
|
@ -1905,7 +1905,7 @@ CASE(EnableInterruptsPseudoOpcode)
|
|||
goto error;
|
||||
goto successful_return_continuation;
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
cx->setPendingExceptionAndCaptureStack(rval);
|
||||
goto error;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -3825,7 +3825,8 @@ CASE(JSOP_RETSUB)
|
|||
* be necessary, but it seems clearer. And it points out a FIXME:
|
||||
* 350509, due to Igor Bukanov.
|
||||
*/
|
||||
cx->setPendingException(rval);
|
||||
ReservedRooted<Value> v(&rootValue0, rval);
|
||||
cx->setPendingExceptionAndCaptureStack(v);
|
||||
goto error;
|
||||
}
|
||||
MOZ_ASSERT(rval.isInt32());
|
||||
|
|
@ -4331,7 +4332,7 @@ bool
|
|||
js::Throw(JSContext* cx, HandleValue v)
|
||||
{
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
cx->setPendingException(v);
|
||||
cx->setPendingExceptionAndCaptureStack(v);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -4342,7 +4343,7 @@ js::ThrowingOperation(JSContext* cx, HandleValue v)
|
|||
// execution instead of calling the (JIT) exception handler.
|
||||
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
cx->setPendingException(v);
|
||||
cx->setPendingExceptionAndCaptureStack(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -4548,16 +4549,25 @@ js::ThrowMsgOperation(JSContext* cx, const unsigned errorNum)
|
|||
}
|
||||
|
||||
bool
|
||||
js::GetAndClearException(JSContext* cx, MutableHandleValue res)
|
||||
js::GetAndClearExceptionAndStack(JSContext* cx, MutableHandleValue res,
|
||||
MutableHandleSavedFrame stack)
|
||||
{
|
||||
if (!cx->getPendingException(res))
|
||||
return false;
|
||||
stack.set(cx->getPendingExceptionStack());
|
||||
cx->clearPendingException();
|
||||
|
||||
// Allow interrupting deeply nested exception handling.
|
||||
return CheckForInterrupt(cx);
|
||||
}
|
||||
|
||||
bool
|
||||
js::GetAndClearException(JSContext* cx, MutableHandleValue res)
|
||||
{
|
||||
RootedSavedFrame stack(cx);
|
||||
return GetAndClearExceptionAndStack(cx, res, &stack);
|
||||
}
|
||||
|
||||
template <bool strict>
|
||||
bool
|
||||
js::DeletePropertyJit(JSContext* cx, HandleValue v, HandlePropertyName name, bool* bp)
|
||||
|
|
|
|||
|
|
@ -489,6 +489,9 @@ ThrowMsgOperation(JSContext* cx, const unsigned errorNum);
|
|||
bool
|
||||
GetAndClearException(JSContext* cx, MutableHandleValue res);
|
||||
|
||||
bool
|
||||
GetAndClearExceptionAndStack(JSContext* cx, MutableHandleValue res, MutableHandleSavedFrame stack);
|
||||
|
||||
bool
|
||||
DeleteNameOperation(JSContext* cx, HandlePropertyName name, HandleObject scopeObj,
|
||||
MutableHandleValue res);
|
||||
|
|
|
|||
|
|
@ -548,7 +548,7 @@ InvokeInterruptCallback(JSContext* cx)
|
|||
Debugger::propagateForcedReturn(cx, iter.abstractFramePtr(), rval);
|
||||
return false;
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
cx->setPendingExceptionAndCaptureStack(rval);
|
||||
return false;
|
||||
default:;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1729,7 +1729,8 @@ RejectWithPendingException(JSContext* cx, Handle<PromiseObject*> promise)
|
|||
return false;
|
||||
|
||||
RootedValue rejectionValue(cx);
|
||||
if (!GetAndClearException(cx, &rejectionValue))
|
||||
RootedSavedFrame stack(cx);
|
||||
if (!GetAndClearExceptionAndStack(cx, &rejectionValue, &stack))
|
||||
return false;
|
||||
|
||||
return PromiseObject::reject(cx, promise, rejectionValue);
|
||||
|
|
|
|||
|
|
@ -2310,7 +2310,7 @@ nsXPCComponents_Utils::ReportError(HandleValue error, JSContext* cx)
|
|||
|
||||
if (errorObj) {
|
||||
JS::RootedObject stackVal(cx,
|
||||
FindExceptionStackForConsoleReport(win, error));
|
||||
FindExceptionStackForConsoleReport(win, error, nullptr));
|
||||
if (stackVal) {
|
||||
scripterr = new nsScriptErrorWithStack(stackVal);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -590,11 +590,13 @@ class ErrorReport : public ErrorBase {
|
|||
|
||||
void
|
||||
DispatchScriptErrorEvent(nsPIDOMWindowInner* win, JS::RootingContext* rootingCx,
|
||||
xpc::ErrorReport* xpcReport, JS::Handle<JS::Value> exception);
|
||||
xpc::ErrorReport* xpcReport, JS::Handle<JS::Value> exception,
|
||||
JS::Handle<JSObject*> exceptionStack);
|
||||
|
||||
// Get a stack of the sort that can be passed to
|
||||
// xpc::ErrorReport::LogToConsoleWithStack from the given exception value. Can
|
||||
// return null if the exception value doesn't have an associated stack. The
|
||||
// be nullptr if the exception value doesn't have an associated stack, and if
|
||||
// there is no stack supplied by the JS engine in exceptionStack. The
|
||||
// returned stack, if any, may also not be in the same compartment as
|
||||
// exceptionValue.
|
||||
//
|
||||
|
|
@ -605,7 +607,8 @@ DispatchScriptErrorEvent(nsPIDOMWindowInner* win, JS::RootingContext* rootingCx,
|
|||
// the stack in the console message keeping the window alive.
|
||||
JSObject*
|
||||
FindExceptionStackForConsoleReport(nsPIDOMWindowInner* win,
|
||||
JS::HandleValue exceptionValue);
|
||||
JS::HandleValue exceptionValue,
|
||||
JS::HandleObject exceptionStack);
|
||||
|
||||
// Return a name for the compartment.
|
||||
// This function makes reasonable efforts to make this name both mostly human-readable
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue