Bug 996785 - Move CPOW wrapper owner code (r=mrbkap)

This commit is contained in:
Bill McCloskey
2014-05-16 16:40:36 -07:00
parent 9af6eef5a8
commit a6ad990683
6 changed files with 888 additions and 666 deletions

103
js/ipc/JavaScriptBase.h Normal file
View File

@@ -0,0 +1,103 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=80:
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_jsipc_JavaScriptBase_h__
#define mozilla_jsipc_JavaScriptBase_h__
#include "WrapperOwner.h"
#include "mozilla/dom/DOMTypes.h"
#include "mozilla/jsipc/PJavaScript.h"
namespace mozilla {
namespace jsipc {
template<class Base>
class JavaScriptBase : public WrapperOwner, public Base
{
typedef WrapperOwner Shared;
public:
/*** Dummy call handlers ***/
bool CallPreventExtensions(const ObjectId &objId, ReturnStatus *rs) {
return Base::CallPreventExtensions(objId, rs);
}
bool CallGetPropertyDescriptor(const ObjectId &objId, const nsString &id,
ReturnStatus *rs,
PPropertyDescriptor *out) {
return Base::CallGetPropertyDescriptor(objId, id, rs, out);
}
bool CallGetOwnPropertyDescriptor(const ObjectId &objId,
const nsString &id,
ReturnStatus *rs,
PPropertyDescriptor *out) {
return Base::CallGetOwnPropertyDescriptor(objId, id, rs, out);
}
bool CallDefineProperty(const ObjectId &objId, const nsString &id,
const PPropertyDescriptor &flags,
ReturnStatus *rs) {
return Base::CallDefineProperty(objId, id, flags, rs);
}
bool CallDelete(const ObjectId &objId, const nsString &id,
ReturnStatus *rs, bool *success) {
return Base::CallDelete(objId, id, rs, success);
}
bool CallHas(const ObjectId &objId, const nsString &id,
ReturnStatus *rs, bool *bp) {
return Base::CallHas(objId, id, rs, bp);
}
bool CallHasOwn(const ObjectId &objId, const nsString &id,
ReturnStatus *rs, bool *bp) {
return Base::CallHasOwn(objId, id, rs, bp);
}
bool CallGet(const ObjectId &objId, const ObjectId &receiverId,
const nsString &id,
ReturnStatus *rs, JSVariant *result) {
return Base::CallGet(objId, receiverId, id, rs, result);
}
bool CallSet(const ObjectId &objId, const ObjectId &receiverId,
const nsString &id, const bool &strict,
const JSVariant &value, ReturnStatus *rs, JSVariant *result) {
return Base::CallSet(objId, receiverId, id, strict, value, rs, result);
}
bool CallIsExtensible(const ObjectId &objId, ReturnStatus *rs,
bool *result) {
return Base::CallIsExtensible(objId, rs, result);
}
bool CallCall(const ObjectId &objId, const nsTArray<JSParam> &argv,
ReturnStatus *rs, JSVariant *result,
nsTArray<JSParam> *outparams) {
return Base::CallCall(objId, argv, rs, result, outparams);
}
bool CallObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
bool *result) {
return Base::CallObjectClassIs(objId, classValue, result);
}
bool CallClassName(const ObjectId &objId, nsString *result) {
return Base::CallClassName(objId, result);
}
bool CallGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
ReturnStatus *rs, nsTArray<nsString> *names) {
return Base::CallGetPropertyNames(objId, flags, rs, names);
}
bool CallInstanceOf(const ObjectId &objId, const JSIID &iid,
ReturnStatus *rs, bool *instanceof) {
return Base::CallInstanceOf(objId, iid, rs, instanceof);
}
bool CallDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
ReturnStatus *rs, bool *instanceof) {
return Base::CallDOMInstanceOf(objId, prototypeID, depth, rs, instanceof);
}
};
} // namespace jsipc
} // namespace mozilla
#endif

View File

