Bug 541003 - CPOW: Support throwing arbitrary exceptions from content to chrome. r=mrbkap

* * *
CPOW-specific exceptions (bug 541003). r=mrbkap
This commit is contained in:
Ben Newman 2010-01-22 12:52:57 -08:00
Родитель 047e75a0dc
Коммит 7bc40759cf
5 изменённых файлов: 307 добавлений и 120 удалений

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

@ -59,6 +59,8 @@ namespace {
nsCxPusher mStack;
JSAutoRequest mRequest;
JSContext* const mContext;
const uint32 mSavedOptions;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER;
public:
@ -66,6 +68,9 @@ namespace {
AutoContextPusher(JSContext* cx
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: mRequest(cx)
, mContext(cx)
, mSavedOptions(JS_SetOptions(cx, (JS_GetOptions(cx) |
JSOPTION_DONT_REPORT_UNCAUGHT)))
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
mStack.Push(cx);
@ -73,10 +78,70 @@ namespace {
~AutoContextPusher() {
mStack.Pop();
JS_SetOptions(mContext, mSavedOptions);
}
};
class StatusPtrOwner
{
OperationStatus* mStatusPtr;
public:
StatusPtrOwner() : mStatusPtr(NULL) {}
void SetStatusPtr(OperationStatus* statusPtr) {
mStatusPtr = statusPtr;
// By default, initialize mStatusPtr to failure without an
// exception. Doing so only when the union is uninitialized
// allows AutoCheckOperation classes to be nested on the
// stack, just in case AnswerConstruct, for example, calls
// AnswerCall (as it once did, before there were unrelated
// problems with that approach).
if (mStatusPtr->type() == OperationStatus::T__None)
*mStatusPtr = JS_FALSE;
}
OperationStatus* StatusPtr() {
NS_ASSERTION(mStatusPtr, "Should have called SetStatusPtr by now.");
return mStatusPtr;
}
};
typedef AutoCheckOperationBase<StatusPtrOwner> ACOBase;
class AutoCheckOperation : public ACOBase
{
JS_DECL_USE_GUARD_OBJECT_NOTIFIER;
public:
AutoCheckOperation(ObjectWrapperChild* owc,
OperationStatus* statusPtr
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: ACOBase(NULL, owc)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
SetStatusPtr(statusPtr);
}
};
}
void
ObjectWrapperChild::CheckOperation(JSContext*,
OperationStatus* status)
{
NS_PRECONDITION(status->type() != OperationStatus::T__None,
"Checking an uninitialized operation.");
JSContext* cx = Manager()->GetContext();
jsval thrown;
if (JS_GetPendingException(cx, &thrown)) {
NS_ASSERTION(!(status->type() == OperationStatus::TJSBool &&
status->get_JSBool()),
"Operation succeeded but exception was thrown?");
JSVariant exception;
if (!jsval_to_JSVariant(cx, thrown, &exception))
exception = void_t(); // XXX Useful?
*status = exception;
JS_ClearPendingException(cx);
}
}
ObjectWrapperChild::ObjectWrapperChild(JSContext* cx, JSObject* obj)
@ -257,88 +322,85 @@ ObjectWrapperChild::AnswerSomething(/* in-parameters */
bool
ObjectWrapperChild::AnswerAddProperty(const nsString& id,
JSBool* ok)
OperationStatus* status)
{
jsid interned_id;
*ok = JS_FALSE;
JSContext* cx = Manager()->GetContext();
AutoContextPusher acp(cx);
AutoCheckOperation aco(this, status);
if (!jsid_from_nsString(cx, id, &interned_id))
return false;
*ok = JS_DefinePropertyById(cx, mObj, interned_id, JSVAL_VOID,
*status = JS_DefinePropertyById(cx, mObj, interned_id, JSVAL_VOID,
NULL, NULL, 0);
return true;
}
bool
ObjectWrapperChild::AnswerGetProperty(const nsString& id,
JSBool* ok, JSVariant* vp)
OperationStatus* status, JSVariant* vp)
{
jsid interned_id;
jsval val;
*ok = JS_FALSE;
JSContext* cx = Manager()->GetContext();
AutoContextPusher acp(cx);
AutoCheckOperation aco(this, status);
if (!jsid_from_nsString(cx, id, &interned_id))
return false;
*ok = JS_GetPropertyById(cx, mObj, interned_id, &val);
*status = JS_GetPropertyById(cx, mObj, interned_id, &val);
// Since we fully expect this call to jsval_to_JSVariant to return
// true, we can't just leave vp uninitialized when JS_GetPropertyById
// returns JS_FALSE. This pitfall could be avoided in general if IPDL
// ensured that outparams were pre-initialized to some default value
// (XXXfixme cjones?).
return jsval_to_JSVariant(cx, *ok ? val : JSVAL_VOID, vp);
return jsval_to_JSVariant(cx, aco.Ok() ? val : JSVAL_VOID, vp);
}
bool
ObjectWrapperChild::AnswerSetProperty(const nsString& id, const JSVariant& v,
JSBool* ok, JSVariant* vp)
OperationStatus* status, JSVariant* vp)
{
jsid interned_id;
jsval val;
*ok = JS_FALSE;
*vp = v;
JSContext* cx = Manager()->GetContext();
AutoContextPusher acp(cx);
AutoCheckOperation aco(this, status);
if (!jsid_from_nsString(cx, id, &interned_id) ||
!jsval_from_JSVariant(cx, v, &val))
return false;
*ok = JS_SetPropertyById(cx, mObj, interned_id, &val);
*status = JS_SetPropertyById(cx, mObj, interned_id, &val);
return jsval_to_JSVariant(cx, *ok ? val : JSVAL_VOID, vp);
return jsval_to_JSVariant(cx, aco.Ok() ? val : JSVAL_VOID, vp);
}
bool
ObjectWrapperChild::AnswerDelProperty(const nsString& id,
JSBool* ok, JSVariant* vp)
OperationStatus* status, JSVariant* vp)
{
jsid interned_id;
jsval val;
*ok = JS_FALSE;
JSContext* cx = Manager()->GetContext();
AutoContextPusher acp(cx);
AutoCheckOperation aco(this, status);
if (!jsid_from_nsString(cx, id, &interned_id))
return false;
*ok = JS_DeletePropertyById2(cx, mObj, interned_id, &val);
*status = JS_DeletePropertyById2(cx, mObj, interned_id, &val);
return jsval_to_JSVariant(cx, *ok ? val : JSVAL_VOID, vp);
return jsval_to_JSVariant(cx, aco.Ok() ? val : JSVAL_VOID, vp);
}
static const PRUint32 sNextIdIndexSlot = 0;
@ -370,13 +432,13 @@ static const JSClass sCPOW_NewEnumerateState_JSClass = {
bool
ObjectWrapperChild::AnswerNewEnumerateInit(/* no in-parameters */
JSBool* ok, JSVariant* statep, int* idp)
OperationStatus* status, JSVariant* statep, int* idp)
{
*ok = JS_FALSE;
*idp = 0;
JSContext* cx = Manager()->GetContext();
AutoContextPusher acp(cx);
AutoCheckOperation aco(this, status);
JSClass* clasp = const_cast<JSClass*>(&sCPOW_NewEnumerateState_JSClass);
JSObject* state = JS_NewObjectWithGivenProto(cx, clasp, NULL, NULL);
@ -408,7 +470,7 @@ ObjectWrapperChild::AnswerNewEnumerateInit(/* no in-parameters */
}
*idp = strIds->Length();
*ok = (JS_SetPrivate(cx, state, strIds) &&
*status = (JS_SetPrivate(cx, state, strIds) &&
JS_SetReservedSlot(cx, state, sNextIdIndexSlot,
JSVAL_ZERO) &&
JSObject_to_JSVariant(cx, state, statep));
@ -418,17 +480,17 @@ ObjectWrapperChild::AnswerNewEnumerateInit(/* no in-parameters */
bool
ObjectWrapperChild::AnswerNewEnumerateNext(const JSVariant& in_state,
JSBool* ok, JSVariant* statep, nsString* idp)
OperationStatus* status, JSVariant* statep, nsString* idp)
{
JSObject* state;
jsval v;
*ok = JS_FALSE;
*statep = in_state;
idp->Truncate();
JSContext* cx = Manager()->GetContext();
AutoContextPusher acp(cx);
AutoCheckOperation aco(this, status);
if (!JSObject_from_JSVariant(cx, in_state, &state))
return false;
@ -444,12 +506,12 @@ ObjectWrapperChild::AnswerNewEnumerateNext(const JSVariant& in_state,
NS_ASSERTION(i <= strIds->Length(), "Index of next jsid too large?");
if (i == strIds->Length()) {
*ok = JS_TRUE;
*status = JS_TRUE;
return JSObject_to_JSVariant(cx, NULL, statep);
}
*idp = strIds->ElementAt(i);
*ok = JS_SetReservedSlot(cx, state, sNextIdIndexSlot,
*status = JS_SetReservedSlot(cx, state, sNextIdIndexSlot,
INT_TO_JSVAL(i + 1));
return true;
}
@ -472,15 +534,15 @@ ObjectWrapperChild::RecvNewEnumerateDestroy(const JSVariant& in_state)
bool
ObjectWrapperChild::AnswerNewResolve(const nsString& id, const int& flags,
JSBool* ok, PObjectWrapperChild** obj2)
OperationStatus* status, PObjectWrapperChild** obj2)
{
jsid interned_id;
*ok = JS_FALSE;
*obj2 = NULL;
JSContext* cx = Manager()->GetContext();
AutoContextPusher acp(cx);
AutoCheckOperation aco(this, status);
if (!jsid_from_nsString(cx, id, &interned_id))
return false;
@ -492,7 +554,7 @@ ObjectWrapperChild::AnswerNewResolve(const nsString& id, const int& flags,
if (!JS_GetPropertyDescriptorById(cx, mObj, interned_id, flags, &desc))
return true;
*ok = JS_TRUE;
*status = JS_TRUE;
if (desc.obj)
*obj2 = Manager()->GetOrCreateWrapper(desc.obj);
@ -502,13 +564,14 @@ ObjectWrapperChild::AnswerNewResolve(const nsString& id, const int& flags,
bool
ObjectWrapperChild::AnswerConvert(const JSType& type,
JSBool* ok, JSVariant* vp)
OperationStatus* status, JSVariant* vp)
{
jsval v;
JSContext* cx = Manager()->GetContext();
AutoContextPusher acp(cx);
*ok = JS_ConvertValue(cx, OBJECT_TO_JSVAL(mObj), type, &v);
return jsval_to_JSVariant(cx, *ok ? v : JSVAL_VOID, vp);
AutoCheckOperation aco(this, status);
*status = JS_ConvertValue(cx, OBJECT_TO_JSVAL(mObj), type, &v);
return jsval_to_JSVariant(cx, aco.Ok() ? v : JSVAL_VOID, vp);
}
namespace {
@ -518,12 +581,11 @@ namespace {
bool
ObjectWrapperChild::AnswerCall(PObjectWrapperChild* receiver, const nsTArray<JSVariant>& argv,
JSBool* ok, JSVariant* rval)
OperationStatus* status, JSVariant* rval)
{
*ok = JS_FALSE;
JSContext* cx = Manager()->GetContext();
AutoContextPusher acp(cx);
AutoCheckOperation aco(this, status);
JSObject* obj;
if (!JSObject_from_PObjectWrapperChild(cx, receiver, &obj))
@ -541,20 +603,19 @@ ObjectWrapperChild::AnswerCall(PObjectWrapperChild* receiver, const nsTArray<JSV
return false;
jsval rv;
*ok = JS_CallFunctionValue(cx, obj, OBJECT_TO_JSVAL(mObj),
*status = JS_CallFunctionValue(cx, obj, OBJECT_TO_JSVAL(mObj),
argv.Length(), jsargs, &rv);
return jsval_to_JSVariant(cx, *ok ? rv : JSVAL_VOID, rval);
return jsval_to_JSVariant(cx, aco.Ok() ? rv : JSVAL_VOID, rval);
}
bool
ObjectWrapperChild::AnswerConstruct(const nsTArray<JSVariant>& argv,
JSBool* ok, PObjectWrapperChild** rval)
OperationStatus* status, PObjectWrapperChild** rval)
{
*ok = JS_FALSE;
JSContext* cx = Manager()->GetContext();
AutoContextPusher acp(cx);
AutoCheckOperation aco(this, status);
AutoJSArgs args;
PRUint32 argc = argv.Length();
@ -569,7 +630,7 @@ ObjectWrapperChild::AnswerConstruct(const nsTArray<JSVariant>& argv,
JSObject* obj = JS_New(cx, mObj, argc, jsargs);
*ok = !!obj;
*status = !!obj;
*rval = Manager()->GetOrCreateWrapper(obj);
return true;
@ -577,13 +638,14 @@ ObjectWrapperChild::AnswerConstruct(const nsTArray<JSVariant>& argv,
bool
ObjectWrapperChild::AnswerHasInstance(const JSVariant& v,
JSBool* ok, JSBool* bp)
OperationStatus* status, JSBool* bp)
{
jsval candidate;
JSContext* cx = Manager()->GetContext();
AutoContextPusher acp(cx);
AutoCheckOperation aco(this, status);
if (!jsval_from_JSVariant(cx, v, &candidate))
return false;
*ok = JS_HasInstance(cx, mObj, candidate, bp);
*status = JS_HasInstance(cx, mObj, candidate, bp);
return true;
}

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

@ -43,6 +43,9 @@
#include "mozilla/jsipc/PObjectWrapperChild.h"
// For OperationChecker and AutoCheckOperationBase.
#include "mozilla/jsipc/ObjectWrapperParent.h"
using mozilla::jsipc::JSVariant;
namespace mozilla {
@ -52,6 +55,7 @@ class ContextWrapperChild;
class ObjectWrapperChild
: public PObjectWrapperChild
, public OperationChecker
{
public:
@ -59,6 +63,8 @@ public:
JSObject* GetJSObject() const { return mObj; }
void CheckOperation(JSContext* cx, OperationStatus* status);
private:
JSObject* const mObj;
@ -81,39 +87,39 @@ protected:
void ActorDestroy(ActorDestroyReason why);
bool AnswerAddProperty(const nsString& id,
JSBool* ok);
OperationStatus* status);
bool AnswerGetProperty(const nsString& id,
JSBool* ok, JSVariant* vp);
OperationStatus* status, JSVariant* vp);
bool AnswerSetProperty(const nsString& id, const JSVariant& v,
JSBool* ok, JSVariant* vp);
OperationStatus* status, JSVariant* vp);
bool AnswerDelProperty(const nsString& id,
JSBool* ok, JSVariant* vp);
OperationStatus* status, JSVariant* vp);
bool AnswerNewEnumerateInit(/* no in-parameters */
JSBool* ok, JSVariant* statep, int* idp);
OperationStatus* status, JSVariant* statep, int* idp);
bool AnswerNewEnumerateNext(const JSVariant& in_state,
JSBool* ok, JSVariant* statep, nsString* idp);
OperationStatus* status, JSVariant* statep, nsString* idp);
bool RecvNewEnumerateDestroy(const JSVariant& in_state);
bool AnswerNewResolve(const nsString& id, const int& flags,
JSBool* ok, PObjectWrapperChild** obj2);
OperationStatus* status, PObjectWrapperChild** obj2);
bool AnswerConvert(const JSType& type,
JSBool* ok, JSVariant* vp);
OperationStatus* status, JSVariant* vp);
bool AnswerCall(PObjectWrapperChild* receiver, const nsTArray<JSVariant>& argv,
JSBool* ok, JSVariant* rval);
OperationStatus* status, JSVariant* rval);
bool AnswerConstruct(const nsTArray<JSVariant>& argv,
JSBool* ok, PObjectWrapperChild** rval);
OperationStatus* status, PObjectWrapperChild** rval);
bool AnswerHasInstance(const JSVariant& v,
JSBool* ok, JSBool* bp);
OperationStatus* status, JSBool* bp);
};
}}

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

