Bug 996785 - Bidirectional CPOWs (r=mrbkap)

This commit is contained in:
Bill McCloskey 2014-05-16 16:40:37 -07:00
parent ef7051c241
commit 07f15166ed
14 changed files with 310 additions and 238 deletions

View File

@ -899,7 +899,7 @@ ContentChild::AllocPJavaScriptChild()
bool
ContentChild::DeallocPJavaScriptChild(PJavaScriptChild *child)
{
delete child;
static_cast<mozilla::jsipc::JavaScriptChild *>(child)->decref();
return true;
}

View File

@ -84,6 +84,7 @@
#include "nsIExternalProtocolService.h"
#include "nsIGfxInfo.h"
#include "nsIIdleService.h"
#include "nsIJSRuntimeService.h"
#include "nsIMemoryInfoDumper.h"
#include "nsIMemoryReporter.h"
#include "nsIMozBrowserFrame.h"
@ -2355,7 +2356,15 @@ mozilla::jsipc::PJavaScriptParent *
ContentParent::AllocPJavaScriptParent()
{
MOZ_ASSERT(!ManagedPJavaScriptParent().Length());
mozilla::jsipc::JavaScriptParent *parent = new mozilla::jsipc::JavaScriptParent();
nsCOMPtr<nsIJSRuntimeService> svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
NS_ENSURE_TRUE(svc, nullptr);
JSRuntime *rt;
svc->GetRuntime(&rt);
NS_ENSURE_TRUE(svc, nullptr);
mozilla::jsipc::JavaScriptParent *parent = new mozilla::jsipc::JavaScriptParent(rt);
if (!parent->init()) {
delete parent;
return nullptr;

View File

@ -22,6 +22,13 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
typedef WrapperAnswer Answer;
public:
JavaScriptBase(JSRuntime *rt)
: JavaScriptShared(rt),
WrapperOwner(rt),
WrapperAnswer(rt)
{}
virtual ~JavaScriptBase() {}
virtual void ActorDestroy(WrapperOwner::ActorDestroyReason why) {
WrapperOwner::ActorDestroy(why);
}
@ -101,8 +108,15 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
return Answer::AnswerDOMInstanceOf(objId, prototypeID, depth, rs, instanceof);
}
bool RecvDropObject(const ObjectId &objId) {
return Answer::RecvDropObject(objId);
}
/*** Dummy call handlers ***/
bool SendDropObject(const ObjectId &objId) {
return Base::SendDropObject(objId);
}
bool CallPreventExtensions(const ObjectId &objId, ReturnStatus *rs) {
return Base::CallPreventExtensions(objId, rs);
}
@ -175,6 +189,15 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
ReturnStatus *rs, bool *instanceof) {
return Base::CallDOMInstanceOf(objId, prototypeID, depth, rs, instanceof);
}
/* The following code is needed to suppress a bogus MSVC warning (C4250). */
virtual bool toObjectVariant(JSContext *cx, JSObject *obj, ObjectVariant *objVarp) {
return WrapperOwner::toObjectVariant(cx, obj, objVarp);
}
virtual JSObject *fromObjectVariant(JSContext *cx, ObjectVariant objVar) {
return WrapperOwner::fromObjectVariant(cx, objVar);
}
};
} // namespace jsipc

View File