@@ -22,496 +22,17 @@ using namespace mozilla::jsipc;
using namespace mozilla::dom; using namespace mozilla::dom;
JavaScriptParent::JavaScriptParent() JavaScriptParent::JavaScriptParent()
: refcount_(1), : refcount_(1)
inactive_(false)
{ {
} }
static inline JavaScriptParent *
ParentOf(JSObject *obj)
{
MOZ_ASSERT(IsCPOW(obj));
return reinterpret_cast<JavaScriptParent *>(GetProxyExtra(obj, 0).toPrivate());
}
ObjectId
JavaScriptParent::idOf(JSObject *obj)
{
MOZ_ASSERT(IsCPOW(obj));
Value v = GetProxyExtra(obj, 1);
MOZ_ASSERT(v.isDouble());
ObjectId objId = BitwiseCast<uint64_t>(v.toDouble());
MOZ_ASSERT(findCPOWById(objId) == obj);
MOZ_ASSERT(objId);
return objId;
}
int sCPOWProxyHandler;
class CPOWProxyHandler : public BaseProxyHandler
{
public:
CPOWProxyHandler()
: BaseProxyHandler(&sCPOWProxyHandler) {}
virtual ~CPOWProxyHandler() {}
virtual bool finalizeInBackground(Value priv) MOZ_OVERRIDE {
return false;
}
virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
AutoIdVector &props) MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp) MOZ_OVERRIDE;
virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp) MOZ_OVERRIDE;
virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
virtual bool objectClassIs(HandleObject obj, js::ESClassValue classValue, JSContext *cx) MOZ_OVERRIDE;
virtual const char* className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
virtual void finalize(JSFreeOp *fop, JSObject *proxy) MOZ_OVERRIDE;
static CPOWProxyHandler singleton;
};
CPOWProxyHandler CPOWProxyHandler::singleton;
#define FORWARD(call, args) \
JavaScriptParent *parent = ParentOf(proxy); \
if (!parent->active()) { \
JS_ReportError(cx, "cannot use a CPOW whose process is gone"); \
return false; \
} \
return parent->call args;
bool
CPOWProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy)
{
FORWARD(preventExtensions, (cx, proxy));
}
bool
JavaScriptParent::preventExtensions(JSContext *cx, HandleObject proxy)
{
ObjectId objId = idOf(proxy);
ReturnStatus status;
if (!CallPreventExtensions(objId, &status))
return ipcfail(cx);
return ok(cx, status);
}
bool
CPOWProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc)
{
FORWARD(getPropertyDescriptor, (cx, proxy, id, desc));
}
bool
JavaScriptParent::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc)
{
ObjectId objId = idOf(proxy);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
ReturnStatus status;
PPropertyDescriptor result;
if (!CallGetPropertyDescriptor(objId, idstr, &status, &result))
return ipcfail(cx);
if (!ok(cx, status))
return false;
return toDescriptor(cx, result, desc);
}
bool
CPOWProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
HandleId id, MutableHandle<JSPropertyDescriptor> desc)
{
FORWARD(getOwnPropertyDescriptor, (cx, proxy, id, desc));
}
bool
JavaScriptParent::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc)
{
ObjectId objId = idOf(proxy);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
ReturnStatus status;
PPropertyDescriptor result;
if (!CallGetOwnPropertyDescriptor(objId, idstr, &status, &result))
return ipcfail(cx);
if (!ok(cx, status))
return false;
return toDescriptor(cx, result, desc);
}
bool
CPOWProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc)
{
FORWARD(defineProperty, (cx, proxy, id, desc));
}
bool
JavaScriptParent::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc)
{
ObjectId objId = idOf(proxy);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
PPropertyDescriptor descriptor;
if (!fromDescriptor(cx, desc, &descriptor))
return false;
ReturnStatus status;
if (!CallDefineProperty(objId, idstr, descriptor, &status))
return ipcfail(cx);
return ok(cx, status);
}
bool
CPOWProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
FORWARD(getOwnPropertyNames, (cx, proxy, props));
}
bool
JavaScriptParent::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
return getPropertyNames(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN, props);
}
bool
CPOWProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
FORWARD(delete_, (cx, proxy, id, bp));
}
bool
JavaScriptParent::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
ObjectId objId = idOf(proxy);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
ReturnStatus status;
if (!CallDelete(objId, idstr, &status, bp))
return ipcfail(cx);
return ok(cx, status);
}
bool
CPOWProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
FORWARD(enumerate, (cx, proxy, props));
}
bool
JavaScriptParent::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
return getPropertyNames(cx, proxy, 0, props);
}
bool
CPOWProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
FORWARD(has, (cx, proxy, id, bp));
}
bool
JavaScriptParent::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
ObjectId objId = idOf(proxy);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
ReturnStatus status;
if (!CallHas(objId, idstr, &status, bp))
return ipcfail(cx);
return ok(cx, status);
}
bool
CPOWProxyHandler::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
FORWARD(hasOwn, (cx, proxy, id, bp));
}
bool
JavaScriptParent::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
ObjectId objId = idOf(proxy);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
ReturnStatus status;
if (!CallHasOwn(objId, idstr, &status, bp))
return ipcfail(cx);
return !!ok(cx, status);
}
bool
CPOWProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp)
{
FORWARD(get, (cx, proxy, receiver, id, vp));
}
bool
JavaScriptParent::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp)
{
ObjectId objId = idOf(proxy);
ObjectId receiverId = idOf(receiver);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
JSVariant val;
ReturnStatus status;
if (!CallGet(objId, receiverId, idstr, &status, &val))
return ipcfail(cx);
if (!ok(cx, status))
return false;
return fromVariant(cx, val, vp);
}
bool
CPOWProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp)
{
FORWARD(set, (cx, proxy, receiver, id, strict, vp));
}
bool
JavaScriptParent::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp)
{
ObjectId objId = idOf(proxy);
ObjectId receiverId = idOf(receiver);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
JSVariant val;
if (!toVariant(cx, vp, &val))
return false;
ReturnStatus status;
JSVariant result;
if (!CallSet(objId, receiverId, idstr, strict, val, &status, &result))
return ipcfail(cx);
if (!ok(cx, status))
return false;
return fromVariant(cx, result, vp);
}
bool
CPOWProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
FORWARD(keys, (cx, proxy, props));
}
bool
JavaScriptParent::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
return getPropertyNames(cx, proxy, JSITER_OWNONLY, props);
}
bool
CPOWProxyHandler::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
{
FORWARD(isExtensible, (cx, proxy, extensible));
}
bool
JavaScriptParent::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
{
ObjectId objId = idOf(proxy);
ReturnStatus status;
if (!CallIsExtensible(objId, &status, extensible))
return ipcfail(cx);
return ok(cx, status);
}
bool
CPOWProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
{
FORWARD(call, (cx, proxy, args));
}
bool
JavaScriptParent::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
{
ObjectId objId = idOf(proxy);
InfallibleTArray<JSParam> vals;
AutoValueVector outobjects(cx);
RootedValue v(cx);
for (size_t i = 0; i < args.length() + 2; i++) {
v = args.base()[i];
if (v.isObject()) {
RootedObject obj(cx, &v.toObject());
if (xpc::IsOutObject(cx, obj)) {
// Make sure it is not an in-out object.
bool found;
if (!JS_HasProperty(cx, obj, "value", &found))
return false;
if (found) {
JS_ReportError(cx, "in-out objects cannot be sent via CPOWs yet");
return false;
}
vals.AppendElement(JSParam(void_t()));
if (!outobjects.append(ObjectValue(*obj)))
return false;
continue;
}
}
JSVariant val;
if (!toVariant(cx, v, &val))
return false;
vals.AppendElement(JSParam(val));
}
JSVariant result;
ReturnStatus status;
InfallibleTArray<JSParam> outparams;
if (!CallCall(objId, vals, &status, &result, &outparams))
return ipcfail(cx);
if (!ok(cx, status))
return false;
if (outparams.Length() != outobjects.length())
return ipcfail(cx);
RootedObject obj(cx);
for (size_t i = 0; i < outparams.Length(); i++) {
// Don't bother doing anything for outparams that weren't set.
if (outparams[i].type() == JSParam::Tvoid_t)
continue;
// Take the value the child process returned, and set it on the XPC
// object.
if (!fromVariant(cx, outparams[i], &v))
return false;
obj = &outobjects[i].toObject();
if (!JS_SetProperty(cx, obj, "value", v))
return false;
}
if (!fromVariant(cx, result, args.rval()))
return false;
return true;
}
bool
CPOWProxyHandler::objectClassIs(HandleObject proxy, js::ESClassValue classValue, JSContext *cx)
{
FORWARD(objectClassIs, (cx, proxy, classValue));
}
bool
JavaScriptParent::objectClassIs(JSContext *cx, HandleObject proxy, js::ESClassValue classValue)
{
ObjectId objId = idOf(proxy);
// This function is assumed infallible, so we just return false if the IPC
// channel fails.
bool result;
if (!CallObjectClassIs(objId, classValue, &result))
return false;
return result;
}
const char *
CPOWProxyHandler::className(JSContext *cx, HandleObject proxy)
{
JavaScriptParent *parent = ParentOf(proxy);
if (!parent->active())
return "<dead CPOW>";
return parent->className(cx, proxy);
}
const char *
JavaScriptParent::className(JSContext *cx, HandleObject proxy)
{
ObjectId objId = idOf(proxy);
nsString name;
if (!CallClassName(objId, &name))
return "<error>";
return ToNewCString(name);
}
void
CPOWProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy)
{
ParentOf(proxy)->drop(proxy);
}
void void
JavaScriptParent::drop(JSObject *obj) JavaScriptParent::drop(JSObject *obj)
{ {
ObjectId objId = idOf(obj); ObjectId objId = idOf(obj);
cpows_.remove(objId); cpows_.remove(objId);
if (!inactive_ && !SendDropObject(objId)) if (active() && !SendDropObject(objId))
(void)0; (void)0;
decref(); decref();
} }
@@ -519,7 +40,7 @@ JavaScriptParent::drop(JSObject *obj)
bool bool
JavaScriptParent::init() JavaScriptParent::init()
{ {
if (!JavaScriptShared::init()) if (!WrapperOwner::init())
return false; return false;
return true; return true;
@@ -529,7 +50,7 @@ bool
JavaScriptParent::toId(JSContext *cx, JSObject *obj, ObjectId *idp) JavaScriptParent::toId(JSContext *cx, JSObject *obj, ObjectId *idp)
{ {
obj = js::CheckedUnwrap(obj, false); obj = js::CheckedUnwrap(obj, false);
if (!obj || !IsProxy(obj) || GetProxyHandler(obj) != &CPOWProxyHandler::singleton) { if (!obj || !IsCPOW(obj)) {
JS_ReportError(cx, "cannot ipc non-cpow object"); JS_ReportError(cx, "cannot ipc non-cpow object");
return false; return false;
} }
@@ -538,29 +59,6 @@ JavaScriptParent::toId(JSContext *cx, JSObject *obj, ObjectId *idp)
return true; return true;
} }
bool
JavaScriptParent::getPropertyNames(JSContext *cx, HandleObject proxy, uint32_t flags, AutoIdVector &props)
{
ObjectId objId = idOf(proxy);
ReturnStatus status;
InfallibleTArray<nsString> names;
if (!CallGetPropertyNames(objId, flags, &status, &names))
return ipcfail(cx);
if (!ok(cx, status))
return false;
for (size_t i = 0; i < names.Length(); i++) {
RootedId name(cx);
if (!convertGeckoStringToId(cx, names[i], &name))
return false;
if (!props.append(name))
return false;
}
return true;
}
JSObject * JSObject *
JavaScriptParent::fromId(JSContext *cx, ObjectId objId) JavaScriptParent::fromId(JSContext *cx, ObjectId objId)
{ {
@@ -584,7 +82,7 @@ JavaScriptParent::fromId(JSContext *cx, ObjectId objId)
ProxyOptions options; ProxyOptions options;
options.selectDefaultClass(callable); options.selectDefaultClass(callable);
obj = NewProxyObject(cx, obj = NewProxyObject(cx,
&CPOWProxyHandler::singleton, ProxyHandler(),
v, v,
nullptr, nullptr,
global, global,
@@ -603,30 +101,6 @@ JavaScriptParent::fromId(JSContext *cx, ObjectId objId)
return obj; return obj;
} }
bool
JavaScriptParent::ipcfail(JSContext *cx)
{
JS_ReportError(cx, "child process crashed or timedout");
return false;
}
bool
JavaScriptParent::ok(JSContext *cx, const ReturnStatus &status)
{
if (status.type() == ReturnStatus::TReturnSuccess)
return true;
if (status.type() == ReturnStatus::TReturnStopIteration)
return JS_ThrowStopIteration(cx);
RootedValue exn(cx);
if (!fromVariant(cx, status.get_ReturnException().exn(), &exn))
return false;
JS_SetPendingException(cx, exn);
return false;
}
void void
JavaScriptParent::decref() JavaScriptParent::decref()
{ {
@@ -641,69 +115,6 @@ JavaScriptParent::incref()
refcount_++; refcount_++;
} }
void
JavaScriptParent::ActorDestroy(ActorDestroyReason why)
{
inactive_ = true;
}
namespace mozilla {
namespace jsipc {
bool
IsCPOW(JSObject *obj)
{
return IsProxy(obj) && GetProxyHandler(obj) == &CPOWProxyHandler::singleton;
}
nsresult
InstanceOf(JSObject *proxy, const nsID *id, bool *bp)
{
JavaScriptParent *parent = ParentOf(proxy);
if (!parent->active())
return NS_ERROR_UNEXPECTED;
return parent->instanceOf(proxy, id, bp);
}
bool
DOMInstanceOf(JSContext *cx, JSObject *proxy, int prototypeID, int depth, bool *bp)
{
FORWARD(domInstanceOf, (cx, proxy, prototypeID, depth, bp));
}
} /* namespace jsipc */
} /* namespace mozilla */
nsresult
JavaScriptParent::instanceOf(JSObject *obj, const nsID *id, bool *bp)
{
ObjectId objId = idOf(obj);
JSIID iid;
ConvertID(*id, &iid);
ReturnStatus status;
if (!CallInstanceOf(objId, iid, &status, bp))
return NS_ERROR_UNEXPECTED;
if (status.type() != ReturnStatus::TReturnSuccess)
return NS_ERROR_UNEXPECTED;
return NS_OK;
}
bool
JavaScriptParent::domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp)
{
ObjectId objId = idOf(obj);
ReturnStatus status;
if (!CallDOMInstanceOf(objId, prototypeID, depth, &status, bp))
return ipcfail(cx);
return ok(cx, status);
}
mozilla::ipc::IProtocol* mozilla::ipc::IProtocol*
JavaScriptParent::CloneProtocol(Channel* aChannel, ProtocolCloneContext* aCtx) JavaScriptParent::CloneProtocol(Channel* aChannel, ProtocolCloneContext* aCtx)
{ {

View File

@@ -8,74 +8,24 @@
#ifndef mozilla_jsipc_JavaScriptParent__ #ifndef mozilla_jsipc_JavaScriptParent__
#define mozilla_jsipc_JavaScriptParent__ #define mozilla_jsipc_JavaScriptParent__
#include "JavaScriptShared.h" #include "JavaScriptBase.h"
#include "mozilla/jsipc/PJavaScriptParent.h" #include "mozilla/jsipc/PJavaScriptParent.h"
#include "js/Class.h"
#ifdef XP_WIN
#undef GetClassName
#undef GetClassInfo
#endif
namespace mozilla { namespace mozilla {
namespace jsipc { namespace jsipc {
class JavaScriptParent class JavaScriptParent : public JavaScriptBase<PJavaScriptParent>
: public PJavaScriptParent,
public JavaScriptShared
{ {
public: public:
JavaScriptParent(); JavaScriptParent();
bool init(); bool init();
public:
// Fundamental proxy traps. These are required.
// (The traps should be in the same order like js/src/jsproxy.h)
bool preventExtensions(JSContext *cx, JS::HandleObject proxy);
bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc);
bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc);
bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc);
bool getOwnPropertyNames(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
bool enumerate(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
// Derived proxy traps. Implementing these is useful for perfomance.
bool has(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
bool hasOwn(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, JS::MutableHandleValue vp);
bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp);
bool keys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
// We use "iterate" provided by the base class here.
// SpiderMonkey Extensions.
bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
bool call(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args);
bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
const char* className(JSContext *cx, JS::HandleObject proxy);
virtual void ActorDestroy(ActorDestroyReason why);
void decref(); void decref();
void incref(); void incref();
bool active() { return !inactive_; }
void drop(JSObject *obj); void drop(JSObject *obj);
nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
/*
* Check that |obj| is a DOM wrapper whose prototype chain contains
* |prototypeID| at depth |depth|.
*/
bool domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp);
mozilla::ipc::IProtocol* mozilla::ipc::IProtocol*
CloneProtocol(Channel* aChannel, ProtocolCloneContext* aCtx) MOZ_OVERRIDE; CloneProtocol(Channel* aChannel, ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
@@ -83,30 +33,10 @@ class JavaScriptParent
JSObject *fromId(JSContext *cx, ObjectId objId); JSObject *fromId(JSContext *cx, ObjectId objId);
bool toId(JSContext *cx, JSObject *obj, ObjectId *idp); bool toId(JSContext *cx, JSObject *obj, ObjectId *idp);
bool getPropertyNames(JSContext *cx, JS::HandleObject proxy, uint32_t flags,
JS::AutoIdVector &props);
ObjectId idOf(JSObject *obj);
// Catastrophic IPC failure.
bool ipcfail(JSContext *cx);
// Check whether a return status is okay, and if not, propagate its error.
bool ok(JSContext *cx, const ReturnStatus &status);
private: private:
uintptr_t refcount_; uintptr_t refcount_;
bool inactive_;
}; };
bool
IsCPOW(JSObject *obj);
nsresult
InstanceOf(JSObject *obj, const nsID *id, bool *bp);
bool
DOMInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp);
} // jsipc } // jsipc
} // mozilla } // mozilla

624
js/ipc/WrapperOwner.cpp Normal file
View File

@@ -0,0 +1,624 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=80:
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WrapperOwner.h"
#include "mozilla/dom/BindingUtils.h"
#include "jsfriendapi.h"
#include "xpcprivate.h"
using namespace js;
using namespace JS;
using namespace mozilla;
using namespace mozilla::jsipc;
WrapperOwner::WrapperOwner()
: inactive_(false)
{
}
static inline WrapperOwner *
OwnerOf(JSObject *obj)
{
MOZ_ASSERT(IsCPOW(obj));
return reinterpret_cast<WrapperOwner *>(GetProxyExtra(obj, 0).toPrivate());
}
ObjectId
WrapperOwner::idOf(JSObject *obj)
{
MOZ_ASSERT(IsCPOW(obj));
Value v = GetProxyExtra(obj, 1);
MOZ_ASSERT(v.isDouble());
ObjectId objId = BitwiseCast<uint64_t>(v.toDouble());
MOZ_ASSERT(findCPOWById(objId) == obj);
MOZ_ASSERT(objId);
return objId;
}
int sCPOWProxyHandler;
class CPOWProxyHandler : public BaseProxyHandler
{
public:
CPOWProxyHandler()
: BaseProxyHandler(&sCPOWProxyHandler) {}
virtual ~CPOWProxyHandler() {}
virtual bool finalizeInBackground(Value priv) MOZ_OVERRIDE {
return false;
}
virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
AutoIdVector &props) MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp) MOZ_OVERRIDE;
virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp) MOZ_OVERRIDE;
virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
virtual bool objectClassIs(HandleObject obj, js::ESClassValue classValue, JSContext *cx) MOZ_OVERRIDE;
virtual const char* className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
virtual void finalize(JSFreeOp *fop, JSObject *proxy) MOZ_OVERRIDE;
static CPOWProxyHandler singleton;
};
CPOWProxyHandler CPOWProxyHandler::singleton;
/* static */ BaseProxyHandler *
WrapperOwner::ProxyHandler()
{
return &CPOWProxyHandler::singleton;
}
#define FORWARD(call, args) \
WrapperOwner *owner = OwnerOf(proxy); \
if (!owner->active()) { \
JS_ReportError(cx, "cannot use a CPOW whose process is gone"); \
return false; \
} \
return owner->call args;
bool
CPOWProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy)
{
FORWARD(preventExtensions, (cx, proxy));
}
bool
WrapperOwner::preventExtensions(JSContext *cx, HandleObject proxy)
{
ObjectId objId = idOf(proxy);
ReturnStatus status;
if (!CallPreventExtensions(objId, &status))
return ipcfail(cx);
return ok(cx, status);
}
bool
CPOWProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc)
{
FORWARD(getPropertyDescriptor, (cx, proxy, id, desc));
}
bool
WrapperOwner::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc)
{
ObjectId objId = idOf(proxy);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
ReturnStatus status;
PPropertyDescriptor result;
if (!CallGetPropertyDescriptor(objId, idstr, &status, &result))
return ipcfail(cx);
if (!ok(cx, status))
return false;
return toDescriptor(cx, result, desc);
}
bool
CPOWProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc)
{
FORWARD(getOwnPropertyDescriptor, (cx, proxy, id, desc));
}
bool
WrapperOwner::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc)
{
ObjectId objId = idOf(proxy);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
ReturnStatus status;
PPropertyDescriptor result;
if (!CallGetOwnPropertyDescriptor(objId, idstr, &status, &result))
return ipcfail(cx);
if (!ok(cx, status))
return false;
return toDescriptor(cx, result, desc);
}
bool
CPOWProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc)
{
FORWARD(defineProperty, (cx, proxy, id, desc));
}
bool
WrapperOwner::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc)
{
ObjectId objId = idOf(proxy);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
PPropertyDescriptor descriptor;
if (!fromDescriptor(cx, desc, &descriptor))
return false;
ReturnStatus status;
if (!CallDefineProperty(objId, idstr, descriptor, &status))
return ipcfail(cx);
return ok(cx, status);
}
bool
CPOWProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
FORWARD(getOwnPropertyNames, (cx, proxy, props));
}
bool
WrapperOwner::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
return getPropertyNames(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN, props);
}
bool
CPOWProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
FORWARD(delete_, (cx, proxy, id, bp));
}
bool
WrapperOwner::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
ObjectId objId = idOf(proxy);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
ReturnStatus status;
if (!CallDelete(objId, idstr, &status, bp))
return ipcfail(cx);
return ok(cx, status);
}
bool
CPOWProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
FORWARD(enumerate, (cx, proxy, props));
}
bool
WrapperOwner::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
return getPropertyNames(cx, proxy, 0, props);
}
bool
CPOWProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
FORWARD(has, (cx, proxy, id, bp));
}
bool
WrapperOwner::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
ObjectId objId = idOf(proxy);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
ReturnStatus status;
if (!CallHas(objId, idstr, &status, bp))
return ipcfail(cx);
return ok(cx, status);
}
bool
CPOWProxyHandler::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
FORWARD(hasOwn, (cx, proxy, id, bp));
}
bool
WrapperOwner::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
ObjectId objId = idOf(proxy);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
ReturnStatus status;
if (!CallHasOwn(objId, idstr, &status, bp))
return ipcfail(cx);
return !!ok(cx, status);
}
bool
CPOWProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp)
{
FORWARD(get, (cx, proxy, receiver, id, vp));
}
bool
WrapperOwner::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp)
{
ObjectId objId = idOf(proxy);
ObjectId receiverId = idOf(receiver);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
JSVariant val;
ReturnStatus status;
if (!CallGet(objId, receiverId, idstr, &status, &val))
return ipcfail(cx);
if (!ok(cx, status))
return false;
return fromVariant(cx, val, vp);
}
bool
CPOWProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp)
{
FORWARD(set, (cx, proxy, receiver, id, strict, vp));
}
bool
WrapperOwner::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp)
{
ObjectId objId = idOf(proxy);
ObjectId receiverId = idOf(receiver);
nsString idstr;
if (!convertIdToGeckoString(cx, id, &idstr))
return false;
JSVariant val;
if (!toVariant(cx, vp, &val))
return false;
ReturnStatus status;
JSVariant result;
if (!CallSet(objId, receiverId, idstr, strict, val, &status, &result))
return ipcfail(cx);
if (!ok(cx, status))
return false;
return fromVariant(cx, result, vp);
}
bool
CPOWProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
FORWARD(keys, (cx, proxy, props));
}
bool
WrapperOwner::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
return getPropertyNames(cx, proxy, JSITER_OWNONLY, props);
}
bool
CPOWProxyHandler::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
{
FORWARD(isExtensible, (cx, proxy, extensible));
}
bool
WrapperOwner::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
{
ObjectId objId = idOf(proxy);
ReturnStatus status;
if (!CallIsExtensible(objId, &status, extensible))
return ipcfail(cx);
return ok(cx, status);
}
bool
CPOWProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
{
FORWARD(call, (cx, proxy, args));
}
bool
WrapperOwner::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
{
ObjectId objId = idOf(proxy);
InfallibleTArray<JSParam> vals;
AutoValueVector outobjects(cx);
RootedValue v(cx);
for (size_t i = 0; i < args.length() + 2; i++) {
v = args.base()[i];
if (v.isObject()) {
RootedObject obj(cx, &v.toObject());
if (xpc::IsOutObject(cx, obj)) {
// Make sure it is not an in-out object.
bool found;
if (!JS_HasProperty(cx, obj, "value", &found))
return false;
if (found) {
JS_ReportError(cx, "in-out objects cannot be sent via CPOWs yet");
return false;
}
vals.AppendElement(JSParam(void_t()));
if (!outobjects.append(ObjectValue(*obj)))
return false;
continue;
}
}
JSVariant val;
if (!toVariant(cx, v, &val))
return false;
vals.AppendElement(JSParam(val));
}
JSVariant result;
ReturnStatus status;
InfallibleTArray<JSParam> outparams;
if (!CallCall(objId, vals, &status, &result, &outparams))
return ipcfail(cx);
if (!ok(cx, status))
return false;
if (outparams.Length() != outobjects.length())
return ipcfail(cx);
RootedObject obj(cx);
for (size_t i = 0; i < outparams.Length(); i++) {
// Don't bother doing anything for outparams that weren't set.
if (outparams[i].type() == JSParam::Tvoid_t)
continue;
// Take the value the child process returned, and set it on the XPC
// object.
if (!fromVariant(cx, outparams[i], &v))
return false;
obj = &outobjects[i].toObject();
if (!JS_SetProperty(cx, obj, "value", v))
return false;
}
if (!fromVariant(cx, result, args.rval()))
return false;
return true;
}
bool
CPOWProxyHandler::objectClassIs(HandleObject proxy, js::ESClassValue classValue, JSContext *cx)
{
FORWARD(objectClassIs, (cx, proxy, classValue));
}
bool
WrapperOwner::objectClassIs(JSContext *cx, HandleObject proxy, js::ESClassValue classValue)
{
ObjectId objId = idOf(proxy);
// This function is assumed infallible, so we just return false if the IPC
// channel fails.
bool result;
if (!CallObjectClassIs(objId, classValue, &result))
return false;
return result;
}
const char *
CPOWProxyHandler::className(JSContext *cx, HandleObject proxy)
{
WrapperOwner *parent = OwnerOf(proxy);
if (!parent->active())
return "<dead CPOW>";
return parent->className(cx, proxy);
}
const char *
WrapperOwner::className(JSContext *cx, HandleObject proxy)
{
ObjectId objId = idOf(proxy);
nsString name;
if (!CallClassName(objId, &name))
return "<error>";
return ToNewCString(name);
}
void
CPOWProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy)
{
OwnerOf(proxy)->drop(proxy);
}
bool
WrapperOwner::init()
{
if (!JavaScriptShared::init())
return false;
return true;
}
bool
WrapperOwner::getPropertyNames(JSContext *cx, HandleObject proxy, uint32_t flags, AutoIdVector &props)
{
ObjectId objId = idOf(proxy);
ReturnStatus status;
InfallibleTArray<nsString> names;
if (!CallGetPropertyNames(objId, flags, &status, &names))
return ipcfail(cx);
if (!ok(cx, status))
return false;
for (size_t i = 0; i < names.Length(); i++) {
RootedId name(cx);
if (!convertGeckoStringToId(cx, names[i], &name))
return false;
if (!props.append(name))
return false;
}
return true;
}
namespace mozilla {
namespace jsipc {
bool
IsCPOW(JSObject *obj)
{
return IsProxy(obj) && GetProxyHandler(obj) == &CPOWProxyHandler::singleton;
}
nsresult
InstanceOf(JSObject *proxy, const nsID *id, bool *bp)
{
WrapperOwner *parent = OwnerOf(proxy);
if (!parent->active())
return NS_ERROR_UNEXPECTED;
return parent->instanceOf(proxy, id, bp);
}
bool
DOMInstanceOf(JSContext *cx, JSObject *proxy, int prototypeID, int depth, bool *bp)
{
FORWARD(domInstanceOf, (cx, proxy, prototypeID, depth, bp));
}
} /* namespace jsipc */
} /* namespace mozilla */
nsresult
WrapperOwner::instanceOf(JSObject *obj, const nsID *id, bool *bp)
{
ObjectId objId = idOf(obj);
JSIID iid;
ConvertID(*id, &iid);
ReturnStatus status;
if (!CallInstanceOf(objId, iid, &status, bp))
return NS_ERROR_UNEXPECTED;
if (status.type() != ReturnStatus::TReturnSuccess)
return NS_ERROR_UNEXPECTED;
return NS_OK;
}
bool
WrapperOwner::domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp)
{
ObjectId objId = idOf(obj);
ReturnStatus status;
if (!CallDOMInstanceOf(objId, prototypeID, depth, &status, bp))
return ipcfail(cx);
return ok(cx, status);
}
void
WrapperOwner::ActorDestroy(ActorDestroyReason why)
{
inactive_ = true;
}
bool
WrapperOwner::ipcfail(JSContext *cx)
{
JS_ReportError(cx, "child process crashed or timedout");
return false;
}
bool
WrapperOwner::ok(JSContext *cx, const ReturnStatus &status)
{
if (status.type() == ReturnStatus::TReturnSuccess)
return true;
if (status.type() == ReturnStatus::TReturnStopIteration)
return JS_ThrowStopIteration(cx);
RootedValue exn(cx);
if (!fromVariant(cx, status.get_ReturnException().exn(), &exn))
return false;
JS_SetPendingException(cx, exn);
return false;
}