@ -103,6 +103,69 @@ namespace {
};
class StatusMemberOwner
{
OperationStatus mStatus;
public:
StatusMemberOwner() : mStatus(JS_FALSE) {}
OperationStatus* StatusPtr() {
return &mStatus;
}
};
typedef AutoCheckOperationBase<StatusMemberOwner> ACOBase;
class AutoCheckOperation : public ACOBase
{
JS_DECL_USE_GUARD_OBJECT_NOTIFIER;
public:
AutoCheckOperation(JSContext* cx,
ObjectWrapperParent* owp
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: ACOBase(cx, owp)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
}
};
}
void
ObjectWrapperParent::CheckOperation(JSContext* cx,
OperationStatus* status)
{
NS_PRECONDITION(status->type() != OperationStatus::T__None,
"Checking an uninitialized operation.");
switch (status->type()) {
case OperationStatus::TJSVariant:
{
jsval thrown;
if (jsval_from_JSVariant(cx, status->get_JSVariant(), &thrown))
JS_SetPendingException(cx, thrown);
*status = JS_FALSE;
}
break;
case OperationStatus::TJSBool:
if (!status->get_JSBool() && !JS_IsExceptionPending(cx)) {
NS_WARNING("CPOW operation failed without setting an exception.");
}
break;
default:
NS_NOTREACHED("Invalid or uninitialized OperationStatus type.");
break;
}
}
template <typename RType>
static RType
with_error(JSContext* cx,
RType rval,
const char* error = NULL)
{
if (!JS_IsExceptionPending(cx))
JS_ReportError(cx, error ? error : "Unspecified CPOW error");
return rval;
}
const JSExtendedClass ObjectWrapperParent::sCPOW_JSClass = {
@ -198,7 +261,7 @@ ObjectWrapperParent::jsval_to_JSVariant(JSContext* cx, jsval from,
{
PObjectWrapperParent* powp;
if (!JSObject_to_PObjectWrapperParent(cx, JSVAL_TO_OBJECT(from), &powp))
return false;
return with_error(cx, false, "Cannot pass parent-created object to child");
*to = powp;
}
return true;
@ -217,8 +280,9 @@ ObjectWrapperParent::jsval_to_JSVariant(JSContext* cx, jsval from,
*to = !!JSVAL_TO_BOOLEAN(from);
return true;
case JSTYPE_XML:
return with_error(cx, false, "CPOWs currently cannot handle JSTYPE_XML");
default:
return false;
return with_error(cx, false, "Bad jsval type");
}
}
@ -332,22 +396,22 @@ ObjectWrapperParent::CPOW_AddProperty(JSContext *cx, JSObject *obj, jsval id,
ObjectWrapperParent* self = Unwrap(cx, obj);
if (!self)
return JS_FALSE;
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_AddProperty");
if (AutoResolveFlag::IsSet(cx, obj))
return JS_TRUE;
AutoCheckOperation aco(cx, self);
nsString in_id;
if (!jsval_to_nsString(cx, id, &in_id))
return JS_FALSE;
JSBool out_ok;
return (self->Manager()->RequestRunToCompletion() &&
self->CallAddProperty(in_id,
&out_ok) &&
out_ok);
aco.StatusPtr()) &&
aco.Ok());
}
/*static*/ JSBool
@ -359,20 +423,21 @@ ObjectWrapperParent::CPOW_GetProperty(JSContext *cx, JSObject *obj, jsval id,
ObjectWrapperParent* self = Unwrap(cx, obj);
if (!self)
return JS_FALSE;
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_GetProperty");
AutoCheckOperation aco(cx, self);
nsString in_id;
if (!jsval_to_nsString(cx, id, &in_id))
return JS_FALSE;
JSBool out_ok;
JSVariant out_v;
return (self->Manager()->RequestRunToCompletion() &&
self->CallGetProperty(in_id,
&out_ok, &out_v) &&
out_ok &&
aco.StatusPtr(), &out_v) &&
aco.Ok() &&
self->jsval_from_JSVariant(cx, out_v, vp));
}
@ -385,7 +450,9 @@ ObjectWrapperParent::CPOW_SetProperty(JSContext *cx, JSObject *obj, jsval id,
ObjectWrapperParent* self = Unwrap(cx, obj);
if (!self)
return JS_FALSE;
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_SetProperty");
AutoCheckOperation aco(cx, self);
nsString in_id;
JSVariant in_v;
@ -394,13 +461,12 @@ ObjectWrapperParent::CPOW_SetProperty(JSContext *cx, JSObject *obj, jsval id,
!self->jsval_to_JSVariant(cx, *vp, &in_v))
return JS_FALSE;
JSBool out_ok;
JSVariant out_v;
return (self->Manager()->RequestRunToCompletion() &&
self->CallSetProperty(in_id, in_v,
&out_ok, &out_v) &&
out_ok &&
aco.StatusPtr(), &out_v) &&
aco.Ok() &&
self->jsval_from_JSVariant(cx, out_v, vp));
}
@ -413,32 +479,34 @@ ObjectWrapperParent::CPOW_DelProperty(JSContext *cx, JSObject *obj, jsval id,
ObjectWrapperParent* self = Unwrap(cx, obj);
if (!self)
return JS_FALSE;
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_DelProperty");
AutoCheckOperation aco(cx, self);
nsString in_id;
if (!jsval_to_nsString(cx, id, &in_id))
return JS_FALSE;
JSBool out_ok;
JSVariant out_v;
return (self->Manager()->RequestRunToCompletion() &&
self->CallDelProperty(in_id,
&out_ok, &out_v) &&
out_ok &&
aco.StatusPtr(), &out_v) &&
aco.Ok() &&
jsval_from_JSVariant(cx, out_v, vp));
}
JSBool
ObjectWrapperParent::NewEnumerateInit(JSContext* cx, jsval* statep, jsid* idp)
{
JSBool out_ok;
AutoCheckOperation aco(cx, this);
JSVariant out_state;
int out_id;
return (CallNewEnumerateInit(&out_ok, &out_state, &out_id) &&
out_ok &&
return (CallNewEnumerateInit(aco.StatusPtr(), &out_state, &out_id) &&
aco.Ok() &&
jsval_from_JSVariant(cx, out_state, statep) &&
(!idp || jsid_from_int(cx, out_id, idp)));
}
@ -446,17 +514,19 @@ ObjectWrapperParent::NewEnumerateInit(JSContext* cx, jsval* statep, jsid* idp)
JSBool
ObjectWrapperParent::NewEnumerateNext(JSContext* cx, jsval* statep, jsid* idp)
{
AutoCheckOperation aco(cx, this);
JSVariant in_state;
if (!jsval_to_JSVariant(cx, *statep, &in_state))
return JS_FALSE;
JSBool out_ok;
JSVariant out_state;
nsString out_id;
if (CallNewEnumerateNext(in_state,
&out_ok, &out_state, &out_id) &&
out_ok &&
aco.StatusPtr(), &out_state, &out_id) &&
aco.Ok() &&
jsval_from_JSVariant(cx, out_state, statep) &&
jsid_from_nsString(cx, out_id, idp))
{
@ -471,7 +541,10 @@ ObjectWrapperParent::NewEnumerateNext(JSContext* cx, jsval* statep, jsid* idp)
JSBool
ObjectWrapperParent::NewEnumerateDestroy(JSContext* cx, jsval state)
{
AutoCheckOperation aco(cx, this);
JSVariant in_state;
if (!jsval_to_JSVariant(cx, state, &in_state))
return JS_FALSE;
@ -487,7 +560,7 @@ ObjectWrapperParent::CPOW_NewEnumerate(JSContext *cx, JSObject *obj,
ObjectWrapperParent* self = Unwrap(cx, obj);
if (!self)
return JS_FALSE;
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_NewEnumerate");
switch (enum_op) {
case JSENUMERATE_INIT:
@ -499,6 +572,7 @@ ObjectWrapperParent::CPOW_NewEnumerate(JSContext *cx, JSObject *obj,
return self->NewEnumerateDestroy(cx, *statep);
}
NS_NOTREACHED("Unknown enum_op value in CPOW_NewEnumerate");
return JS_FALSE;
}
@ -511,20 +585,21 @@ ObjectWrapperParent::CPOW_NewResolve(JSContext *cx, JSObject *obj, jsval id,
ObjectWrapperParent* self = Unwrap(cx, obj);
if (!self)
return JS_FALSE;
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_NewResolve");
AutoCheckOperation aco(cx, self);
nsString in_id;
if (!jsval_to_nsString(cx, id, &in_id))
return JS_FALSE;
JSBool out_ok;
PObjectWrapperParent* out_pobj;
if (!self->Manager()->RequestRunToCompletion() ||
!self->CallNewResolve(in_id, flags,
&out_ok, &out_pobj) ||
!out_ok ||
aco.StatusPtr(), &out_pobj) ||
!aco.Ok() ||
!JSObject_from_PObjectWrapperParent(cx, out_pobj, objp))
return JS_FALSE;
@ -547,7 +622,7 @@ ObjectWrapperParent::CPOW_Convert(JSContext *cx, JSObject *obj, JSType type,
ObjectWrapperParent* self = Unwrap(cx, obj);
if (!self)
return JS_FALSE;
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_Convert");
*vp = OBJECT_TO_JSVAL(obj);
@ -573,7 +648,9 @@ ObjectWrapperParent::CPOW_Call(JSContext* cx, JSObject* obj, uintN argc,
ObjectWrapperParent* function =
Unwrap(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)));
if (!function)
return JS_FALSE;
return with_error(cx, JS_FALSE, "Could not unwrap CPOW function");
AutoCheckOperation aco(cx, function);
ObjectWrapperParent* receiver = Unwrap(cx, obj);
if (!receiver) {
@ -589,13 +666,12 @@ ObjectWrapperParent::CPOW_Call(JSContext* cx, JSObject* obj, uintN argc,
if (!jsval_to_JSVariant(cx, argv[i], in_argv.AppendElement()))
return JS_FALSE;
JSBool out_ok;
JSVariant out_rval;
return (function->Manager()->RequestRunToCompletion() &&
function->CallCall(receiver, in_argv,
&out_ok, &out_rval) &&
out_ok &&
aco.StatusPtr(), &out_rval) &&
aco.Ok() &&
jsval_from_JSVariant(cx, out_rval, rval));
}
@ -608,20 +684,21 @@ ObjectWrapperParent::CPOW_Construct(JSContext *cx, JSObject *obj, uintN argc,
ObjectWrapperParent* constructor =
Unwrap(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)));
if (!constructor)
return JS_FALSE;
return with_error(cx, JS_FALSE, "Could not unwrap CPOW constructor function");
AutoCheckOperation aco(cx, constructor);
nsTArray<JSVariant> in_argv(argc);
for (uintN i = 0; i < argc; i++)
if (!jsval_to_JSVariant(cx, argv[i], in_argv.AppendElement()))
return JS_FALSE;
JSBool out_ok;
PObjectWrapperParent* out_powp;
return (constructor->Manager()->RequestRunToCompletion() &&
constructor->CallConstruct(in_argv,
&out_ok, &out_powp) &&
out_ok &&
aco.StatusPtr(), &out_powp) &&
aco.Ok() &&
jsval_from_PObjectWrapperParent(cx, out_powp, rval));
}
@ -635,19 +712,19 @@ ObjectWrapperParent::CPOW_HasInstance(JSContext *cx, JSObject *obj, jsval v,
ObjectWrapperParent* self = Unwrap(cx, obj);
if (!self)
return JS_FALSE;
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_HasInstance");
AutoCheckOperation aco(cx, self);
JSVariant in_v;
if (!jsval_to_JSVariant(cx, v, &in_v))
return JS_FALSE;
JSBool out_ok;
return (self->Manager()->RequestRunToCompletion() &&
self->CallHasInstance(in_v,
&out_ok, bp) &&
out_ok);
aco.StatusPtr(), bp) &&
aco.Ok());
}
/*static*/ JSBool
@ -660,7 +737,7 @@ ObjectWrapperParent::CPOW_Equality(JSContext *cx, JSObject *obj, jsval v,
ObjectWrapperParent* self = Unwrap(cx, obj);
if (!self)
return JS_FALSE;
return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_Equality");
if (JSVAL_IS_PRIMITIVE(v))
return JS_TRUE;

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

@ -50,8 +50,15 @@ namespace jsipc {
class ContextWrapperParent;
class OperationChecker {
public:
virtual void CheckOperation(JSContext* cx,
OperationStatus* status) = 0;
};
class ObjectWrapperParent
: public PObjectWrapperParent
, public OperationChecker
{
public:
@ -65,6 +72,9 @@ public:
return OBJECT_TO_JSVAL(GetJSObject(cx));
}
void CheckOperation(JSContext* cx,
OperationStatus* status);
static const JSExtendedClass sCPOW_JSClass;
protected:
@ -136,6 +146,33 @@ private:
jsval* to);
};
template <class StatusOwnerPolicy>
class AutoCheckOperationBase
: public StatusOwnerPolicy
{
JSContext* const mContext;
OperationChecker* const mChecker;
protected:
AutoCheckOperationBase(JSContext* cx,
OperationChecker* checker)
: mContext(cx)
, mChecker(checker)
{}
virtual ~AutoCheckOperationBase() {
mChecker->CheckOperation(mContext, StatusOwnerPolicy::StatusPtr());
}
public:
bool Ok() {
return (StatusOwnerPolicy::StatusPtr()->type() == OperationStatus::TJSBool &&
StatusOwnerPolicy::StatusPtr()->get_JSBool());
}
};
}}
#endif

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