@ -19,29 +19,23 @@ using namespace mozilla::jsipc;
using mozilla::AutoSafeJSContext;
JavaScriptChild::JavaScriptChild(JSRuntime *rt)
: lastId_(0),
rt_(rt)
static void
FinalizeChild(JSFreeOp *fop, JSFinalizeStatus status, bool isCompartment, void *data)
{
if (status == JSFINALIZE_GROUP_START) {
static_cast<JavaScriptChild *>(data)->finalize(fop);
}
}
static void
Trace(JSTracer *trc, void *data)
JavaScriptChild::JavaScriptChild(JSRuntime *rt)
: JavaScriptShared(rt),
JavaScriptBase<PJavaScriptChild>(rt)
{
reinterpret_cast<JavaScriptChild *>(data)->trace(trc);
}
JavaScriptChild::~JavaScriptChild()
{
JS_RemoveExtraGCRootsTracer(rt_, Trace, this);
}
void
JavaScriptChild::trace(JSTracer *trc)
{
objects_.trace(trc);
cpows_.trace(trc);
ids_.trace(trc);
JS_RemoveFinalizeCallback(rt_, FinalizeChild);
}
bool
@ -52,61 +46,13 @@ JavaScriptChild::init()
if (!WrapperAnswer::init())
return false;
if (!ids_.init())
return false;
JS_AddExtraGCRootsTracer(rt_, Trace, this);
JS_AddFinalizeCallback(rt_, FinalizeChild, this);
return true;
}
bool
JavaScriptChild::RecvDropObject(const ObjectId &objId)
void
JavaScriptChild::finalize(JSFreeOp *fop)
{
JSObject *obj = findObjectById(objId);
if (obj) {
ids_.remove(obj);
objects_.remove(objId);
}
return true;
objects_.finalize(fop);
objectIds_.finalize(fop);
}
bool
JavaScriptChild::toObjectVariant(JSContext *cx, JSObject *obj, ObjectVariant *objVarp)
{
JS_ASSERT(obj);
ObjectId id = ids_.find(obj);
if (id) {
*objVarp = RemoteObject(id);
return true;
}
id = ++lastId_;
if (id > MAX_CPOW_IDS) {
JS_ReportError(cx, "CPOW id limit reached");
return false;
}
id <<= OBJECT_EXTRA_BITS;
if (JS_ObjectIsCallable(cx, obj))
id |= OBJECT_IS_CALLABLE;
if (!objects_.add(id, obj))
return false;
if (!ids_.add(cx, obj, id))
return false;
*objVarp = RemoteObject(id);
return true;
}
JSObject *
JavaScriptChild::fromObjectVariant(JSContext *cx, ObjectVariant objVar)
{
JS_ASSERT(objVar.type() == ObjectVariant::TLocalObject);
ObjectId id = objVar.get_LocalObject().id();
JSObject *obj = findObjectById(id);
MOZ_ASSERT(obj);
return obj;
}

View File

@ -18,26 +18,16 @@ class JavaScriptChild : public JavaScriptBase<PJavaScriptChild>
{
public:
JavaScriptChild(JSRuntime *rt);
~JavaScriptChild();
virtual ~JavaScriptChild();
bool init();
void trace(JSTracer *trc);
void finalize(JSFreeOp *fop);
bool RecvDropObject(const ObjectId &objId) MOZ_OVERRIDE;
virtual void drop(JSObject *obj) { MOZ_CRASH(); }
void drop(JSObject *obj);
private:
virtual bool toObjectVariant(JSContext *cx, JSObject *obj, ObjectVariant *objVarp);
virtual JSObject *fromObjectVariant(JSContext *cx, ObjectVariant objVar);
bool fail(JSContext *cx, ReturnStatus *rs);
bool ok(ReturnStatus *rs);
private:
ObjectId lastId_;
JSRuntime *rt_;
ObjectToIdMap ids_;
};
} // mozilla

View File

