зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
c10469b486
Коммит
4b826d7ec3
|
@ -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,
|
||||
NULL, NULL, 0);
|
||||
*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,27 +470,27 @@ ObjectWrapperChild::AnswerNewEnumerateInit(/* no in-parameters */
|
|||
}
|
||||
*idp = strIds->Length();
|
||||
|
||||
*ok = (JS_SetPrivate(cx, state, strIds) &&
|
||||
JS_SetReservedSlot(cx, state, sNextIdIndexSlot,
|
||||
JSVAL_ZERO) &&
|
||||
JSObject_to_JSVariant(cx, state, statep));
|
||||
*status = (JS_SetPrivate(cx, state, strIds) &&
|
||||
JS_SetReservedSlot(cx, state, sNextIdIndexSlot,
|
||||
JSVAL_ZERO) &&
|
||||
JSObject_to_JSVariant(cx, state, statep));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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,13 +506,13 @@ 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,
|
||||
INT_TO_JSVAL(i + 1));
|
||||
*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),
|
||||
argv.Length(), jsargs, &rv);
|
||||
*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,21 +43,27 @@
|
|||
|
||||
#include "mozilla/jsipc/PObjectWrapperChild.h"
|
||||
|
||||
// For OperationChecker and AutoCheckOperationBase.
|
||||
#include "mozilla/jsipc/ObjectWrapperParent.h"
|
||||
|
||||
using mozilla::jsipc::JSVariant;
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
class ContextWrapperChild;
|
||||
|
||||
|
||||
class ObjectWrapperChild
|
||||
: public PObjectWrapperChild
|
||||
, public OperationChecker
|
||||
{
|
||||
public:
|
||||
|
||||
ObjectWrapperChild(JSContext* cx, JSObject* obj);
|
||||
|
||||
JSObject* GetJSObject() const { return mObj; }
|
||||
|
||||
void CheckOperation(JSContext* cx, OperationStatus* status);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -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;
|
||||
|
@ -393,14 +460,13 @@ ObjectWrapperParent::CPOW_SetProperty(JSContext *cx, JSObject *obj, jsval id,
|
|||
if (!jsval_to_nsString(cx, id, &in_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) {
|
||||
|
@ -588,14 +665,13 @@ ObjectWrapperParent::CPOW_Call(JSContext* cx, JSObject* obj, uintN argc,
|
|||
for (uintN i = 0; i < argc; i++)
|
||||
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);
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче