mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 951282 - Wrap the pending exception lazily; r=luke
--HG-- extra : rebase_source : e2bf58c6c5ba5ba857a97bd18f5543f32da6f508
This commit is contained in:
parent
3e8465db86
commit
17b810fe52
@ -540,7 +540,9 @@ HandleExceptionBaseline(JSContext *cx, const IonFrameIterator &frame, ResumeFrom
|
||||
rfe->kind = ResumeFromException::RESUME_FINALLY;
|
||||
jsbytecode *finallyPC = script->main() + tn->start + tn->length;
|
||||
rfe->target = script->baselineScript()->nativeCodeForPC(script, finallyPC);
|
||||
rfe->exception = cx->getPendingException();
|
||||
// Drop the exception instead of leaking cross compartment data.
|
||||
if (!cx->getPendingException(MutableHandleValue::fromMarkedLocation(&rfe->exception)))
|
||||
rfe->exception = UndefinedValue();
|
||||
cx->clearPendingException();
|
||||
return;
|
||||
}
|
||||
|
@ -5865,9 +5865,7 @@ JS_GetPendingException(JSContext *cx, MutableHandleValue vp)
|
||||
CHECK_REQUEST(cx);
|
||||
if (!cx->isExceptionPending())
|
||||
return false;
|
||||
vp.set(cx->getPendingException());
|
||||
assertSameCompartment(cx, vp);
|
||||
return true;
|
||||
return cx->getPendingException(vp);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
|
@ -1073,7 +1073,7 @@ ThreadSafeContext::asForkJoinSlice()
|
||||
JSContext::JSContext(JSRuntime *rt)
|
||||
: ExclusiveContext(rt, &rt->mainThread, Context_JS),
|
||||
throwing(false),
|
||||
exception(UndefinedValue()),
|
||||
unwrappedException_(UndefinedValue()),
|
||||
options_(),
|
||||
reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
|
||||
resolvingList(nullptr),
|
||||
@ -1109,21 +1109,21 @@ JSContext::~JSContext()
|
||||
JS_ASSERT(!resolvingList);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since this function is only called in the context of a pending exception,
|
||||
* the caller must subsequently take an error path. If wrapping fails, it will
|
||||
* set a new (uncatchable) exception to be used in place of the original.
|
||||
*/
|
||||
void
|
||||
JSContext::wrapPendingException()
|
||||
bool
|
||||
JSContext::getPendingException(MutableHandleValue rval)
|
||||
{
|
||||
RootedValue value(this, getPendingException());
|
||||
JS_ASSERT(throwing);
|
||||
rval.set(unwrappedException_);
|
||||
if (IsAtomsCompartment(compartment()))
|
||||
return true;
|
||||
clearPendingException();
|
||||
if (!IsAtomsCompartment(compartment()) && compartment()->wrap(this, &value))
|
||||
setPendingException(value);
|
||||
if (!compartment()->wrap(this, rval))
|
||||
return false;
|
||||
assertSameCompartment(this, rval);
|
||||
setPendingException(rval);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSContext::enterGenerator(JSGenerator *gen)
|
||||
{
|
||||
@ -1171,9 +1171,6 @@ JSContext::restoreFrameChain()
|
||||
|
||||
if (Activation *act = mainThread().activation())
|
||||
act->restoreFrameChain();
|
||||
|
||||
if (isExceptionPending())
|
||||
wrapPendingException();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1287,7 +1284,7 @@ JSContext::mark(JSTracer *trc)
|
||||
if (defaultCompartmentObject_)
|
||||
MarkObjectRoot(trc, &defaultCompartmentObject_, "default compartment object");
|
||||
if (isExceptionPending())
|
||||
MarkValueRoot(trc, &exception, "exception");
|
||||
MarkValueRoot(trc, &unwrappedException_, "unwrapped exception");
|
||||
|
||||
TraceCycleDetectionSet(trc, cycleDetectorSet);
|
||||
|
||||
|
@ -426,7 +426,7 @@ struct JSContext : public js::ExclusiveContext,
|
||||
private:
|
||||
/* Exception state -- the exception member is a GC root by definition. */
|
||||
bool throwing; /* is there a pending exception? */
|
||||
js::Value exception; /* most-recently-thrown exception */
|
||||
js::Value unwrappedException_; /* most-recently-thrown exception */
|
||||
|
||||
/* Per-context options. */
|
||||
JS::ContextOptions options_;
|
||||
@ -468,9 +468,6 @@ struct JSContext : public js::ExclusiveContext,
|
||||
return defaultCompartmentObject_;
|
||||
}
|
||||
|
||||
/* Wrap cx->exception for the current compartment. */
|
||||
void wrapPendingException();
|
||||
|
||||
/* State for object and array toSource conversion. */
|
||||
js::ObjectSet cycleDetectorSet;
|
||||
|
||||
@ -583,16 +580,13 @@ struct JSContext : public js::ExclusiveContext,
|
||||
return throwing;
|
||||
}
|
||||
|
||||
js::Value getPendingException() {
|
||||
JS_ASSERT(throwing);
|
||||
return exception;
|
||||
}
|
||||
bool getPendingException(JS::MutableHandleValue rval);
|
||||
|
||||
void setPendingException(js::Value v);
|
||||
|
||||
void clearPendingException() {
|
||||
throwing = false;
|
||||
exception.setUndefined();
|
||||
unwrappedException_.setUndefined();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -358,10 +358,11 @@ ExclusiveContext::typeLifoAlloc()
|
||||
} /* namespace js */
|
||||
|
||||
inline void
|
||||
JSContext::setPendingException(js::Value v) {
|
||||
JSContext::setPendingException(js::Value v)
|
||||
{
|
||||
JS_ASSERT(!IsPoisonedValue(v));
|
||||
this->throwing = true;
|
||||
this->exception = v;
|
||||
this->unwrappedException_ = v;
|
||||
js::assertSameCompartment(this, v);
|
||||
}
|
||||
|
||||
@ -388,11 +389,6 @@ js::ExclusiveContext::enterCompartment(JSCompartment *c)
|
||||
enterCompartmentDepth_++;
|
||||
c->enter();
|
||||
setCompartment(c);
|
||||
|
||||
if (JSContext *cx = maybeJSContext()) {
|
||||
if (cx->throwing)
|
||||
cx->wrapPendingException();
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
@ -406,11 +402,6 @@ js::ExclusiveContext::leaveCompartment(JSCompartment *oldCompartment)
|
||||
JSCompartment *startingCompartment = compartment_;
|
||||
setCompartment(oldCompartment);
|
||||
startingCompartment->leave();
|
||||
|
||||
if (JSContext *cx = maybeJSContext()) {
|
||||
if (cx->throwing && oldCompartment)
|
||||
cx->wrapPendingException();
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -730,7 +730,10 @@ js_ReportUncaughtException(JSContext *cx)
|
||||
if (!cx->isExceptionPending())
|
||||
return true;
|
||||
|
||||
RootedValue exn(cx, cx->getPendingException());
|
||||
RootedValue exn(cx);
|
||||
if (!cx->getPendingException(&exn))
|
||||
return false;
|
||||
|
||||
AutoValueVector roots(cx);
|
||||
roots.resize(6);
|
||||
|
||||
|
@ -978,7 +978,8 @@ js::CloseIterator(JSContext *cx, HandleObject obj)
|
||||
bool
|
||||
js::UnwindIteratorForException(JSContext *cx, HandleObject obj)
|
||||
{
|
||||
RootedValue v(cx, cx->getPendingException());
|
||||
RootedValue v(cx);
|
||||
cx->getPendingException(&v);
|
||||
cx->clearPendingException();
|
||||
if (!CloseIterator(cx, obj))
|
||||
return false;
|
||||
@ -1195,7 +1196,12 @@ js_IteratorMore(JSContext *cx, HandleObject iterobj, MutableHandleValue rval)
|
||||
return false;
|
||||
if (!Invoke(cx, ObjectValue(*iterobj), rval, 0, nullptr, rval)) {
|
||||
/* Check for StopIteration. */
|
||||
if (!cx->isExceptionPending() || !JS_IsStopIteration(cx->getPendingException()))
|
||||
if (!cx->isExceptionPending())
|
||||
return false;
|
||||
RootedValue exception(cx);
|
||||
if (!cx->getPendingException(&exception))
|
||||
return false;
|
||||
if (!JS_IsStopIteration(exception))
|
||||
return false;
|
||||
|
||||
cx->clearPendingException();
|
||||
|
@ -149,8 +149,8 @@ ErrorCopier::~ErrorCopier()
|
||||
{
|
||||
JSContext *cx = ac.ref().context()->asJSContext();
|
||||
if (ac.ref().origin() != cx->compartment() && cx->isExceptionPending()) {
|
||||
RootedValue exc(cx, cx->getPendingException());
|
||||
if (exc.isObject() && exc.toObject().is<ErrorObject>()) {
|
||||
RootedValue exc(cx);
|
||||
if (cx->getPendingException(&exc) && exc.isObject() && exc.toObject().is<ErrorObject>()) {
|
||||
cx->clearPendingException();
|
||||
ac.destroy();
|
||||
Rooted<ErrorObject*> errObj(cx, &exc.toObject().as<ErrorObject>());
|
||||
|
@ -783,11 +783,13 @@ Debugger::handleUncaughtExceptionHelper(Maybe<AutoCompartment> &ac,
|
||||
JSContext *cx = ac.ref().context()->asJSContext();
|
||||
if (cx->isExceptionPending()) {
|
||||
if (callHook && uncaughtExceptionHook) {
|
||||
Value fval = ObjectValue(*uncaughtExceptionHook);
|
||||
Value exc = cx->getPendingException();
|
||||
RootedValue rv(cx);
|
||||
RootedValue exc(cx);
|
||||
if (!cx->getPendingException(&exc))
|
||||
return JSTRAP_ERROR;
|
||||
cx->clearPendingException();
|
||||
if (Invoke(cx, ObjectValue(*object), fval, 1, &exc, &rv))
|
||||
RootedValue fval(cx, ObjectValue(*uncaughtExceptionHook));
|
||||
RootedValue rv(cx);
|
||||
if (Invoke(cx, ObjectValue(*object), fval, 1, exc.address(), &rv))
|
||||
return vp ? parseResumptionValue(ac, true, rv, *vp, false) : JSTRAP_CONTINUE;
|
||||
}
|
||||
|
||||
@ -823,7 +825,8 @@ Debugger::resultToCompletion(JSContext *cx, bool ok, const Value &rv,
|
||||
value.set(rv);
|
||||
} else if (cx->isExceptionPending()) {
|
||||
*status = JSTRAP_THROW;
|
||||
value.set(cx->getPendingException());
|
||||
if (!cx->getPendingException(value))
|
||||
*status = JSTRAP_ERROR;
|
||||
cx->clearPendingException();
|
||||
} else {
|
||||
*status = JSTRAP_ERROR;
|
||||
@ -984,7 +987,9 @@ Debugger::fireExceptionUnwind(JSContext *cx, MutableHandleValue vp)
|
||||
JS_ASSERT(hook);
|
||||
JS_ASSERT(hook->isCallable());
|
||||
|
||||
RootedValue exc(cx, cx->getPendingException());
|
||||
RootedValue exc(cx);
|
||||
if (!cx->getPendingException(&exc))
|
||||
return JSTRAP_ERROR;
|
||||
cx->clearPendingException();
|
||||
|
||||
Maybe<AutoCompartment> ac;
|
||||
@ -1231,7 +1236,8 @@ Debugger::onSingleStep(JSContext *cx, MutableHandleValue vp)
|
||||
RootedValue exception(cx, UndefinedValue());
|
||||
bool exceptionPending = cx->isExceptionPending();
|
||||
if (exceptionPending) {
|
||||
exception = cx->getPendingException();
|
||||
if (!cx->getPendingException(&exception))
|
||||
return JSTRAP_ERROR;
|
||||
cx->clearPendingException();
|
||||
}
|
||||
|
||||
|
@ -993,6 +993,7 @@ HandleError(JSContext *cx, FrameRegs ®s)
|
||||
}
|
||||
}
|
||||
|
||||
RootedValue exception(cx);
|
||||
for (TryNoteIter tni(cx, regs); !tni.done(); ++tni) {
|
||||
JSTryNote *tn = *tni;
|
||||
|
||||
@ -1009,14 +1010,10 @@ HandleError(JSContext *cx, FrameRegs ®s)
|
||||
switch (tn->kind) {
|
||||
case JSTRY_CATCH:
|
||||
/* Catch cannot intercept the closing of a generator. */
|
||||
if (JS_UNLIKELY(cx->getPendingException().isMagic(JS_GENERATOR_CLOSING)))
|
||||
if (!cx->getPendingException(&exception))
|
||||
return ErrorReturnContinuation;
|
||||
if (exception.isMagic(JS_GENERATOR_CLOSING))
|
||||
break;
|
||||
|
||||
/*
|
||||
* Don't clear exceptions to save cx->exception from GC
|
||||
* until it is pushed to the stack via [exception] in the
|
||||
* catch block.
|
||||
*/
|
||||
return CatchContinuation;
|
||||
|
||||
case JSTRY_FINALLY:
|
||||
@ -1042,11 +1039,16 @@ HandleError(JSContext *cx, FrameRegs ®s)
|
||||
* Propagate the exception or error to the caller unless the exception
|
||||
* is an asynchronous return from a generator.
|
||||
*/
|
||||
if (JS_UNLIKELY(cx->isExceptionPending() &&
|
||||
cx->getPendingException().isMagic(JS_GENERATOR_CLOSING))) {
|
||||
cx->clearPendingException();
|
||||
ok = true;
|
||||
regs.fp()->clearReturnValue();
|
||||
if (cx->isExceptionPending()) {
|
||||
RootedValue exception(cx);
|
||||
if (!cx->getPendingException(&exception))
|
||||
return ErrorReturnContinuation;
|
||||
|
||||
if (exception.isMagic(JS_GENERATOR_CLOSING)) {
|
||||
cx->clearPendingException();
|
||||
ok = true;
|
||||
regs.fp()->clearReturnValue();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
UnwindForUncatchableException(cx, regs);
|
||||
@ -3433,8 +3435,13 @@ DEFAULT()
|
||||
* Push (true, exception) pair for finally to indicate that [retsub]
|
||||
* should rethrow the exception.
|
||||
*/
|
||||
RootedValue &exception = rootValue0;
|
||||
if (!cx->getPendingException(&exception)) {
|
||||
interpReturnOK = false;
|
||||
goto return_continuation;
|
||||
}
|
||||
PUSH_BOOLEAN(true);
|
||||
PUSH_COPY(cx->getPendingException());
|
||||
PUSH_COPY(exception);
|
||||
cx->clearPendingException();
|
||||
ADVANCE_AND_DISPATCH(0);
|
||||
}
|
||||
@ -3683,9 +3690,9 @@ js::GetAndClearException(JSContext *cx, MutableHandleValue res)
|
||||
if (cx->runtime()->interrupt && !js_HandleExecutionInterrupt(cx))
|
||||
return false;
|
||||
|
||||
res.set(cx->getPendingException());
|
||||
bool status = cx->getPendingException(res);
|
||||
cx->clearPendingException();
|
||||
return true;
|
||||
return status;
|
||||
}
|
||||
|
||||
template <bool strict>
|
||||
|
@ -632,8 +632,10 @@ GetPropertyDesc(JSContext *cx, JSObject *obj_, HandleShape shape, JSPropertyDesc
|
||||
|
||||
bool wasThrowing = cx->isExceptionPending();
|
||||
RootedValue lastException(cx, UndefinedValue());
|
||||
if (wasThrowing)
|
||||
lastException = cx->getPendingException();
|
||||
if (wasThrowing) {
|
||||
if (!cx->getPendingException(&lastException))
|
||||
return false;
|
||||
}
|
||||
cx->clearPendingException();
|
||||
|
||||
Rooted<jsid> id(cx, shape->propid());
|
||||
@ -644,7 +646,9 @@ GetPropertyDesc(JSContext *cx, JSObject *obj_, HandleShape shape, JSPropertyDesc
|
||||
pd->value = JSVAL_VOID;
|
||||
} else {
|
||||
pd->flags = JSPD_EXCEPTION;
|
||||
pd->value = cx->getPendingException();
|
||||
if (!cx->getPendingException(&value))
|
||||
return false;
|
||||
pd->value = value;
|
||||
}
|
||||
} else {
|
||||
pd->flags = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user