@ -21,20 +21,21 @@ using namespace mozilla;
using namespace mozilla::jsipc;
using namespace mozilla::dom;
JavaScriptParent::JavaScriptParent()
: refcount_(1)
static void
TraceParent(JSTracer *trc, void *data)
{
static_cast<JavaScriptParent *>(data)->trace(trc);
}
JavaScriptParent::JavaScriptParent(JSRuntime *rt)
: JavaScriptShared(rt),
JavaScriptBase<PJavaScriptParent>(rt)
{
}
void
JavaScriptParent::drop(JSObject *obj)
JavaScriptParent::~JavaScriptParent()
{
ObjectId objId = idOf(obj);
cpows_.remove(objId);
if (active() && !SendDropObject(objId))
(void)0;
decref();
JS_RemoveExtraGCRootsTracer(rt_, TraceParent, this);
}
bool
@ -43,80 +44,15 @@ JavaScriptParent::init()
if (!WrapperOwner::init())
return false;
JS_AddExtraGCRootsTracer(rt_, TraceParent, this);
return true;
}
bool
JavaScriptParent::toObjectVariant(JSContext *cx, JSObject *obj, ObjectVariant *objVarp)
{
JS_ASSERT(obj);
obj = js::CheckedUnwrap(obj, false);
if (!obj || !IsCPOW(obj)) {
JS_ReportError(cx, "cannot ipc non-cpow object");
return false;
}
*objVarp = LocalObject(idOf(obj));
return true;
}
JSObject *
JavaScriptParent::fromObjectVariant(JSContext *cx, ObjectVariant objVar)
{
JS_ASSERT(objVar.type() == ObjectVariant::TRemoteObject);
ObjectId objId = objVar.get_RemoteObject().id();
RootedObject obj(cx, findCPOWById(objId));
if (obj) {
if (!JS_WrapObject(cx, &obj))
return nullptr;
return obj;
}
if (objId > MAX_CPOW_IDS) {
JS_ReportError(cx, "unusable CPOW id");
return nullptr;
}
bool callable = !!(objId & OBJECT_IS_CALLABLE);
RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
RootedValue v(cx, UndefinedValue());
ProxyOptions options;
options.selectDefaultClass(callable);
obj = NewProxyObject(cx,
ProxyHandler(),
v,
nullptr,
global,
options);
if (!obj)
return nullptr;
if (!cpows_.add(objId, obj))
return nullptr;
// Incref once we know the decref will be called.
incref();
SetProxyExtra(obj, 0, PrivateValue(this));
SetProxyExtra(obj, 1, DoubleValue(BitwiseCast<double>(objId)));
return obj;
}
void
JavaScriptParent::decref()
JavaScriptParent::trace(JSTracer *trc)
{
refcount_--;
if (!refcount_)
delete this;
}
void
JavaScriptParent::incref()
{
refcount_++;
if (active())
objects_.trace(trc);
}
mozilla::ipc::IProtocol*

View File

@ -17,24 +17,16 @@ namespace jsipc {
class JavaScriptParent : public JavaScriptBase<PJavaScriptParent>
{
public:
JavaScriptParent();
JavaScriptParent(JSRuntime *rt);
virtual ~JavaScriptParent();
bool init();
void decref();
void incref();
void trace(JSTracer *trc);
void drop(JSObject *obj);
mozilla::ipc::IProtocol*
CloneProtocol(Channel* aChannel, ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
private:
virtual bool toObjectVariant(JSContext *cx, JSObject *obj, ObjectVariant *objVarp);
virtual JSObject *fromObjectVariant(JSContext *cx, ObjectVariant objVar);
private:
uintptr_t refcount_;
};
} // jsipc

View File

@ -38,6 +38,18 @@ IdToObjectMap::trace(JSTracer *trc)
}
}
void
IdToObjectMap::finalize(JSFreeOp *fop)
{
for (Table::Enum e(table_); !e.empty(); e.popFront()) {
DebugOnly<JSObject *> prior = e.front().value().get();
if (JS_IsAboutToBeFinalized(&e.front().value()))
e.removeFront();
else
MOZ_ASSERT(e.front().value() == prior);
}
}
JSObject *
IdToObjectMap::find(ObjectId id)
{
@ -83,12 +95,14 @@ ObjectToIdMap::init()
}
void
ObjectToIdMap::trace(JSTracer *trc)
ObjectToIdMap::finalize(JSFreeOp *fop)
{
for (Table::Range r(table_->all()); !r.empty(); r.popFront()) {
JSObject *obj = r.front().key();
JS_CallObjectTracer(trc, &obj, "ipc-id");
MOZ_ASSERT(obj == r.front().key());
for (Table::Enum e(*table_); !e.empty(); e.popFront()) {
JSObject *obj = e.front().key();
if (JS_IsAboutToBeFinalizedUnbarriered(&obj))
e.removeFront();
else
MOZ_ASSERT(obj == e.front().key());
}
}
@ -129,6 +143,13 @@ ObjectToIdMap::remove(JSObject *obj)
table_->remove(obj);
}
JavaScriptShared::JavaScriptShared(JSRuntime *rt)
: rt_(rt),
refcount_(1),
lastId_(0)
{
}
bool
JavaScriptShared::init()
{
@ -136,9 +157,26 @@ JavaScriptShared::init()
return false;
if (!cpows_.init())
return false;
if (!objectIds_.init())
return false;
return true;
}
void
JavaScriptShared::decref()
{
refcount_--;
if (!refcount_)
delete this;
}
void
JavaScriptShared::incref()
{
refcount_++;
}
bool
JavaScriptShared::convertIdToGeckoString(JSContext *cx, JS::HandleId id, nsString *to)
{
@ -318,6 +356,12 @@ JavaScriptShared::ConvertID(const JSIID &from, nsID *to)
to->m3[7] = from.m3_7();
}
void
JavaScriptShared::ReportNonexistentObject(JSContext *cx)
{
JS_ReportError(cx, "operation not possible on dead CPOW");
}
static const uint64_t DefaultPropertyOp = 1;
static const uint64_t GetterOnlyPropertyStub = 2;
static const uint64_t UnknownPropertyOp = 3;

