Merge backout.

This commit is contained in:
Robert Sayre 2011-01-06 21:39:31 -05:00
commit e477e5125b
18 changed files with 156 additions and 170 deletions

View File

@ -1130,7 +1130,7 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
JS_SetFrameReturnValue(cx, fp, rval); JS_SetFrameReturnValue(cx, fp, rval);
return JS_TRUE; return JS_TRUE;
case JSTRAP_ERROR: case JSTRAP_ERROR:
JS_ClearPendingException(cx); cx->throwing = JS_FALSE;
return JS_FALSE; return JS_FALSE;
case JSTRAP_THROW: case JSTRAP_THROW:
JS_SetPendingException(cx, rval); JS_SetPendingException(cx, rval);

View File

@ -5173,8 +5173,7 @@ JS_IsRunning(JSContext *cx)
VOUCH_DOES_NOT_REQUIRE_STACK(); VOUCH_DOES_NOT_REQUIRE_STACK();
#ifdef JS_TRACER #ifdef JS_TRACER
JS_ASSERT_IF(cx->compartment && JS_ASSERT_IF(JS_TRACE_MONITOR(cx).tracecx == cx, cx->hasfp());
JS_TRACE_MONITOR(cx).tracecx == cx, cx->hasfp());
#endif #endif
JSStackFrame *fp = cx->maybefp(); JSStackFrame *fp = cx->maybefp();
while (fp && fp->isDummyFrame()) while (fp && fp->isDummyFrame())
@ -5847,17 +5846,16 @@ JS_GetLocaleCallbacks(JSContext *cx)
JS_PUBLIC_API(JSBool) JS_PUBLIC_API(JSBool)
JS_IsExceptionPending(JSContext *cx) JS_IsExceptionPending(JSContext *cx)
{ {
return (JSBool) cx->isExceptionPending(); return (JSBool) cx->throwing;
} }
JS_PUBLIC_API(JSBool) JS_PUBLIC_API(JSBool)
JS_GetPendingException(JSContext *cx, jsval *vp) JS_GetPendingException(JSContext *cx, jsval *vp)
{ {
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
if (!cx->isExceptionPending()) if (!cx->throwing)
return JS_FALSE; return JS_FALSE;
Valueify(*vp) = cx->getPendingException(); Valueify(*vp) = cx->exception;
assertSameCompartment(cx, *vp);
return JS_TRUE; return JS_TRUE;
} }
@ -5866,13 +5864,14 @@ JS_SetPendingException(JSContext *cx, jsval v)
{ {
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
assertSameCompartment(cx, v); assertSameCompartment(cx, v);
cx->setPendingException(Valueify(v)); SetPendingException(cx, Valueify(v));
} }
JS_PUBLIC_API(void) JS_PUBLIC_API(void)
JS_ClearPendingException(JSContext *cx) JS_ClearPendingException(JSContext *cx)
{ {
cx->clearPendingException(); cx->throwing = JS_FALSE;
cx->exception.setUndefined();
} }
JS_PUBLIC_API(JSBool) JS_PUBLIC_API(JSBool)

View File

@ -1357,7 +1357,7 @@ js_ReportOutOfMemory(JSContext *cx)
* exception if any now so the hooks can replace the out-of-memory error * exception if any now so the hooks can replace the out-of-memory error
* by a script-catchable exception. * by a script-catchable exception.
*/ */
cx->clearPendingException(); cx->throwing = JS_FALSE;
if (onError) { if (onError) {
JSDebugErrorHook hook = cx->debugHooks->debugErrorHook; JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
if (hook && if (hook &&
@ -2005,37 +2005,27 @@ JSContext::resetCompartment()
scopeobj = &fp()->scopeChain(); scopeobj = &fp()->scopeChain();
} else { } else {
scopeobj = globalObject; scopeobj = globalObject;
if (!scopeobj) if (!scopeobj) {
goto error; compartment = runtime->defaultCompartment;
return;
}
/* /*
* Innerize. Assert, but check anyway, that this succeeds. (It * Innerize. Assert, but check anyway, that this succeeds. (It
* can only fail due to bugs in the engine or embedding.) * can only fail due to bugs in the engine or embedding.)
*/ */
OBJ_TO_INNER_OBJECT(this, scopeobj); OBJ_TO_INNER_OBJECT(this, scopeobj);
if (!scopeobj) if (!scopeobj) {
goto error; /*
* Bug. Return NULL, not defaultCompartment, to crash rather
* than open a security hole.
*/
JS_ASSERT(0);
compartment = NULL;
return;
}
} }
compartment = scopeobj->getCompartment();
compartment = scopeobj->compartment();
/*
* If wrapException fails, it overrides this->exception and
* reports OOM. The upshot is that we silently turn the exception
* into an uncatchable OOM error. A bit surprising, but the
* caller is just going to return false either way.
*/
if (isExceptionPending())
(void) compartment->wrapException(this);
return;
error:
/*
* If we try to use the context without a selected compartment,
* we will crash.
*/
compartment = NULL;
} }
void void
@ -2299,4 +2289,11 @@ LeaveTrace(JSContext *cx)
#endif #endif
} }
void
SetPendingException(JSContext *cx, const Value &v)
{
cx->throwing = JS_TRUE;
cx->exception = v;
}
} /* namespace js */ } /* namespace js */

View File