@ -59,6 +59,11 @@ union JSVariant {
// and IPC::ParamTraits mistakes JSIntn for int.
};
union OperationStatus {
JSBool;
JSVariant; // Exception thrown.
};
rpc protocol PObjectWrapper
{
manager PContextWrapper;
@ -67,28 +72,28 @@ child:
__delete__(); // unroot
rpc AddProperty(nsString id)
returns (JSBool ok);
returns (OperationStatus status);
rpc GetProperty(nsString id)
returns (JSBool ok,
returns (OperationStatus status,
JSVariant vp);
rpc SetProperty(nsString id,
JSVariant v)
returns (JSBool ok,
returns (OperationStatus status,
JSVariant vp);
rpc DelProperty(nsString id)
returns (JSBool ok,
returns (OperationStatus status,
JSVariant vp);
rpc NewEnumerateInit()
returns (JSBool ok,
returns (OperationStatus status,
JSVariant statep,
int idp);
rpc NewEnumerateNext(JSVariant in_state)
returns (JSBool ok,
returns (OperationStatus status,
JSVariant statep,
nsString idp);
@ -96,24 +101,24 @@ child:
rpc NewResolve(nsString id,
int flags)
returns (JSBool ok,
returns (OperationStatus status,
nullable PObjectWrapper obj2);
rpc Convert(JSType type)
returns (JSBool ok,
returns (OperationStatus status,
JSVariant vp);
rpc Call(PObjectWrapper receiver,
JSVariant[] argv)
returns (JSBool ok,
returns (OperationStatus status,
JSVariant rval);
rpc Construct(JSVariant[] argv)
returns (JSBool ok,
returns (OperationStatus status,
nullable PObjectWrapper rval);
rpc HasInstance(JSVariant v)
returns (JSBool ok,
returns (OperationStatus status,
JSBool bp);
};