View File

@ -48,6 +48,7 @@ class IdToObjectMap
bool init();
void trace(JSTracer *trc);
void finalize(JSFreeOp *fop);
bool add(ObjectId id, JSObject *obj);
JSObject *find(ObjectId id);
@ -68,7 +69,7 @@ class ObjectToIdMap
~ObjectToIdMap();
bool init();
void trace(JSTracer *trc);
void finalize(JSFreeOp *fop);
bool add(JSContext *cx, JSObject *obj, ObjectId id);
ObjectId find(JSObject *obj);
@ -83,8 +84,14 @@ class ObjectToIdMap
class JavaScriptShared
{
public:
JavaScriptShared(JSRuntime *rt);
virtual ~JavaScriptShared() {}
bool init();
void decref();
void incref();
static const uint32_t OBJECT_EXTRA_BITS = 1;
static const uint32_t OBJECT_IS_CALLABLE = (1 << 0);
@ -109,16 +116,30 @@ class JavaScriptShared
static void ConvertID(const nsID &from, JSIID *to);
static void ConvertID(const JSIID &from, nsID *to);
void ReportNonexistentObject(JSContext *cx);
JSObject *findCPOWById(uint32_t objId) {
return cpows_.find(objId);
}
JSObject *findObjectById(uint32_t objId) {
return objects_.find(objId);
}
JSObject *findObjectById(JSContext *cx, uint32_t objId) {
if (JSObject *result = objects_.find(objId))
return result;
ReportNonexistentObject(cx);
return nullptr;
}
protected:
JSRuntime *rt_;
uintptr_t refcount_;
IdToObjectMap objects_;
IdToObjectMap cpows_;
ObjectId lastId_;
ObjectToIdMap objectIds_;
};
// Use 47 at most, to be safe, since jsval privates are encoded as doubles.

View File