@ -888,7 +888,7 @@ private:
* executing. cx must be a context on the current thread. * executing. cx must be a context on the current thread.
*/ */
#ifdef JS_TRACER #ifdef JS_TRACER
# define JS_ON_TRACE(cx) (cx->compartment && JS_TRACE_MONITOR(cx).ontrace()) # define JS_ON_TRACE(cx) (JS_TRACE_MONITOR(cx).ontrace())
#else #else
# define JS_ON_TRACE(cx) false # define JS_ON_TRACE(cx) false
#endif #endif
@ -1700,10 +1700,6 @@ struct JSContext
JSVersion versionOverride; /* supercedes defaultVersion when valid */ JSVersion versionOverride; /* supercedes defaultVersion when valid */
bool hasVersionOverride; bool hasVersionOverride;
/* Exception state -- the exception member is a GC root by definition. */
JSBool throwing; /* is there a pending exception? */
js::Value exception; /* most-recently-thrown exception */
public: public:
/* Per-context options. */ /* Per-context options. */
uint32 options; /* see jsapi.h for JSOPTION_* */ uint32 options; /* see jsapi.h for JSOPTION_* */
@ -1725,6 +1721,10 @@ struct JSContext
*/ */
JSPackedBool generatingError; JSPackedBool generatingError;
/* Exception state -- the exception member is a GC root by definition. */
JSBool throwing; /* is there a pending exception? */
js::Value exception; /* most-recently-thrown exception */
/* Limit pointer for checking native stack consumption during recursion. */ /* Limit pointer for checking native stack consumption during recursion. */
jsuword stackLimit; jsuword stackLimit;
@ -2168,22 +2168,6 @@ struct JSContext
void assertValidStackDepth(uintN /*depth*/) {} void assertValidStackDepth(uintN /*depth*/) {}
#endif #endif
bool isExceptionPending() {
return throwing;
}
js::Value getPendingException() {
JS_ASSERT(throwing);
return exception;
}
void setPendingException(js::Value v);
void clearPendingException() {
this->throwing = false;
this->exception.setUndefined();
}
private: private:
/* /*
* The allocation code calls the function to indicate either OOM failure * The allocation code calls the function to indicate either OOM failure
@ -3163,6 +3147,9 @@ js_CurrentPCIsInImacro(JSContext *cx);
namespace js { namespace js {
extern void
SetPendingException(JSContext *cx, const Value &v);
class RegExpStatics; class RegExpStatics;
extern JS_FORCES_STACK JS_FRIEND_API(void) extern JS_FORCES_STACK JS_FRIEND_API(void)

View File

@ -686,13 +686,13 @@ JS_ALWAYS_INLINE bool
CallJSNative(JSContext *cx, js::Native native, uintN argc, js::Value *vp) CallJSNative(JSContext *cx, js::Native native, uintN argc, js::Value *vp)
{ {
#ifdef DEBUG #ifdef DEBUG
JSBool alreadyThrowing = cx->isExceptionPending(); JSBool alreadyThrowing = cx->throwing;
#endif #endif
assertSameCompartment(cx, ValueArray(vp, argc + 2)); assertSameCompartment(cx, ValueArray(vp, argc + 2));
JSBool ok = native(cx, argc, vp); JSBool ok = native(cx, argc, vp);
if (ok) { if (ok) {
assertSameCompartment(cx, vp[0]); assertSameCompartment(cx, vp[0]);
JS_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending()); JS_ASSERT_IF(!alreadyThrowing, !cx->throwing);
} }
return ok; return ok;
} }
@ -800,11 +800,4 @@ CanLeaveTrace(JSContext *cx)
} /* namespace js */ } /* namespace js */
inline void
JSContext::setPendingException(js::Value v) {
this->throwing = true;
this->exception = v;
assertSameCompartment(this, v);
}
#endif /* jscntxtinlines_h___ */ #endif /* jscntxtinlines_h___ */

View File

