Bug 674171: Separate the construction of a completion value from the debuggee->debugger compartment transition. r=jorendorff

In class Debugger, split newCompletionValue into:
- resultToCompletion, which takes a standard SpiderMonkey (success, value,
  context's exception) triple and produces the corresponding
  (JSTrapStatus, value) pair; and
- newCompletionValue, which takes a (JSTrapStatus, value) pair and produces
  a JavaScript completion value.

Define receiveCompletionValue to do exactly what newCompletionValue used to
do: the above two operations, with a compartment 'leave' in the middle.
Substitute receiveCompletionValue where newCompletionValue is used now.
This commit is contained in:
Jim Blandy 2012-03-02 12:12:14 -08:00
parent 435129c819
commit 5faf15629d
2 changed files with 76 additions and 19 deletions

View File

@ -700,39 +700,79 @@ Debugger::handleUncaughtException(AutoCompartment &ac, Value *vp, bool callHook)
return JSTRAP_ERROR;
}
bool
Debugger::newCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp)
void
Debugger::resultToCompletion(JSContext *cx, bool ok, const Value &rv,
JSTrapStatus *status, Value *value)
{
JS_ASSERT_IF(ok, !ac.context->isExceptionPending());
JS_ASSERT_IF(ok, !cx->isExceptionPending());
JSContext *cx = ac.context;
jsid key;
if (ok) {
ac.leave();
key = ATOM_TO_JSID(cx->runtime->atomState.returnAtom);
*status = JSTRAP_RETURN;
*value = rv;
} else if (cx->isExceptionPending()) {
key = ATOM_TO_JSID(cx->runtime->atomState.throwAtom);
val = cx->getPendingException();
*status = JSTRAP_THROW;
*value = cx->getPendingException();
cx->clearPendingException();
ac.leave();
} else {
ac.leave();
vp->setNull();
*status = JSTRAP_ERROR;
value->setUndefined();
}
}
bool
Debugger::newCompletionValue(JSContext *cx, JSTrapStatus status, Value value, Value *result)
{
/*
* We must be in the debugger's compartment, since that's where we want
* to construct the completion value.
*/
assertSameCompartment(cx, object.get());
jsid key;
switch (status) {
case JSTRAP_RETURN:
key = ATOM_TO_JSID(cx->runtime->atomState.returnAtom);
break;
case JSTRAP_THROW:
key = ATOM_TO_JSID(cx->runtime->atomState.throwAtom);
break;
case JSTRAP_ERROR:
result->setNull();
return true;
default:
JS_NOT_REACHED("bad status passed to Debugger::newCompletionValue");
}
/* Common tail for JSTRAP_RETURN and JSTRAP_THROW. */
JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass);
if (!obj ||
!wrapDebuggeeValue(cx, &val) ||
!DefineNativeProperty(cx, obj, key, val, JS_PropertyStub, JS_StrictPropertyStub,
!wrapDebuggeeValue(cx, &value) ||
!DefineNativeProperty(cx, obj, key, value, JS_PropertyStub, JS_StrictPropertyStub,
JSPROP_ENUMERATE, 0, 0))
{
return false;
}
vp->setObject(*obj);
result->setObject(*obj);
return true;
}
bool
Debugger::receiveCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp)
{
JSContext *cx = ac.context;
JSTrapStatus status;
Value value;
resultToCompletion(cx, ok, val, &status, &value);
ac.leave();
return newCompletionValue(cx, status, value, vp);
}
JSTrapStatus
Debugger::parseResumptionValue(AutoCompartment &ac, bool ok, const Value &rv, Value *vp,
bool callHook)
@ -2986,7 +3026,7 @@ DebuggerFrameEval(JSContext *cx, unsigned argc, Value *vp, EvalBindingsMode mode
JS::Anchor<JSString *> anchor(linearStr);
bool ok = EvaluateInEnv(cx, env, fp, linearStr->chars(), linearStr->length(),
"debugger eval code", 1, &rval);
return dbg->newCompletionValue(ac, ok, rval, vp);
return dbg->receiveCompletionValue(ac, ok, rval, vp);
}
static JSBool
@ -3624,12 +3664,12 @@ ApplyOrCall(JSContext *cx, unsigned argc, Value *vp, ApplyOrCallMode mode)
}
/*
* Call the function. Use newCompletionValue to return to the debugger
* Call the function. Use receiveCompletionValue to return to the debugger
* compartment and populate args.rval().
*/
Value rval;
bool ok = Invoke(cx, thisv, calleev, callArgc, callArgv, &rval);
return dbg->newCompletionValue(ac, ok, rval, &args.rval());
return dbg->receiveCompletionValue(ac, ok, rval, &args.rval());
}
static JSBool

View File

@ -331,6 +331,23 @@ class Debugger {
/* Store the Debugger.Frame object for the frame fp in *vp. */
bool getScriptFrame(JSContext *cx, StackFrame *fp, Value *vp);
/*
* Set |*status| and |*value| to a (JSTrapStatus, Value) pair reflecting a
* standard SpiderMonkey call state: a boolean success value |ok|, a return
* value |rv|, and a context |cx| that may or may not have an exception set.
* If an exception was pending on |cx|, it is cleared (and |ok| is asserted
* to be false).
*/
static void resultToCompletion(JSContext *cx, bool ok, const Value &rv,
JSTrapStatus *status, Value *value);
/*
* Set |*result| to a JavaScript completion value corresponding to |status|
* and |value|. |value| should be the return value or exception value, not
* wrapped as a debuggee value. |cx| must be in the debugger compartment.
*/
bool newCompletionValue(JSContext *cx, JSTrapStatus status, Value value, Value *result);
/*
* Precondition: we are in the debuggee compartment (ac is entered) and ok
* is true if the operation in the debuggee compartment succeeded, false on
@ -343,7 +360,7 @@ class Debugger {
* pending exception. (This ordinarily returns true even if the ok argument
* is false.)
*/
bool newCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp);
bool receiveCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp);
/*
* Return the Debugger.Script object for |script|, or create a new one if