@ -18,11 +18,10 @@ intr protocol PJavaScript
{
manager PContent;
child:
// The parent process no longer holds any references to the child object.
both:
// Sent when a CPOW has been finalized and table entries can be freed up.
async DropObject(uint64_t objId);
both:
// These roughly map to the ProxyHandler hooks that CPOWs need.
rpc PreventExtensions(uint64_t objId) returns (ReturnStatus rs);
rpc GetPropertyDescriptor(uint64_t objId, nsString id) returns (ReturnStatus rs, PPropertyDescriptor result);

View File

@ -63,9 +63,9 @@ WrapperAnswer::AnswerPreventExtensions(const ObjectId &objId, ReturnStatus *rs)
AutoSafeJSContext cx;
JSAutoRequest request(cx);
RootedObject obj(cx, findObjectById(objId));
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return false;
return fail(cx, rs);
JSAutoCompartment comp(cx, obj);
if (!JS_PreventExtensions(cx, obj))
@ -93,9 +93,9 @@ WrapperAnswer::AnswerGetPropertyDescriptor(const ObjectId &objId, const nsString
EmptyDesc(out);
RootedObject obj(cx, findObjectById(objId));
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return false;
return fail(cx, rs);
JSAutoCompartment comp(cx, obj);
@ -125,9 +125,9 @@ WrapperAnswer::AnswerGetOwnPropertyDescriptor(const ObjectId &objId, const nsStr
EmptyDesc(out);
RootedObject obj(cx, findObjectById(objId));
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return false;
return fail(cx, rs);
JSAutoCompartment comp(cx, obj);
@ -155,9 +155,9 @@ WrapperAnswer::AnswerDefineProperty(const ObjectId &objId, const nsString &id,
AutoSafeJSContext cx;
JSAutoRequest request(cx);
RootedObject obj(cx, findObjectById(objId));
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return false;
return fail(cx, rs);
JSAutoCompartment comp(cx, obj);
@ -167,7 +167,7 @@ WrapperAnswer::AnswerDefineProperty(const ObjectId &objId, const nsString &id,
Rooted<JSPropertyDescriptor> desc(cx);
if (!toDescriptor(cx, descriptor, &desc))
return false;
return fail(cx, rs);
if (!js::CheckDefineProperty(cx, obj, internedId, desc.value(), desc.attributes(),
desc.getter(), desc.setter()))
@ -193,9 +193,9 @@ WrapperAnswer::AnswerDelete(const ObjectId &objId, const nsString &id, ReturnSta
*success = false;
RootedObject obj(cx, findObjectById(objId));
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return false;
return fail(cx, rs);
JSAutoCompartment comp(cx, obj);
@ -217,9 +217,9 @@ WrapperAnswer::AnswerHas(const ObjectId &objId, const nsString &id, ReturnStatus
*bp = false;
RootedObject obj(cx, findObjectById(objId));
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return false;
return fail(cx, rs);
JSAutoCompartment comp(cx, obj);
@ -243,9 +243,9 @@ WrapperAnswer::AnswerHasOwn(const ObjectId &objId, const nsString &id, ReturnSta
*bp = false;
RootedObject obj(cx, findObjectById(objId));
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return false;
return fail(cx, rs);
JSAutoCompartment comp(cx, obj);
@ -272,13 +272,13 @@ WrapperAnswer::AnswerGet(const ObjectId &objId, const ObjectId &receiverId, cons
// the parent won't read it.
*result = UndefinedVariant();
RootedObject obj(cx, findObjectById(objId));
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return false;
return fail(cx, rs);
RootedObject receiver(cx, findObjectById(receiverId));
RootedObject receiver(cx, findObjectById(cx, receiverId));
if (!receiver)
return false;
return fail(cx, rs);
JSAutoCompartment comp(cx, obj);
@ -308,13 +308,13 @@ WrapperAnswer::AnswerSet(const ObjectId &objId, const ObjectId &receiverId, cons
// the parent won't read it.
*result = UndefinedVariant();
RootedObject obj(cx, findObjectById(objId));
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return false;
return fail(cx, rs);
RootedObject receiver(cx, findObjectById(receiverId));
RootedObject receiver(cx, findObjectById(cx, receiverId));
if (!receiver)
return false;
return fail(cx, rs);
JSAutoCompartment comp(cx, obj);
@ -345,9 +345,9 @@ WrapperAnswer::AnswerIsExtensible(const ObjectId &objId, ReturnStatus *rs, bool
*result = false;
RootedObject obj(cx, findObjectById(objId));
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return false;
return fail(cx, rs);
JSAutoCompartment comp(cx, obj);
@ -370,9 +370,9 @@ WrapperAnswer::AnswerCall(const ObjectId &objId, const nsTArray<JSParam> &argv,
// the parent won't read it.
*result = UndefinedVariant();
RootedObject obj(cx, findObjectById(objId));
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return false;
return fail(cx, rs);
JSAutoCompartment comp(cx, obj);
@ -463,9 +463,12 @@ WrapperAnswer::AnswerObjectClassIs(const ObjectId &objId, const uint32_t &classV
AutoSafeJSContext cx;
JSAutoRequest request(cx);
RootedObject obj(cx, findObjectById(objId));
if (!obj)
return false;
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj) {
// This is very unfortunate, but we have no choice.
*result = false;
return true;
}
JSAutoCompartment comp(cx, obj);
@ -479,9 +482,11 @@ WrapperAnswer::AnswerClassName(const ObjectId &objId, nsString *name)
AutoSafeJSContext cx;
JSAutoRequest request(cx);
RootedObject obj(cx, findObjectById(objId));
if (!obj)
return false;
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj) {
// This is very unfortunate, but we have no choice.
return "<dead CPOW>";
}
JSAutoCompartment comp(cx, obj);
@ -496,9 +501,9 @@ WrapperAnswer::AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &fla
AutoSafeJSContext cx;
JSAutoRequest request(cx);
RootedObject obj(cx, findObjectById(objId));
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return false;
return fail(cx, rs);
JSAutoCompartment comp(cx, obj);
@ -526,9 +531,9 @@ WrapperAnswer::AnswerInstanceOf(const ObjectId &objId, const JSIID &iid, ReturnS
*instanceof = false;
RootedObject obj(cx, findObjectById(objId));
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return false;
return fail(cx, rs);
JSAutoCompartment comp(cx, obj);
@ -552,9 +557,9 @@ WrapperAnswer::AnswerDOMInstanceOf(const ObjectId &objId, const int &prototypeID
*instanceof = false;
RootedObject obj(cx, findObjectById(objId));
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return false;
return fail(cx, rs);
JSAutoCompartment comp(cx, obj);

View File

@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WrapperOwner.h"
#include "mozilla/unused.h"
#include "mozilla/dom/BindingUtils.h"
#include "jsfriendapi.h"
#include "xpcprivate.h"
@ -15,8 +16,9 @@ using namespace JS;
using namespace mozilla;
using namespace mozilla::jsipc;
WrapperOwner::WrapperOwner()
: inactive_(false)
WrapperOwner::WrapperOwner(JSRuntime *rt)
: JavaScriptShared(rt),
inactive_(false)
{
}
@ -86,12 +88,6 @@ class CPOWProxyHandler : public BaseProxyHandler
CPOWProxyHandler CPOWProxyHandler::singleton;
/* static */ BaseProxyHandler *
WrapperOwner::ProxyHandler()
{
return &CPOWProxyHandler::singleton;
}
#define FORWARD(call, args) \
WrapperOwner *owner = OwnerOf(proxy); \
if (!owner->active()) { \
@ -504,6 +500,17 @@ CPOWProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy)
OwnerOf(proxy)->drop(proxy);
}
void
WrapperOwner::drop(JSObject *obj)
{
ObjectId objId = idOf(obj);
cpows_.remove(objId);
if (active())
unused << SendDropObject(objId);
decref();
}
bool
WrapperOwner::init()
{
@ -622,3 +629,104 @@ WrapperOwner::ok(JSContext *cx, const ReturnStatus &status)
JS_SetPendingException(cx, exn);
return false;
}
bool
WrapperOwner::toObjectVariant(JSContext *cx, JSObject *obj, ObjectVariant *objVarp)
{
JS_ASSERT(obj);
JSObject *unwrapped = js::CheckedUnwrap(obj, false);
if (unwrapped && IsCPOW(unwrapped) && OwnerOf(unwrapped) == this) {
*objVarp = LocalObject(idOf(unwrapped));
return true;
}
ObjectId id = objectIds_.find(obj);
if (id) {
*objVarp = RemoteObject(id);
return true;
}
id = ++lastId_;
if (id > MAX_CPOW_IDS) {
JS_ReportError(cx, "CPOW id limit reached");
return false;
}
id <<= OBJECT_EXTRA_BITS;
if (JS_ObjectIsCallable(cx, obj))
id |= OBJECT_IS_CALLABLE;
if (!objects_.add(id, obj))
return false;
if (!objectIds_.add(cx, obj, id))
return false;
*objVarp = RemoteObject(id);
return true;
}
JSObject *
WrapperOwner::fromObjectVariant(JSContext *cx, ObjectVariant objVar)
{
if (objVar.type() == ObjectVariant::TRemoteObject) {
return fromRemoteObjectVariant(cx, objVar.get_RemoteObject());
} else {
return fromLocalObjectVariant(cx, objVar.get_LocalObject());
}
}
JSObject *
WrapperOwner::fromRemoteObjectVariant(JSContext *cx, RemoteObject objVar)
{
ObjectId objId = objVar.id();
RootedObject obj(cx, findCPOWById(objId));
if (obj) {
if (!JS_WrapObject(cx, &obj))
return nullptr;
return obj;
}
if (objId > MAX_CPOW_IDS) {
JS_ReportError(cx, "unusable CPOW id");
return nullptr;
}
bool callable = !!(objId & OBJECT_IS_CALLABLE);
RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
RootedValue v(cx, UndefinedValue());
ProxyOptions options;
options.selectDefaultClass(callable);
obj = NewProxyObject(cx,
&CPOWProxyHandler::singleton,
v,
nullptr,
global,
options);
if (!obj)
return nullptr;
if (!cpows_.add(objId, obj))
return nullptr;
// Incref once we know the decref will be called.
incref();
SetProxyExtra(obj, 0, PrivateValue(this));
SetProxyExtra(obj, 1, DoubleValue(BitwiseCast<double>(objId)));
return obj;
}
JSObject *
WrapperOwner::fromLocalObjectVariant(JSContext *cx, LocalObject objVar)
{
ObjectId id = objVar.id();
Rooted<JSObject*> obj(cx, findObjectById(cx, id));
if (!obj)
return nullptr;
if (!JS_WrapObject(cx, &obj))
return nullptr;
return obj;
}

View File

@ -17,10 +17,6 @@
#undef GetClassInfo
#endif
namespace js {
class BaseProxyHandler;
} // js
namespace mozilla {
namespace jsipc {
@ -31,7 +27,7 @@ class WrapperOwner : public virtual JavaScriptShared
mozilla::ipc::IProtocol>::ActorDestroyReason
ActorDestroyReason;
WrapperOwner();
WrapperOwner(JSRuntime *rt);
bool init();
// Fundamental proxy traps. These are required.
@ -73,15 +69,18 @@ class WrapperOwner : public virtual JavaScriptShared
bool active() { return !inactive_; }
virtual void drop(JSObject *obj) = 0;
void drop(JSObject *obj);
virtual void ActorDestroy(ActorDestroyReason why);
virtual bool toObjectVariant(JSContext *cx, JSObject *obj, ObjectVariant *objVarp);
virtual JSObject *fromObjectVariant(JSContext *cx, ObjectVariant objVar);
JSObject *fromRemoteObjectVariant(JSContext *cx, RemoteObject objVar);
JSObject *fromLocalObjectVariant(JSContext *cx, LocalObject objVar);
protected:
ObjectId idOf(JSObject *obj);
static js::BaseProxyHandler *ProxyHandler();
private:
bool getPropertyNames(JSContext *cx, JS::HandleObject proxy, uint32_t flags,
JS::AutoIdVector &props);
@ -96,6 +95,7 @@ class WrapperOwner : public virtual JavaScriptShared
/*** Dummy call handlers ***/
public:
virtual bool SendDropObject(const ObjectId &objId) = 0;
virtual bool CallPreventExtensions(const ObjectId &objId, ReturnStatus *rs) = 0;
virtual bool CallGetPropertyDescriptor(const ObjectId &objId, const nsString &id,
ReturnStatus *rs,

View File

@ -1625,7 +1625,6 @@ JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
JS_PUBLIC_API(void)
JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
{
AssertHeapIsIdle(rt);
for (size_t i = 0; i < rt->gc.blackRootTracers.length(); i++) {
Callback<JSTraceDataOp> *e = &rt->gc.blackRootTracers[i];
if (e->op == traceOp && e->data == data) {