@ -358,11 +358,14 @@ JSCompartment::wrapException(JSContext *cx)
{ {
JS_ASSERT(cx->compartment == this); JS_ASSERT(cx->compartment == this);
if (cx->isExceptionPending()) { if (cx->throwing) {
Value v = cx->getPendingException(); AutoValueRooter tvr(cx, cx->exception);
cx->clearPendingException(); cx->throwing = false;
if (wrap(cx, &v)) cx->exception.setNull();
cx->setPendingException(v); if (wrap(cx, tvr.addr())) {
cx->throwing = true;
cx->exception = tvr.value();
}
return false; return false;
} }
return true; return true;

View File

@ -377,7 +377,6 @@ class PreserveCompartment {
public: public:
PreserveCompartment(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) : cx(cx) { PreserveCompartment(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) : cx(cx) {
JS_GUARD_OBJECT_NOTIFIER_INIT; JS_GUARD_OBJECT_NOTIFIER_INIT;
JS_ASSERT(!cx->isExceptionPending());
oldCompartment = cx->compartment; oldCompartment = cx->compartment;
} }

View File

@ -1545,26 +1545,25 @@ JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
Shape *shape = (Shape *) sprop; Shape *shape = (Shape *) sprop;
pd->id = IdToJsval(shape->id); pd->id = IdToJsval(shape->id);
JSBool wasThrowing = cx->isExceptionPending(); JSBool wasThrowing = cx->throwing;
Value lastException = UndefinedValue(); AutoValueRooter lastException(cx, cx->exception);
if (wasThrowing) cx->throwing = JS_FALSE;
lastException = cx->getPendingException();
cx->clearPendingException();
if (!js_GetProperty(cx, obj, shape->id, Valueify(&pd->value))) { if (!js_GetProperty(cx, obj, shape->id, Valueify(&pd->value))) {
if (!cx->isExceptionPending()) { if (!cx->throwing) {
pd->flags = JSPD_ERROR; pd->flags = JSPD_ERROR;
pd->value = JSVAL_VOID; pd->value = JSVAL_VOID;
} else { } else {
pd->flags = JSPD_EXCEPTION; pd->flags = JSPD_EXCEPTION;
pd->value = Jsvalify(cx->getPendingException()); pd->value = Jsvalify(cx->exception);
} }
} else { } else {
pd->flags = 0; pd->flags = 0;
} }
cx->throwing = wasThrowing;
if (wasThrowing) if (wasThrowing)
cx->setPendingException(lastException); cx->exception = lastException.value();
pd->flags |= (shape->enumerable() ? JSPD_ENUMERATE : 0) pd->flags |= (shape->enumerable() ? JSPD_ENUMERATE : 0)
| (!shape->writable() ? JSPD_READONLY : 0) | (!shape->writable() ? JSPD_READONLY : 0)

View File

@ -1582,8 +1582,12 @@ MarkContext(JSTracer *trc, JSContext *acx)
/* Mark other roots-by-definition in acx. */ /* Mark other roots-by-definition in acx. */
if (acx->globalObject && !JS_HAS_OPTION(acx, JSOPTION_UNROOTED_GLOBAL)) if (acx->globalObject && !JS_HAS_OPTION(acx, JSOPTION_UNROOTED_GLOBAL))
MarkObject(trc, *acx->globalObject, "global object"); MarkObject(trc, *acx->globalObject, "global object");
if (acx->isExceptionPending()) if (acx->throwing) {
MarkValue(trc, acx->getPendingException(), "exception"); MarkValue(trc, acx->exception, "exception");
} else {
/* Avoid keeping GC-ed junk stored in JSContext.exception. */
acx->exception.setNull();
}
for (js::AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down) for (js::AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down)
gcr->trace(trc); gcr->trace(trc);

View File

@ -2429,7 +2429,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
argv = regs.fp->maybeFormalArgs(); \ argv = regs.fp->maybeFormalArgs(); \
atoms = FrameAtomBase(cx, regs.fp); \ atoms = FrameAtomBase(cx, regs.fp); \
JS_ASSERT(cx->regs == &regs); \ JS_ASSERT(cx->regs == &regs); \
if (cx->isExceptionPending()) \ if (cx->throwing) \
goto error; \ goto error; \
JS_END_MACRO JS_END_MACRO
@ -2445,7 +2445,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
CLEAR_LEAVE_ON_TRACE_POINT(); \ CLEAR_LEAVE_ON_TRACE_POINT(); \
} \ } \
RESTORE_INTERP_VARS(); \ RESTORE_INTERP_VARS(); \
JS_ASSERT_IF(cx->isExceptionPending(), r == MONITOR_ERROR); \ JS_ASSERT_IF(cx->throwing, r == MONITOR_ERROR); \
if (r == MONITOR_ERROR) \ if (r == MONITOR_ERROR) \
goto error; \ goto error; \
} \ } \
@ -2571,9 +2571,9 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
/* /*
* To support generator_throw and to catch ignored exceptions, * To support generator_throw and to catch ignored exceptions,
* fail if cx->isExceptionPending() is true. * fail if cx->throwing is set.
*/ */
if (cx->isExceptionPending()) if (cx->throwing)
goto error; goto error;
} }
#endif #endif
@ -2687,7 +2687,8 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
interpReturnOK = JS_TRUE; interpReturnOK = JS_TRUE;
goto forced_return; goto forced_return;
case JSTRAP_THROW: case JSTRAP_THROW:
cx->setPendingException(rval); cx->throwing = JS_TRUE;
cx->exception = rval;
goto error; goto error;
default:; default:;
} }
@ -2715,7 +2716,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
if (TraceRecorder* tr = TRACE_RECORDER(cx)) { if (TraceRecorder* tr = TRACE_RECORDER(cx)) {
JS_ASSERT(!TRACE_PROFILER(cx)); JS_ASSERT(!TRACE_PROFILER(cx));
AbortableRecordingStatus status = tr->monitorRecording(op); AbortableRecordingStatus status = tr->monitorRecording(op);
JS_ASSERT_IF(cx->isExceptionPending(), status == ARECORD_ERROR); JS_ASSERT_IF(cx->throwing, status == ARECORD_ERROR);
if (interpMode != JSINTERP_NORMAL) { if (interpMode != JSINTERP_NORMAL) {
JS_ASSERT(interpMode == JSINTERP_RECORD || JSINTERP_SAFEPOINT); JS_ASSERT(interpMode == JSINTERP_RECORD || JSINTERP_SAFEPOINT);
@ -5203,7 +5204,8 @@ BEGIN_CASE(JSOP_TRAP)
interpReturnOK = JS_TRUE; interpReturnOK = JS_TRUE;
goto forced_return; goto forced_return;
case JSTRAP_THROW: case JSTRAP_THROW:
cx->setPendingException(rval); cx->throwing = JS_TRUE;
cx->exception = rval;
goto error; goto error;
default: default:
break; break;
@ -6229,7 +6231,8 @@ BEGIN_CASE(JSOP_RETSUB)
* be necessary, but it seems clearer. And it points out a FIXME: * be necessary, but it seems clearer. And it points out a FIXME:
* 350509, due to Igor Bukanov. * 350509, due to Igor Bukanov.
*/ */
cx->setPendingException(rval); cx->throwing = JS_TRUE;
cx->exception = rval;
goto error; goto error;
} }
JS_ASSERT(rval.isInt32()); JS_ASSERT(rval.isInt32());
@ -6239,8 +6242,9 @@ END_VARLEN_CASE
} }
BEGIN_CASE(JSOP_EXCEPTION) BEGIN_CASE(JSOP_EXCEPTION)
PUSH_COPY(cx->getPendingException()); JS_ASSERT(cx->throwing);
cx->clearPendingException(); PUSH_COPY(cx->exception);
cx->throwing = JS_FALSE;
#if defined(JS_TRACER) && defined(JS_METHODJIT) #if defined(JS_TRACER) && defined(JS_METHODJIT)
if (interpMode == JSINTERP_PROFILE) { if (interpMode == JSINTERP_PROFILE) {
leaveOnSafePoint = true; leaveOnSafePoint = true;
@ -6255,24 +6259,19 @@ BEGIN_CASE(JSOP_FINALLY)
END_CASE(JSOP_FINALLY) END_CASE(JSOP_FINALLY)
BEGIN_CASE(JSOP_THROWING) BEGIN_CASE(JSOP_THROWING)
{ JS_ASSERT(!cx->throwing);
JS_ASSERT(!cx->isExceptionPending()); cx->throwing = JS_TRUE;
Value v; POP_COPY_TO(cx->exception);
POP_COPY_TO(v);
cx->setPendingException(v);
}
END_CASE(JSOP_THROWING) END_CASE(JSOP_THROWING)
BEGIN_CASE(JSOP_THROW) BEGIN_CASE(JSOP_THROW)
{ JS_ASSERT(!cx->throwing);
JS_ASSERT(!cx->isExceptionPending());
CHECK_BRANCH(); CHECK_BRANCH();
Value v; cx->throwing = JS_TRUE;
POP_COPY_TO(v); POP_COPY_TO(cx->exception);
cx->setPendingException(v);
/* let the code at error try to catch the exception. */ /* let the code at error try to catch the exception. */
goto error; goto error;
}
BEGIN_CASE(JSOP_SETLOCALPOP) BEGIN_CASE(JSOP_SETLOCALPOP)
{ {
/* /*
@ -6348,7 +6347,8 @@ BEGIN_CASE(JSOP_DEBUGGER)
interpReturnOK = JS_TRUE; interpReturnOK = JS_TRUE;
goto forced_return; goto forced_return;
case JSTRAP_THROW: case JSTRAP_THROW:
cx->setPendingException(rval); cx->throwing = JS_TRUE;
cx->exception = rval;
goto error; goto error;
default:; default:;
} }
@ -6720,7 +6720,7 @@ END_CASE(JSOP_LEAVEBLOCK)
#if JS_HAS_GENERATORS #if JS_HAS_GENERATORS
BEGIN_CASE(JSOP_GENERATOR) BEGIN_CASE(JSOP_GENERATOR)
{ {
JS_ASSERT(!cx->isExceptionPending()); JS_ASSERT(!cx->throwing);
regs.pc += JSOP_GENERATOR_LENGTH; regs.pc += JSOP_GENERATOR_LENGTH;
JSObject *obj = js_NewGenerator(cx); JSObject *obj = js_NewGenerator(cx);
if (!obj) if (!obj)
@ -6734,7 +6734,7 @@ BEGIN_CASE(JSOP_GENERATOR)
} }
BEGIN_CASE(JSOP_YIELD) BEGIN_CASE(JSOP_YIELD)
JS_ASSERT(!cx->isExceptionPending()); JS_ASSERT(!cx->throwing);
JS_ASSERT(regs.fp->isFunctionFrame() && !regs.fp->isEvalFrame()); JS_ASSERT(regs.fp->isFunctionFrame() && !regs.fp->isEvalFrame());
if (cx->generatorFor(regs.fp)->state == JSGEN_CLOSING) { if (cx->generatorFor(regs.fp)->state == JSGEN_CLOSING) {
js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD,
@ -6830,7 +6830,7 @@ END_CASE(JSOP_ARRAYPUSH)
error: error:
JS_ASSERT(cx->regs == &regs); JS_ASSERT(cx->regs == &regs);
#ifdef JS_TRACER #ifdef JS_TRACER
if (regs.fp->hasImacropc() && cx->isExceptionPending()) { if (regs.fp->hasImacropc() && cx->throwing) {
// Handle exceptions as if they came from the imacro-calling pc. // Handle exceptions as if they came from the imacro-calling pc.
regs.pc = regs.fp->imacropc(); regs.pc = regs.fp->imacropc();
regs.fp->clearImacropc(); regs.fp->clearImacropc();
@ -6854,7 +6854,7 @@ END_CASE(JSOP_ARRAYPUSH)
# endif # endif
#endif #endif
if (!cx->isExceptionPending()) { if (!cx->throwing) {
/* This is an error, not a catchable exception, quit the frame ASAP. */ /* This is an error, not a catchable exception, quit the frame ASAP. */
interpReturnOK = JS_FALSE; interpReturnOK = JS_FALSE;
} else { } else {
@ -6872,15 +6872,15 @@ END_CASE(JSOP_ARRAYPUSH)
switch (handler(cx, script, regs.pc, Jsvalify(&rval), switch (handler(cx, script, regs.pc, Jsvalify(&rval),
cx->debugHooks->throwHookData)) { cx->debugHooks->throwHookData)) {
case JSTRAP_ERROR: case JSTRAP_ERROR:
cx->clearPendingException(); cx->throwing = JS_FALSE;
goto error; goto error;
case JSTRAP_RETURN: case JSTRAP_RETURN:
cx->clearPendingException(); cx->throwing = JS_FALSE;
regs.fp->setReturnValue(rval); regs.fp->setReturnValue(rval);
interpReturnOK = JS_TRUE; interpReturnOK = JS_TRUE;
goto forced_return; goto forced_return;
case JSTRAP_THROW: case JSTRAP_THROW:
cx->setPendingException(rval); cx->exception = rval;
case JSTRAP_CONTINUE: case JSTRAP_CONTINUE:
default:; default:;
} }
@ -6943,12 +6943,12 @@ END_CASE(JSOP_ARRAYPUSH)
case JSTRY_CATCH: case JSTRY_CATCH:
#if JS_HAS_GENERATORS #if JS_HAS_GENERATORS
/* Catch cannot intercept the closing of a generator. */ /* Catch cannot intercept the closing of a generator. */
if (JS_UNLIKELY(cx->getPendingException().isMagic(JS_GENERATOR_CLOSING))) if (JS_UNLIKELY(cx->exception.isMagic(JS_GENERATOR_CLOSING)))
break; break;
#endif #endif
/* /*
* Don't clear exceptions to save cx->exception from GC * Don't clear cx->throwing to save cx->exception from GC
* until it is pushed to the stack via [exception] in the * until it is pushed to the stack via [exception] in the
* catch block. * catch block.
*/ */
@ -6961,21 +6961,22 @@ END_CASE(JSOP_ARRAYPUSH)
* [retsub] should rethrow the exception. * [retsub] should rethrow the exception.
*/ */
PUSH_BOOLEAN(true); PUSH_BOOLEAN(true);
PUSH_COPY(cx->getPendingException()); PUSH_COPY(cx->exception);
cx->clearPendingException(); cx->throwing = JS_FALSE;
len = 0; len = 0;
DO_NEXT_OP(len); DO_NEXT_OP(len);
case JSTRY_ITER: { case JSTRY_ITER: {
/* This is similar to JSOP_ENDITER in the interpreter loop. */ /* This is similar to JSOP_ENDITER in the interpreter loop. */
JS_ASSERT(js_GetOpcode(cx, regs.fp->script(), regs.pc) == JSOP_ENDITER); JS_ASSERT(js_GetOpcode(cx, regs.fp->script(), regs.pc) == JSOP_ENDITER);
Value v = cx->getPendingException(); AutoValueRooter tvr(cx, cx->exception);
cx->clearPendingException(); cx->throwing = false;
ok = js_CloseIterator(cx, &regs.sp[-1].toObject()); ok = js_CloseIterator(cx, &regs.sp[-1].toObject());
regs.sp -= 1; regs.sp -= 1;
if (!ok) if (!ok)
goto error; goto error;
cx->setPendingException(v); cx->throwing = true;
cx->exception = tvr.value();
} }
} }
} while (++tn != tnlimit); } while (++tn != tnlimit);
@ -6987,9 +6988,9 @@ END_CASE(JSOP_ARRAYPUSH)
*/ */
interpReturnOK = JS_FALSE; interpReturnOK = JS_FALSE;
#if JS_HAS_GENERATORS #if JS_HAS_GENERATORS
if (JS_UNLIKELY(cx->isExceptionPending() && if (JS_UNLIKELY(cx->throwing &&
cx->getPendingException().isMagic(JS_GENERATOR_CLOSING))) { cx->exception.isMagic(JS_GENERATOR_CLOSING))) {
cx->clearPendingException(); cx->throwing = JS_FALSE;
interpReturnOK = JS_TRUE; interpReturnOK = JS_TRUE;
regs.fp->clearReturnValue(); regs.fp->clearReturnValue();
} }
@ -7004,7 +7005,7 @@ END_CASE(JSOP_ARRAYPUSH)
* When a trap handler returns JSTRAP_RETURN, we jump here with * When a trap handler returns JSTRAP_RETURN, we jump here with
* interpReturnOK set to true bypassing any finally blocks. * interpReturnOK set to true bypassing any finally blocks.
*/ */
interpReturnOK &= js_UnwindScope(cx, 0, interpReturnOK || cx->isExceptionPending()); interpReturnOK &= js_UnwindScope(cx, 0, interpReturnOK || cx->throwing);
JS_ASSERT(regs.sp == regs.fp->base()); JS_ASSERT(regs.sp == regs.fp->base());
#ifdef DEBUG #ifdef DEBUG

