mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 996785 - Bidirectional CPOWs (r=mrbkap)
This commit is contained in:
parent
ef7051c241
commit
07f15166ed
@ -899,7 +899,7 @@ ContentChild::AllocPJavaScriptChild()
|
||||
bool
|
||||
ContentChild::DeallocPJavaScriptChild(PJavaScriptChild *child)
|
||||
{
|
||||
delete child;
|
||||
static_cast<mozilla::jsipc::JavaScriptChild *>(child)->decref();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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*
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user