153
js/ipc/WrapperOwner.h Normal file
View File

@@ -0,0 +1,153 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=80:
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_jsipc_WrapperOwner_h__
#define mozilla_jsipc_WrapperOwner_h__
#include "JavaScriptShared.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "js/Class.h"
#ifdef XP_WIN
#undef GetClassName
#undef GetClassInfo
#endif
namespace js {
class BaseProxyHandler;
} // js
namespace mozilla {
namespace jsipc {
class WrapperOwner : public JavaScriptShared
{
public:
typedef mozilla::ipc::IProtocolManager<
mozilla::ipc::IProtocol>::ActorDestroyReason
ActorDestroyReason;
WrapperOwner();
bool init();
// Fundamental proxy traps. These are required.
// (The traps should be in the same order like js/src/jsproxy.h)
bool preventExtensions(JSContext *cx, JS::HandleObject proxy);
bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc);
bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc);
bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc);
bool getOwnPropertyNames(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
bool enumerate(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
// Derived proxy traps. Implementing these is useful for perfomance.
bool has(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
bool hasOwn(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, JS::MutableHandleValue vp);
bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp);
bool keys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
// We use "iterate" provided by the base class here.
// SpiderMonkey Extensions.
bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
bool call(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args);
bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
const char* className(JSContext *cx, JS::HandleObject proxy);
nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
/*
* Check that |obj| is a DOM wrapper whose prototype chain contains
* |prototypeID| at depth |depth|.
*/
bool domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp);
bool active() { return !inactive_; }
virtual void drop(JSObject *obj) = 0;
virtual void ActorDestroy(ActorDestroyReason why);
protected:
ObjectId idOf(JSObject *obj);
static js::BaseProxyHandler *ProxyHandler();
private:
bool getPropertyNames(JSContext *cx, JS::HandleObject proxy, uint32_t flags,
JS::AutoIdVector &props);
// Catastrophic IPC failure.
bool ipcfail(JSContext *cx);
// Check whether a return status is okay, and if not, propagate its error.
bool ok(JSContext *cx, const ReturnStatus &status);
bool inactive_;
/*** Dummy call handlers ***/
public:
virtual bool CallPreventExtensions(const ObjectId &objId, ReturnStatus *rs) = 0;
virtual bool CallGetPropertyDescriptor(const ObjectId &objId, const nsString &id,
ReturnStatus *rs,
PPropertyDescriptor *out) = 0;
virtual bool CallGetOwnPropertyDescriptor(const ObjectId &objId,
const nsString &id,
ReturnStatus *rs,
PPropertyDescriptor *out) = 0;
virtual bool CallDefineProperty(const ObjectId &objId, const nsString &id,
const PPropertyDescriptor &flags,
ReturnStatus *rs) = 0;
virtual bool CallDelete(const ObjectId &objId, const nsString &id,
ReturnStatus *rs, bool *success) = 0;
virtual bool CallHas(const ObjectId &objId, const nsString &id,
ReturnStatus *rs, bool *bp) = 0;
virtual bool CallHasOwn(const ObjectId &objId, const nsString &id,
ReturnStatus *rs, bool *bp) = 0;
virtual bool CallGet(const ObjectId &objId, const ObjectId &receiverId,
const nsString &id,
ReturnStatus *rs, JSVariant *result) = 0;
virtual bool CallSet(const ObjectId &objId, const ObjectId &receiverId,
const nsString &id, const bool &strict,
const JSVariant &value, ReturnStatus *rs, JSVariant *result) = 0;
virtual bool CallIsExtensible(const ObjectId &objId, ReturnStatus *rs,
bool *result) = 0;
virtual bool CallCall(const ObjectId &objId, const nsTArray<JSParam> &argv,
ReturnStatus *rs, JSVariant *result,
nsTArray<JSParam> *outparams) = 0;
virtual bool CallObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
bool *result) = 0;
virtual bool CallClassName(const ObjectId &objId, nsString *result) = 0;
virtual bool CallGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
ReturnStatus *rs, nsTArray<nsString> *names) = 0;
virtual bool CallInstanceOf(const ObjectId &objId, const JSIID &iid,
ReturnStatus *rs, bool *instanceof) = 0;
virtual bool CallDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
ReturnStatus *rs, bool *instanceof) = 0;
};
bool
IsCPOW(JSObject *obj);
nsresult
InstanceOf(JSObject *obj, const nsID *id, bool *bp);
bool
DOMInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp);
} // jsipc
} // mozilla
#endif // mozilla_jsipc_WrapperOwner_h__

View File

@@ -8,6 +8,7 @@ UNIFIED_SOURCES += [
'JavaScriptChild.cpp', 'JavaScriptChild.cpp',
'JavaScriptParent.cpp', 'JavaScriptParent.cpp',
'JavaScriptShared.cpp', 'JavaScriptShared.cpp',
'WrapperOwner.cpp',
] ]
IPDL_SOURCES += [ IPDL_SOURCES += [