View File

@ -767,7 +767,7 @@ js_ThrowStopIteration(JSContext *cx)
JS_ASSERT(!JS_IsExceptionPending(cx)); JS_ASSERT(!JS_IsExceptionPending(cx));
if (js_FindClassObject(cx, NULL, JSProto_StopIteration, &v)) if (js_FindClassObject(cx, NULL, JSProto_StopIteration, &v))
cx->setPendingException(v); SetPendingException(cx, v);
return JS_FALSE; return JS_FALSE;
} }
@ -1017,10 +1017,12 @@ js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval)
return false; return false;
if (!ExternalInvoke(cx, iterobj, *rval, 0, NULL, rval)) { if (!ExternalInvoke(cx, iterobj, *rval, 0, NULL, rval)) {
/* Check for StopIteration. */ /* Check for StopIteration. */
if (!cx->isExceptionPending() || !js_ValueIsStopIteration(cx->getPendingException())) if (!cx->throwing || !js_ValueIsStopIteration(cx->exception))
return false; return false;
cx->clearPendingException(); /* Inline JS_ClearPendingException(cx). */
cx->throwing = JS_FALSE;
cx->exception.setUndefined();
cx->iterValue.setMagic(JS_NO_ITER_VALUE); cx->iterValue.setMagic(JS_NO_ITER_VALUE);
rval->setBoolean(false); rval->setBoolean(false);
return true; return true;
@ -1284,13 +1286,13 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
break; break;
case JSGENOP_THROW: case JSGENOP_THROW:
cx->setPendingException(arg); SetPendingException(cx, arg);
gen->state = JSGEN_RUNNING; gen->state = JSGEN_RUNNING;
break; break;
default: default:
JS_ASSERT(op == JSGENOP_CLOSE); JS_ASSERT(op == JSGENOP_CLOSE);
cx->setPendingException(MagicValue(JS_GENERATOR_CLOSING)); SetPendingException(cx, MagicValue(JS_GENERATOR_CLOSING));
gen->state = JSGEN_CLOSING; gen->state = JSGEN_CLOSING;
break; break;
} }
@ -1348,7 +1350,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
if (gen->floatingFrame()->isYielding()) { if (gen->floatingFrame()->isYielding()) {
/* Yield cannot fail, throw or be called on closing. */ /* Yield cannot fail, throw or be called on closing. */
JS_ASSERT(ok); JS_ASSERT(ok);
JS_ASSERT(!cx->isExceptionPending()); JS_ASSERT(!cx->throwing);
JS_ASSERT(gen->state == JSGEN_RUNNING); JS_ASSERT(gen->state == JSGEN_RUNNING);
JS_ASSERT(op != JSGENOP_CLOSE); JS_ASSERT(op != JSGENOP_CLOSE);
genfp->clearYielding(); genfp->clearYielding();
@ -1434,7 +1436,7 @@ generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc)
case JSGENOP_SEND: case JSGENOP_SEND:
return js_ThrowStopIteration(cx); return js_ThrowStopIteration(cx);
case JSGENOP_THROW: case JSGENOP_THROW:
cx->setPendingException(argc >= 1 ? vp[2] : UndefinedValue()); SetPendingException(cx, argc >= 1 ? vp[2] : UndefinedValue());
return JS_FALSE; return JS_FALSE;
default: default:
JS_ASSERT(op == JSGENOP_CLOSE); JS_ASSERT(op == JSGENOP_CLOSE);

View File

@ -1667,7 +1667,7 @@ class RegExpGuard
* @param checkMetaChars Look for regexp metachars in the pattern string. * @param checkMetaChars Look for regexp metachars in the pattern string.
* @return Whether flat matching could be used. * @return Whether flat matching could be used.
* *
* N.B. tryFlatMatch returns NULL on OOM, so the caller must check cx->isExceptionPending(). * N.B. tryFlatMatch returns NULL on OOM, so the caller must check cx->throwing.
*/ */
const FlatMatch * const FlatMatch *
tryFlatMatch(JSContext *cx, JSString *textstr, uintN optarg, uintN argc, tryFlatMatch(JSContext *cx, JSString *textstr, uintN optarg, uintN argc,
@ -1856,7 +1856,7 @@ str_match(JSContext *cx, uintN argc, Value *vp)
return false; return false;
if (const FlatMatch *fm = g.tryFlatMatch(cx, str, 1, argc)) if (const FlatMatch *fm = g.tryFlatMatch(cx, str, 1, argc))
return BuildFlatMatchArray(cx, str, *fm, vp); return BuildFlatMatchArray(cx, str, *fm, vp);
if (cx->isExceptionPending()) /* from tryFlatMatch */ if (cx->throwing) /* from tryFlatMatch */
return false; return false;
const RegExpPair *rep = g.normalizeRegExp(false, 1, argc, vp); const RegExpPair *rep = g.normalizeRegExp(false, 1, argc, vp);
@ -1888,7 +1888,7 @@ str_search(JSContext *cx, uintN argc, Value *vp)
vp->setInt32(fm->match()); vp->setInt32(fm->match());
return true; return true;
} }
if (cx->isExceptionPending()) /* from tryFlatMatch */ if (cx->throwing) /* from tryFlatMatch */
return false; return false;
const RegExpPair *rep = g.normalizeRegExp(false, 1, argc, vp); const RegExpPair *rep = g.normalizeRegExp(false, 1, argc, vp);
if (!rep) if (!rep)
@ -2501,7 +2501,7 @@ js::str_replace(JSContext *cx, uintN argc, Value *vp)
const FlatMatch *fm = rdata.g.tryFlatMatch(cx, rdata.str, optarg, argc, false); const FlatMatch *fm = rdata.g.tryFlatMatch(cx, rdata.str, optarg, argc, false);
if (!fm) { if (!fm) {
if (cx->isExceptionPending()) /* oom in RopeMatch in tryFlatMatch */ if (cx->throwing) /* oom in RopeMatch in tryFlatMatch */
return false; return false;
JS_ASSERT_IF(!rdata.g.hasRegExpPair(), argc > optarg); JS_ASSERT_IF(!rdata.g.hasRegExpPair(), argc > optarg);
return str_replace_regexp(cx, argc, vp, rdata); return str_replace_regexp(cx, argc, vp, rdata);

View File

@ -6568,7 +6568,7 @@ ExecuteTree(JSContext* cx, TreeFragment* f, uintN& inlineCallCount,
*lrp = state.innermost; *lrp = state.innermost;
bool ok = !(state.builtinStatus & BUILTIN_ERROR); bool ok = !(state.builtinStatus & BUILTIN_ERROR);
JS_ASSERT_IF(cx->isExceptionPending(), !ok); JS_ASSERT_IF(cx->throwing, !ok);
size_t iters = tm->iterationCounter; size_t iters = tm->iterationCounter;
@ -16592,7 +16592,7 @@ RecordTracePoint(JSContext* cx, uintN& inlineCallCount, bool* blacklist, bool ex
if (!Interpret(cx, fp, inlineCallCount, JSINTERP_RECORD)) if (!Interpret(cx, fp, inlineCallCount, JSINTERP_RECORD))
return TPA_Error; return TPA_Error;
JS_ASSERT(!cx->isExceptionPending()); JS_ASSERT(!cx->throwing);
return TPA_RanStuff; return TPA_RanStuff;
} }
@ -16759,7 +16759,7 @@ MonitorTracePoint(JSContext *cx, uintN& inlineCallCount, bool* blacklist,
if (!Interpret(cx, cx->fp(), inlineCallCount, JSINTERP_PROFILE)) if (!Interpret(cx, cx->fp(), inlineCallCount, JSINTERP_PROFILE))
return TPA_Error; return TPA_Error;
JS_ASSERT(!cx->isExceptionPending()); JS_ASSERT(!cx->throwing);
return TPA_RanStuff; return TPA_RanStuff;
} }

View File

@ -358,8 +358,7 @@ AutoCompartment::enter()
JSObject *scopeChain = target->getGlobal(); JSObject *scopeChain = target->getGlobal();
JS_ASSERT(scopeChain->isNative()); JS_ASSERT(scopeChain->isNative());
frame.construct(); frame.construct();
if (!context->stack().pushDummyFrame(context, *scopeChain, &frame.ref()) || if (!context->stack().pushDummyFrame(context, *scopeChain, &frame.ref())) {
!destination->wrapException(context)) {
frame.destroy(); frame.destroy();
context->compartment = origin; context->compartment = origin;
return false; return false;

View File

@ -1720,9 +1720,16 @@ mjit::Compiler::generateMethod()
END_CASE(JSOP_INSTANCEOF) END_CASE(JSOP_INSTANCEOF)
BEGIN_CASE(JSOP_EXCEPTION) BEGIN_CASE(JSOP_EXCEPTION)
prepareStubCall(Uses(0)); {
INLINE_STUBCALL(stubs::Exception); JS_STATIC_ASSERT(sizeof(cx->throwing) == 4);
frame.pushSynced(); RegisterID reg = frame.allocReg();
masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), reg);
masm.store32(Imm32(JS_FALSE), Address(reg, offsetof(JSContext, throwing)));
Address excn(reg, offsetof(JSContext, exception));
frame.freeReg(reg);
frame.push(excn);
}
END_CASE(JSOP_EXCEPTION) END_CASE(JSOP_EXCEPTION)
BEGIN_CASE(JSOP_LINENO) BEGIN_CASE(JSOP_LINENO)

View File

@ -81,7 +81,7 @@ FindExceptionHandler(JSContext *cx)
JSScript *script = fp->script(); JSScript *script = fp->script();
top: top:
if (cx->isExceptionPending() && JSScript::isValidOffset(script->trynotesOffset)) { if (cx->throwing && JSScript::isValidOffset(script->trynotesOffset)) {
// The PC is updated before every stub call, so we can use it here. // The PC is updated before every stub call, so we can use it here.
unsigned offset = cx->regs->pc - script->main; unsigned offset = cx->regs->pc - script->main;
@ -119,7 +119,7 @@ top:
#if JS_HAS_GENERATORS #if JS_HAS_GENERATORS
/* Catch cannot intercept the closing of a generator. */ /* Catch cannot intercept the closing of a generator. */
if (JS_UNLIKELY(cx->getPendingException().isMagic(JS_GENERATOR_CLOSING))) if (JS_UNLIKELY(cx->exception.isMagic(JS_GENERATOR_CLOSING)))
break; break;
#endif #endif
@ -136,9 +136,9 @@ top:
* [retsub] should rethrow the exception. * [retsub] should rethrow the exception.
*/ */
cx->regs->sp[0].setBoolean(true); cx->regs->sp[0].setBoolean(true);
cx->regs->sp[1] = cx->getPendingException(); cx->regs->sp[1] = cx->exception;
cx->regs->sp += 2; cx->regs->sp += 2;
cx->clearPendingException(); cx->throwing = JS_FALSE;
return pc; return pc;
case JSTRY_ITER: case JSTRY_ITER:
@ -150,14 +150,15 @@ top:
* adjustment and regs.sp[1] after, to save and restore the * adjustment and regs.sp[1] after, to save and restore the
* pending exception. * pending exception.
*/ */
Value v = cx->getPendingException(); AutoValueRooter tvr(cx, cx->exception);
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENDITER); JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENDITER);
cx->clearPendingException(); cx->throwing = JS_FALSE;
ok = !!js_CloseIterator(cx, &cx->regs->sp[-1].toObject()); ok = !!js_CloseIterator(cx, &cx->regs->sp[-1].toObject());
cx->regs->sp -= 1; cx->regs->sp -= 1;
if (!ok) if (!ok)
goto top; goto top;
cx->setPendingException(v); cx->throwing = JS_TRUE;
cx->exception = tvr.value();
} }
} }
} }
@ -501,17 +502,17 @@ js_InternalThrow(VMFrame &f)
switch (handler(cx, cx->fp()->script(), cx->regs->pc, Jsvalify(&rval), switch (handler(cx, cx->fp()->script(), cx->regs->pc, Jsvalify(&rval),
cx->debugHooks->throwHookData)) { cx->debugHooks->throwHookData)) {
case JSTRAP_ERROR: case JSTRAP_ERROR:
cx->clearPendingException(); cx->throwing = JS_FALSE;
return NULL; return NULL;
case JSTRAP_RETURN: case JSTRAP_RETURN:
cx->clearPendingException(); cx->throwing = JS_FALSE;
cx->fp()->setReturnValue(rval); cx->fp()->setReturnValue(rval);
return JS_FUNC_TO_DATA_PTR(void *, return JS_FUNC_TO_DATA_PTR(void *,
cx->jaegerCompartment()->forceReturnTrampoline()); cx->jaegerCompartment()->forceReturnTrampoline());
case JSTRAP_THROW: case JSTRAP_THROW:
cx->setPendingException(rval); cx->exception = rval;
break; break;
default: default:
@ -530,7 +531,7 @@ js_InternalThrow(VMFrame &f)
// but we shouldn't return from a JS function, because we're not in a // but we shouldn't return from a JS function, because we're not in a
// JS function. // JS function.
bool lastFrame = (f.entryfp == f.fp()); bool lastFrame = (f.entryfp == f.fp());
js_UnwindScope(cx, 0, cx->isExceptionPending()); js_UnwindScope(cx, 0, cx->throwing);
// For consistency with Interpret(), always run the script epilogue. // For consistency with Interpret(), always run the script epilogue.
// This simplifies interactions with RunTracer(), since it can assume // This simplifies interactions with RunTracer(), since it can assume
@ -657,7 +658,7 @@ HandleErrorInExcessFrame(VMFrame &f, JSStackFrame *stopFp, bool searchedTopmostF
JS_ASSERT(!fp->hasImacropc()); JS_ASSERT(!fp->hasImacropc());
/* If there's an exception and a handler, set the pc and leave. */ /* If there's an exception and a handler, set the pc and leave. */
if (cx->isExceptionPending()) { if (cx->throwing) {
jsbytecode *pc = FindExceptionHandler(cx); jsbytecode *pc = FindExceptionHandler(cx);
if (pc) { if (pc) {
cx->regs->pc = pc; cx->regs->pc = pc;
@ -671,7 +672,7 @@ HandleErrorInExcessFrame(VMFrame &f, JSStackFrame *stopFp, bool searchedTopmostF
break; break;
/* Unwind and return. */ /* Unwind and return. */
returnOK &= bool(js_UnwindScope(cx, 0, returnOK || cx->isExceptionPending())); returnOK &= bool(js_UnwindScope(cx, 0, returnOK || cx->throwing));
returnOK = ScriptEpilogue(cx, fp, returnOK); returnOK = ScriptEpilogue(cx, fp, returnOK);
InlineReturn(f); InlineReturn(f);
} }
@ -972,7 +973,7 @@ RunTracer(VMFrame &f)
// Even though ExecuteTree() bypasses the interpreter, it should propagate // Even though ExecuteTree() bypasses the interpreter, it should propagate
// error failures correctly. // error failures correctly.
JS_ASSERT_IF(cx->isExceptionPending(), tpa == TPA_Error); JS_ASSERT_IF(cx->throwing, tpa == TPA_Error);
f.fp() = cx->fp(); f.fp() = cx->fp();
JS_ASSERT(f.fp() == cx->fp()); JS_ASSERT(f.fp() == cx->fp());

View File

@ -1291,11 +1291,12 @@ stubs::Debugger(VMFrame &f, jsbytecode *pc)
switch (handler(f.cx, f.cx->fp()->script(), pc, Jsvalify(&rval), switch (handler(f.cx, f.cx->fp()->script(), pc, Jsvalify(&rval),
f.cx->debugHooks->debuggerHandlerData)) { f.cx->debugHooks->debuggerHandlerData)) {
case JSTRAP_THROW: case JSTRAP_THROW:
f.cx->setPendingException(rval); f.cx->throwing = JS_TRUE;
f.cx->exception = rval;
THROW(); THROW();
case JSTRAP_RETURN: case JSTRAP_RETURN:
f.cx->clearPendingException(); f.cx->throwing = JS_FALSE;
f.cx->fp()->setReturnValue(rval); f.cx->fp()->setReturnValue(rval);
#if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64) #if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
*f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *, *f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
@ -1307,7 +1308,7 @@ stubs::Debugger(VMFrame &f, jsbytecode *pc)
break; break;
case JSTRAP_ERROR: case JSTRAP_ERROR:
f.cx->clearPendingException(); f.cx->throwing = JS_FALSE;
THROW(); THROW();
default: default:
@ -1351,11 +1352,12 @@ stubs::Trap(VMFrame &f, uint32 trapTypes)
switch (result) { switch (result) {
case JSTRAP_THROW: case JSTRAP_THROW:
f.cx->setPendingException(rval); f.cx->throwing = JS_TRUE;
f.cx->exception = rval;
THROW(); THROW();
case JSTRAP_RETURN: case JSTRAP_RETURN:
f.cx->clearPendingException(); f.cx->throwing = JS_FALSE;
f.cx->fp()->setReturnValue(rval); f.cx->fp()->setReturnValue(rval);
#if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64) #if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
*f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *, *f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
@ -1367,7 +1369,7 @@ stubs::Trap(VMFrame &f, uint32 trapTypes)
break; break;
case JSTRAP_ERROR: case JSTRAP_ERROR:
f.cx->clearPendingException(); f.cx->throwing = JS_FALSE;
THROW(); THROW();
default: default:
@ -2333,8 +2335,9 @@ stubs::Throw(VMFrame &f)
{ {
JSContext *cx = f.cx; JSContext *cx = f.cx;
JS_ASSERT(!cx->isExceptionPending()); JS_ASSERT(!cx->throwing);
cx->setPendingException(f.regs.sp[-1]); cx->throwing = JS_TRUE;
cx->exception = f.regs.sp[-1];
THROW(); THROW();
} }
@ -2767,12 +2770,6 @@ stubs::In(VMFrame &f)
template void JS_FASTCALL stubs::DelElem<true>(VMFrame &f); template void JS_FASTCALL stubs::DelElem<true>(VMFrame &f);
template void JS_FASTCALL stubs::DelElem<false>(VMFrame &f); template void JS_FASTCALL stubs::DelElem<false>(VMFrame &f);
void JS_FASTCALL
stubs::Exception(VMFrame &f)
{
f.regs.sp[0] = f.cx->getPendingException();
f.cx->clearPendingException();
}
template <bool Clamped> template <bool Clamped>
int32 JS_FASTCALL int32 JS_FASTCALL
stubs::ConvertToTypedInt(JSContext *cx, Value *vp) stubs::ConvertToTypedInt(JSContext *cx, Value *vp)

View File

@ -224,8 +224,6 @@ void JS_FASTCALL Unbrand(VMFrame &f);
template <bool strict> int32 JS_FASTCALL ConvertToTypedInt(JSContext *cx, Value *vp); template <bool strict> int32 JS_FASTCALL ConvertToTypedInt(JSContext *cx, Value *vp);
void JS_FASTCALL ConvertToTypedFloat(JSContext *cx, Value *vp); void JS_FASTCALL ConvertToTypedFloat(JSContext *cx, Value *vp);
void JS_FASTCALL Exception(VMFrame &f);
} /* namespace stubs */ } /* namespace stubs */
/* /*