mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-06 23:37:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
43
js/ipc/CPOWTimer.cpp
Normal file
43
js/ipc/CPOWTimer.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/* -*- 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 "jsfriendapi.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "CPOWTimer.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
|
||||
CPOWTimer::CPOWTimer(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
: cx_(nullptr)
|
||||
, startInterval_(0)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
if (!js::GetStopwatchIsMonitoringCPOW(cx))
|
||||
return;
|
||||
cx_ = cx;
|
||||
startInterval_ = JS_Now();
|
||||
}
|
||||
CPOWTimer::~CPOWTimer()
|
||||
{
|
||||
if (!cx_) {
|
||||
// Monitoring was off when we started the timer.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!js::GetStopwatchIsMonitoringCPOW(cx_)) {
|
||||
// Monitoring has been deactivated while we were in the timer.
|
||||
return;
|
||||
}
|
||||
|
||||
const int64_t endInterval = JS_Now();
|
||||
if (endInterval <= startInterval_) {
|
||||
// Do not assume monotonicity.
|
||||
return;
|
||||
}
|
||||
|
||||
js::AddCPOWPerformanceDelta(cx_, endInterval - startInterval_);
|
||||
}
|
||||
44
js/ipc/CPOWTimer.h
Normal file
44
js/ipc/CPOWTimer.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef CPOWTIMER_H
|
||||
#define CPOWTIMER_H
|
||||
|
||||
#include "prinrval.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
/**
|
||||
* A stopwatch measuring the duration of a CPOW call.
|
||||
*
|
||||
* As the process is consuming neither user time nor system time
|
||||
* during a CPOW call, we measure such durations using wallclock time.
|
||||
*
|
||||
* This stopwatch is active iff JSRuntime::stopwatch.isActive is set.
|
||||
* Upon destruction, update JSRuntime::stopwatch.data.totalCPOWTime.
|
||||
*/
|
||||
class MOZ_RAII CPOWTimer final {
|
||||
public:
|
||||
explicit inline CPOWTimer(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
~CPOWTimer();
|
||||
|
||||
private:
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
/**
|
||||
* The context in which this timer was created, or `nullptr` if
|
||||
* CPOW monitoring was off when the timer was created.
|
||||
*/
|
||||
JSContext* cx_;
|
||||
|
||||
/**
|
||||
* The instant at which the stopwatch was started. Undefined
|
||||
* if CPOW monitoring was off when the timer was created.
|
||||
*/
|
||||
int64_t startInterval_;
|
||||
};
|
||||
|
||||
#endif
|
||||
25
js/ipc/CpowHolder.h
Normal file
25
js/ipc/CpowHolder.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* -*- 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_CpowHolder_h__
|
||||
#define mozilla_jsipc_CpowHolder_h__
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
class CpowHolder
|
||||
{
|
||||
public:
|
||||
virtual bool ToObject(JSContext* cx, JS::MutableHandle<JSObject*> objp) = 0;
|
||||
};
|
||||
|
||||
} // namespace jsipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_jsipc_CpowHolder_h__
|
||||
101
js/ipc/CrossProcessObjectWrappers.h
Normal file
101
js/ipc/CrossProcessObjectWrappers.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/* -*- 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_CrossProcessObjectWrappers_h__
|
||||
#define mozilla_jsipc_CrossProcessObjectWrappers_h__
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/jsipc/CpowHolder.h"
|
||||
#include "mozilla/jsipc/JavaScriptTypes.h"
|
||||
#include "nsID.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#undef GetClassName
|
||||
#undef GetClassInfo
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class CPOWManagerGetter;
|
||||
} // namespace dom
|
||||
|
||||
namespace jsipc {
|
||||
|
||||
class PJavaScriptParent;
|
||||
class PJavaScriptChild;
|
||||
|
||||
class CPOWManager
|
||||
{
|
||||
public:
|
||||
virtual bool Unwrap(JSContext* cx,
|
||||
const InfallibleTArray<CpowEntry>& aCpows,
|
||||
JS::MutableHandleObject objp) = 0;
|
||||
|
||||
virtual bool Wrap(JSContext* cx,
|
||||
JS::HandleObject aObj,
|
||||
InfallibleTArray<CpowEntry>* outCpows) = 0;
|
||||
};
|
||||
|
||||
class CrossProcessCpowHolder : public CpowHolder
|
||||
{
|
||||
public:
|
||||
CrossProcessCpowHolder(dom::CPOWManagerGetter* managerGetter,
|
||||
const InfallibleTArray<CpowEntry>& cpows);
|
||||
|
||||
~CrossProcessCpowHolder();
|
||||
|
||||
bool ToObject(JSContext* cx, JS::MutableHandleObject objp);
|
||||
|
||||
private:
|
||||
CPOWManager* js_;
|
||||
const InfallibleTArray<CpowEntry>& cpows_;
|
||||
bool unwrapped_;
|
||||
};
|
||||
|
||||
CPOWManager*
|
||||
CPOWManagerFor(PJavaScriptParent* aParent);
|
||||
|
||||
CPOWManager*
|
||||
CPOWManagerFor(PJavaScriptChild* aChild);
|
||||
|
||||
bool
|
||||
IsCPOW(JSObject* obj);
|
||||
|
||||
bool
|
||||
IsWrappedCPOW(JSObject* obj);
|
||||
|
||||
nsresult
|
||||
InstanceOf(JSObject* obj, const nsID* id, bool* bp);
|
||||
|
||||
bool
|
||||
DOMInstanceOf(JSContext* cx, JSObject* obj, int prototypeID, int depth, bool* bp);
|
||||
|
||||
void
|
||||
GetWrappedCPOWTag(JSObject* obj, nsACString& out);
|
||||
|
||||
PJavaScriptParent*
|
||||
NewJavaScriptParent();
|
||||
|
||||
void
|
||||
ReleaseJavaScriptParent(PJavaScriptParent* parent);
|
||||
|
||||
PJavaScriptChild*
|
||||
NewJavaScriptChild();
|
||||
|
||||
void
|
||||
ReleaseJavaScriptChild(PJavaScriptChild* child);
|
||||
|
||||
void
|
||||
AfterProcessTask();
|
||||
|
||||
} // namespace jsipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_jsipc_CrossProcessObjectWrappers_h__
|
||||
230
js/ipc/JavaScriptBase.h
Normal file
230
js/ipc/JavaScriptBase.h
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
/* -*- 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 "WrapperAnswer.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 WrapperAnswer, public Base
|
||||
{
|
||||
typedef WrapperAnswer Answer;
|
||||
|
||||
public:
|
||||
virtual ~JavaScriptBase() {}
|
||||
|
||||
virtual void ActorDestroy(WrapperOwner::ActorDestroyReason why) {
|
||||
WrapperOwner::ActorDestroy(why);
|
||||
}
|
||||
|
||||
/*** IPC handlers ***/
|
||||
|
||||
bool RecvPreventExtensions(const uint64_t& objId, ReturnStatus* rs) {
|
||||
return Answer::RecvPreventExtensions(ObjectId::deserialize(objId), rs);
|
||||
}
|
||||
bool RecvGetPropertyDescriptor(const uint64_t& objId, const JSIDVariant& id,
|
||||
ReturnStatus* rs,
|
||||
PPropertyDescriptor* out) {
|
||||
return Answer::RecvGetPropertyDescriptor(ObjectId::deserialize(objId), id, rs, out);
|
||||
}
|
||||
bool RecvGetOwnPropertyDescriptor(const uint64_t& objId,
|
||||
const JSIDVariant& id,
|
||||
ReturnStatus* rs,
|
||||
PPropertyDescriptor* out) {
|
||||
return Answer::RecvGetOwnPropertyDescriptor(ObjectId::deserialize(objId), id, rs, out);
|
||||
}
|
||||
bool RecvDefineProperty(const uint64_t& objId, const JSIDVariant& id,
|
||||
const PPropertyDescriptor& flags, ReturnStatus* rs) {
|
||||
return Answer::RecvDefineProperty(ObjectId::deserialize(objId), id, flags, rs);
|
||||
}
|
||||
bool RecvDelete(const uint64_t& objId, const JSIDVariant& id,
|
||||
ReturnStatus* rs) {
|
||||
return Answer::RecvDelete(ObjectId::deserialize(objId), id, rs);
|
||||
}
|
||||
|
||||
bool RecvHas(const uint64_t& objId, const JSIDVariant& id,
|
||||
ReturnStatus* rs, bool* bp) {
|
||||
return Answer::RecvHas(ObjectId::deserialize(objId), id, rs, bp);
|
||||
}
|
||||
bool RecvHasOwn(const uint64_t& objId, const JSIDVariant& id,
|
||||
ReturnStatus* rs, bool* bp) {
|
||||
return Answer::RecvHasOwn(ObjectId::deserialize(objId), id, rs, bp);
|
||||
}
|
||||
bool RecvGet(const uint64_t& objId, const JSVariant& receiverVar, const JSIDVariant& id,
|
||||
ReturnStatus* rs, JSVariant* result) {
|
||||
return Answer::RecvGet(ObjectId::deserialize(objId), receiverVar, id, rs, result);
|
||||
}
|
||||
bool RecvSet(const uint64_t& objId, const JSIDVariant& id, const JSVariant& value,
|
||||
const JSVariant& receiverVar, ReturnStatus* rs) {
|
||||
return Answer::RecvSet(ObjectId::deserialize(objId), id, value, receiverVar, rs);
|
||||
}
|
||||
|
||||
bool RecvIsExtensible(const uint64_t& objId, ReturnStatus* rs,
|
||||
bool* result) {
|
||||
return Answer::RecvIsExtensible(ObjectId::deserialize(objId), rs, result);
|
||||
}
|
||||
bool RecvCallOrConstruct(const uint64_t& objId, InfallibleTArray<JSParam>&& argv,
|
||||
const bool& construct, ReturnStatus* rs, JSVariant* result,
|
||||
nsTArray<JSParam>* outparams) {
|
||||
return Answer::RecvCallOrConstruct(ObjectId::deserialize(objId), Move(argv), construct, rs, result, outparams);
|
||||
}
|
||||
bool RecvHasInstance(const uint64_t& objId, const JSVariant& v, ReturnStatus* rs, bool* bp) {
|
||||
return Answer::RecvHasInstance(ObjectId::deserialize(objId), v, rs, bp);
|
||||
}
|
||||
bool RecvGetBuiltinClass(const uint64_t& objId, ReturnStatus* rs, uint32_t* classValue) {
|
||||
return Answer::RecvGetBuiltinClass(ObjectId::deserialize(objId), rs, classValue);
|
||||
}
|
||||
bool RecvIsArray(const uint64_t& objId, ReturnStatus* rs, uint32_t* answer) {
|
||||
return Answer::RecvIsArray(ObjectId::deserialize(objId), rs, answer);
|
||||
}
|
||||
bool RecvClassName(const uint64_t& objId, nsCString* result) {
|
||||
return Answer::RecvClassName(ObjectId::deserialize(objId), result);
|
||||
}
|
||||
bool RecvGetPrototype(const uint64_t& objId, ReturnStatus* rs, ObjectOrNullVariant* result) {
|
||||
return Answer::RecvGetPrototype(ObjectId::deserialize(objId), rs, result);
|
||||
}
|
||||
bool RecvGetPrototypeIfOrdinary(const uint64_t& objId, ReturnStatus* rs, bool* isOrdinary,
|
||||
ObjectOrNullVariant* result)
|
||||
{
|
||||
return Answer::RecvGetPrototypeIfOrdinary(ObjectId::deserialize(objId), rs, isOrdinary, result);
|
||||
}
|
||||
bool RecvRegExpToShared(const uint64_t& objId, ReturnStatus* rs, nsString* source, uint32_t* flags) {
|
||||
return Answer::RecvRegExpToShared(ObjectId::deserialize(objId), rs, source, flags);
|
||||
}
|
||||
|
||||
bool RecvGetPropertyKeys(const uint64_t& objId, const uint32_t& flags,
|
||||
ReturnStatus* rs, nsTArray<JSIDVariant>* ids) {
|
||||
return Answer::RecvGetPropertyKeys(ObjectId::deserialize(objId), flags, rs, ids);
|
||||
}
|
||||
bool RecvInstanceOf(const uint64_t& objId, const JSIID& iid,
|
||||
ReturnStatus* rs, bool* instanceof) {
|
||||
return Answer::RecvInstanceOf(ObjectId::deserialize(objId), iid, rs, instanceof);
|
||||
}
|
||||
bool RecvDOMInstanceOf(const uint64_t& objId, const int& prototypeID, const int& depth,
|
||||
ReturnStatus* rs, bool* instanceof) {
|
||||
return Answer::RecvDOMInstanceOf(ObjectId::deserialize(objId), prototypeID, depth, rs, instanceof);
|
||||
}
|
||||
|
||||
bool RecvDropObject(const uint64_t& objId) {
|
||||
return Answer::RecvDropObject(ObjectId::deserialize(objId));
|
||||
}
|
||||
|
||||
/*** Dummy call handlers ***/
|
||||
|
||||
bool SendDropObject(const ObjectId& objId) {
|
||||
return Base::SendDropObject(objId.serialize());
|
||||
}
|
||||
bool SendPreventExtensions(const ObjectId& objId, ReturnStatus* rs) {
|
||||
return Base::SendPreventExtensions(objId.serialize(), rs);
|
||||
}
|
||||
bool SendGetPropertyDescriptor(const ObjectId& objId, const JSIDVariant& id,
|
||||
ReturnStatus* rs,
|
||||
PPropertyDescriptor* out) {
|
||||
return Base::SendGetPropertyDescriptor(objId.serialize(), id, rs, out);
|
||||
}
|
||||
bool SendGetOwnPropertyDescriptor(const ObjectId& objId,
|
||||
const JSIDVariant& id,
|
||||
ReturnStatus* rs,
|
||||
PPropertyDescriptor* out) {
|
||||
return Base::SendGetOwnPropertyDescriptor(objId.serialize(), id, rs, out);
|
||||
}
|
||||
bool SendDefineProperty(const ObjectId& objId, const JSIDVariant& id,
|
||||
const PPropertyDescriptor& flags,
|
||||
ReturnStatus* rs) {
|
||||
return Base::SendDefineProperty(objId.serialize(), id, flags, rs);
|
||||
}
|
||||
bool SendDelete(const ObjectId& objId, const JSIDVariant& id, ReturnStatus* rs) {
|
||||
return Base::SendDelete(objId.serialize(), id, rs);
|
||||
}
|
||||
|
||||
bool SendHas(const ObjectId& objId, const JSIDVariant& id,
|
||||
ReturnStatus* rs, bool* bp) {
|
||||
return Base::SendHas(objId.serialize(), id, rs, bp);
|
||||
}
|
||||
bool SendHasOwn(const ObjectId& objId, const JSIDVariant& id,
|
||||
ReturnStatus* rs, bool* bp) {
|
||||
return Base::SendHasOwn(objId.serialize(), id, rs, bp);
|
||||
}
|
||||
bool SendGet(const ObjectId& objId, const JSVariant& receiverVar, const JSIDVariant& id,
|
||||
ReturnStatus* rs, JSVariant* result) {
|
||||
return Base::SendGet(objId.serialize(), receiverVar, id, rs, result);
|
||||
}
|
||||
bool SendSet(const ObjectId& objId, const JSIDVariant& id, const JSVariant& value,
|
||||
const JSVariant& receiverVar, ReturnStatus* rs) {
|
||||
return Base::SendSet(objId.serialize(), id, value, receiverVar, rs);
|
||||
}
|
||||
|
||||
bool SendIsExtensible(const ObjectId& objId, ReturnStatus* rs,
|
||||
bool* result) {
|
||||
return Base::SendIsExtensible(objId.serialize(), rs, result);
|
||||
}
|
||||
bool SendCallOrConstruct(const ObjectId& objId, const nsTArray<JSParam>& argv,
|
||||
const bool& construct, ReturnStatus* rs, JSVariant* result,
|
||||
nsTArray<JSParam>* outparams) {
|
||||
return Base::SendCallOrConstruct(objId.serialize(), argv, construct, rs, result, outparams);
|
||||
}
|
||||
bool SendHasInstance(const ObjectId& objId, const JSVariant& v, ReturnStatus* rs, bool* bp) {
|
||||
return Base::SendHasInstance(objId.serialize(), v, rs, bp);
|
||||
}
|
||||
bool SendGetBuiltinClass(const ObjectId& objId, ReturnStatus* rs, uint32_t* classValue) {
|
||||
return Base::SendGetBuiltinClass(objId.serialize(), rs, classValue);
|
||||
}
|
||||
bool SendIsArray(const ObjectId& objId, ReturnStatus* rs, uint32_t* answer)
|
||||
{
|
||||
return Base::SendIsArray(objId.serialize(), rs, answer);
|
||||
}
|
||||
bool SendClassName(const ObjectId& objId, nsCString* result) {
|
||||
return Base::SendClassName(objId.serialize(), result);
|
||||
}
|
||||
bool SendGetPrototype(const ObjectId& objId, ReturnStatus* rs, ObjectOrNullVariant* result) {
|
||||
return Base::SendGetPrototype(objId.serialize(), rs, result);
|
||||
}
|
||||
bool SendGetPrototypeIfOrdinary(const ObjectId& objId, ReturnStatus* rs, bool* isOrdinary,
|
||||
ObjectOrNullVariant* result)
|
||||
{
|
||||
return Base::SendGetPrototypeIfOrdinary(objId.serialize(), rs, isOrdinary, result);
|
||||
}
|
||||
|
||||
bool SendRegExpToShared(const ObjectId& objId, ReturnStatus* rs,
|
||||
nsString* source, uint32_t* flags) {
|
||||
return Base::SendRegExpToShared(objId.serialize(), rs, source, flags);
|
||||
}
|
||||
|
||||
bool SendGetPropertyKeys(const ObjectId& objId, const uint32_t& flags,
|
||||
ReturnStatus* rs, nsTArray<JSIDVariant>* ids) {
|
||||
return Base::SendGetPropertyKeys(objId.serialize(), flags, rs, ids);
|
||||
}
|
||||
bool SendInstanceOf(const ObjectId& objId, const JSIID& iid,
|
||||
ReturnStatus* rs, bool* instanceof) {
|
||||
return Base::SendInstanceOf(objId.serialize(), iid, rs, instanceof);
|
||||
}
|
||||
bool SendDOMInstanceOf(const ObjectId& objId, const int& prototypeID, const int& depth,
|
||||
ReturnStatus* rs, bool* instanceof) {
|
||||
return Base::SendDOMInstanceOf(objId.serialize(), 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, const ObjectVariant& objVar) {
|
||||
return WrapperOwner::fromObjectVariant(cx, objVar);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace jsipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
100
js/ipc/JavaScriptChild.cpp
Normal file
100
js/ipc/JavaScriptChild.cpp
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/* -*- 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 "JavaScriptChild.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/ipc/MessageChannel.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "AccessCheck.h"
|
||||
|
||||
using namespace JS;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::jsipc;
|
||||
|
||||
using mozilla::AutoSafeJSContext;
|
||||
|
||||
static void
|
||||
UpdateChildWeakPointersBeforeSweepingZoneGroup(JSContext* cx, void* data)
|
||||
{
|
||||
static_cast<JavaScriptChild*>(data)->updateWeakPointers();
|
||||
}
|
||||
|
||||
static void
|
||||
TraceChild(JSTracer* trc, void* data)
|
||||
{
|
||||
static_cast<JavaScriptChild*>(data)->trace(trc);
|
||||
}
|
||||
|
||||
JavaScriptChild::~JavaScriptChild()
|
||||
{
|
||||
JSContext* cx = dom::danger::GetJSContext();
|
||||
JS_RemoveWeakPointerZoneGroupCallback(cx, UpdateChildWeakPointersBeforeSweepingZoneGroup);
|
||||
JS_RemoveExtraGCRootsTracer(cx, TraceChild, this);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::init()
|
||||
{
|
||||
if (!WrapperOwner::init())
|
||||
return false;
|
||||
if (!WrapperAnswer::init())
|
||||
return false;
|
||||
|
||||
JSContext* cx = dom::danger::GetJSContext();
|
||||
JS_AddWeakPointerZoneGroupCallback(cx, UpdateChildWeakPointersBeforeSweepingZoneGroup, this);
|
||||
JS_AddExtraGCRootsTracer(cx, TraceChild, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
JavaScriptChild::trace(JSTracer* trc)
|
||||
{
|
||||
objects_.trace(trc, strongReferenceObjIdMinimum_);
|
||||
}
|
||||
|
||||
void
|
||||
JavaScriptChild::updateWeakPointers()
|
||||
{
|
||||
objects_.sweep();
|
||||
unwaivedObjectIds_.sweep();
|
||||
waivedObjectIds_.sweep();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
JavaScriptChild::scopeForTargetObjects()
|
||||
{
|
||||
// CPOWs from the parent need to point into the child's privileged junk
|
||||
// scope so that they can benefit from XrayWrappers in the child.
|
||||
return xpc::PrivilegedJunkScope();
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptChild::RecvDropTemporaryStrongReferences(const uint64_t& upToObjId)
|
||||
{
|
||||
strongReferenceObjIdMinimum_ = upToObjId + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
PJavaScriptChild*
|
||||
mozilla::jsipc::NewJavaScriptChild()
|
||||
{
|
||||
JavaScriptChild* child = new JavaScriptChild();
|
||||
if (!child->init()) {
|
||||
delete child;
|
||||
return nullptr;
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
void
|
||||
mozilla::jsipc::ReleaseJavaScriptChild(PJavaScriptChild* child)
|
||||
{
|
||||
static_cast<JavaScriptChild*>(child)->decref();
|
||||
}
|
||||
50
js/ipc/JavaScriptChild.h
Normal file
50
js/ipc/JavaScriptChild.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_jsipc_JavaScriptChild_h_
|
||||
#define mozilla_jsipc_JavaScriptChild_h_
|
||||
|
||||
#include "JavaScriptBase.h"
|
||||
#include "mozilla/jsipc/PJavaScriptChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
class JavaScriptChild : public JavaScriptBase<PJavaScriptChild>
|
||||
{
|
||||
public:
|
||||
JavaScriptChild() : strongReferenceObjIdMinimum_(0) {}
|
||||
virtual ~JavaScriptChild();
|
||||
|
||||
bool init();
|
||||
void trace(JSTracer* trc);
|
||||
void updateWeakPointers();
|
||||
|
||||
void drop(JSObject* obj);
|
||||
|
||||
bool allowMessage(JSContext* cx) override { return true; }
|
||||
|
||||
protected:
|
||||
virtual bool isParent() override { return false; }
|
||||
virtual JSObject* scopeForTargetObjects() override;
|
||||
|
||||
bool RecvDropTemporaryStrongReferences(const uint64_t& upToObjId) override;
|
||||
|
||||
private:
|
||||
bool fail(JSContext* cx, ReturnStatus* rs);
|
||||
bool ok(ReturnStatus* rs);
|
||||
|
||||
// JavaScriptChild will keep strong references to JS objects that are
|
||||
// referenced by the parent only if their ID is >=
|
||||
// strongReferenceObjIdMinimum_.
|
||||
uint64_t strongReferenceObjIdMinimum_;
|
||||
};
|
||||
|
||||
} // namespace jsipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
231
js/ipc/JavaScriptLogging.h
Normal file
231
js/ipc/JavaScriptLogging.h
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/* -*- 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_JavaScriptLogging__
|
||||
#define mozilla_jsipc_JavaScriptLogging__
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "jswrapper.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
#define LOG(...) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (LoggingEnabled()) { \
|
||||
Logging log(this, cx); \
|
||||
log.print(__VA_ARGS__); \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
#define LOG_STACK() \
|
||||
PR_BEGIN_MACRO \
|
||||
if (StackLoggingEnabled()) { \
|
||||
js::DumpBacktrace(cx); \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
struct ReceiverObj
|
||||
{
|
||||
ObjectId id;
|
||||
explicit ReceiverObj(ObjectId id) : id(id) {}
|
||||
};
|
||||
|
||||
struct InVariant
|
||||
{
|
||||
JSVariant variant;
|
||||
explicit InVariant(const JSVariant& variant) : variant(variant) {}
|
||||
};
|
||||
|
||||
struct OutVariant
|
||||
{
|
||||
JSVariant variant;
|
||||
explicit OutVariant(const JSVariant& variant) : variant(variant) {}
|
||||
};
|
||||
|
||||
struct Identifier
|
||||
{
|
||||
JSIDVariant variant;
|
||||
explicit Identifier(const JSIDVariant& variant) : variant(variant) {}
|
||||
};
|
||||
|
||||
class Logging
|
||||
{
|
||||
public:
|
||||
Logging(JavaScriptShared* shared, JSContext* cx) : shared(shared), cx(cx) {}
|
||||
|
||||
void print(const nsCString& str) {
|
||||
const char* side = shared->isParent() ? "from child" : "from parent";
|
||||
printf("CPOW %s: %s\n", side, str.get());
|
||||
}
|
||||
|
||||
void print(const char* str) {
|
||||
print(nsCString(str));
|
||||
}
|
||||
template<typename T1>
|
||||
void print(const char* fmt, const T1& a1) {
|
||||
nsAutoCString tmp1;
|
||||
format(a1, tmp1);
|
||||
print(nsPrintfCString(fmt, tmp1.get()));
|
||||
}
|
||||
template<typename T1, typename T2>
|
||||
void print(const char* fmt, const T1& a1, const T2& a2) {
|
||||
nsAutoCString tmp1;
|
||||
nsAutoCString tmp2;
|
||||
format(a1, tmp1);
|
||||
format(a2, tmp2);
|
||||
print(nsPrintfCString(fmt, tmp1.get(), tmp2.get()));
|
||||
}
|
||||
template<typename T1, typename T2, typename T3>
|
||||
void print(const char* fmt, const T1& a1, const T2& a2, const T3& a3) {
|
||||
nsAutoCString tmp1;
|
||||
nsAutoCString tmp2;
|
||||
nsAutoCString tmp3;
|
||||
format(a1, tmp1);
|
||||
format(a2, tmp2);
|
||||
format(a3, tmp3);
|
||||
print(nsPrintfCString(fmt, tmp1.get(), tmp2.get(), tmp3.get()));
|
||||
}
|
||||
|
||||
void format(const nsString& str, nsCString& out) {
|
||||
out = NS_ConvertUTF16toUTF8(str);
|
||||
}
|
||||
|
||||
void formatObject(bool incoming, bool local, ObjectId id, nsCString& out) {
|
||||
const char* side;
|
||||
const char* objDesc;
|
||||
void* ptr;
|
||||
|
||||
if (local == incoming) {
|
||||
JS::RootedObject obj(cx);
|
||||
obj = shared->objects_.find(id);
|
||||
if (obj) {
|
||||
JSAutoCompartment ac(cx, obj);
|
||||
objDesc = js::ObjectClassName(cx, obj);
|
||||
} else {
|
||||
objDesc = "<dead object>";
|
||||
}
|
||||
|
||||
side = shared->isParent() ? "parent" : "child";
|
||||
ptr = js::UncheckedUnwrap(obj, true);
|
||||
} else {
|
||||
objDesc = "<cpow>";
|
||||
side = shared->isParent() ? "child" : "parent";
|
||||
ptr = nullptr;
|
||||
}
|
||||
|
||||
out = nsPrintfCString("<%s %s:%d:%p>", side, objDesc, id.serialNumber(), ptr);
|
||||
}
|
||||
|
||||
void format(const ReceiverObj& obj, nsCString& out) {
|
||||
formatObject(true, true, obj.id, out);
|
||||
}
|
||||
|
||||
void format(const nsTArray<JSParam>& values, nsCString& out) {
|
||||
nsAutoCString tmp;
|
||||
out.Truncate();
|
||||
for (size_t i = 0; i < values.Length(); i++) {
|
||||
if (i)
|
||||
out.AppendLiteral(", ");
|
||||
if (values[i].type() == JSParam::Tvoid_t) {
|
||||
out.AppendLiteral("<void>");
|
||||
} else {
|
||||
format(InVariant(values[i].get_JSVariant()), tmp);
|
||||
out += tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void format(const InVariant& value, nsCString& out) {
|
||||
format(true, value.variant, out);
|
||||
}
|
||||
|
||||
void format(const OutVariant& value, nsCString& out) {
|
||||
format(false, value.variant, out);
|
||||
}
|
||||
|
||||
void format(bool incoming, const JSVariant& value, nsCString& out) {
|
||||
switch (value.type()) {
|
||||
case JSVariant::TUndefinedVariant: {
|
||||
out = "undefined";
|
||||
break;
|
||||
}
|
||||
case JSVariant::TNullVariant: {
|
||||
out = "null";
|
||||
break;
|
||||
}
|
||||
case JSVariant::TnsString: {
|
||||
nsAutoCString tmp;
|
||||
format(value.get_nsString(), tmp);
|
||||
out = nsPrintfCString("\"%s\"", tmp.get());
|
||||
break;
|
||||
}
|
||||
case JSVariant::TObjectVariant: {
|
||||
const ObjectVariant& ovar = value.get_ObjectVariant();
|
||||
if (ovar.type() == ObjectVariant::TLocalObject)
|
||||
formatObject(incoming, true, ObjectId::deserialize(ovar.get_LocalObject().serializedId()), out);
|
||||
else
|
||||
formatObject(incoming, false, ObjectId::deserialize(ovar.get_RemoteObject().serializedId()), out);
|
||||
break;
|
||||
}
|
||||
case JSVariant::TSymbolVariant: {
|
||||
out = "<Symbol>";
|
||||
break;
|
||||
}
|
||||
case JSVariant::Tdouble: {
|
||||
out = nsPrintfCString("%.0f", value.get_double());
|
||||
break;
|
||||
}
|
||||
case JSVariant::Tbool: {
|
||||
out = value.get_bool() ? "true" : "false";
|
||||
break;
|
||||
}
|
||||
case JSVariant::TJSIID: {
|
||||
out = "<JSIID>";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
out = "<JSIID>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void format(const Identifier& id, nsCString& out) {
|
||||
switch (id.variant.type()) {
|
||||
case JSIDVariant::TSymbolVariant: {
|
||||
out = "<Symbol>";
|
||||
break;
|
||||
}
|
||||
case JSIDVariant::TnsString: {
|
||||
nsAutoCString tmp;
|
||||
format(id.variant.get_nsString(), tmp);
|
||||
out = nsPrintfCString("\"%s\"", tmp.get());
|
||||
break;
|
||||
}
|
||||
case JSIDVariant::Tint32_t: {
|
||||
out = nsPrintfCString("%d", id.variant.get_int32_t());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
out = "Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
JavaScriptShared* shared;
|
||||
JSContext* cx;
|
||||
};
|
||||
|
||||
} // namespace jsipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
212
js/ipc/JavaScriptParent.cpp
Normal file
212
js/ipc/JavaScriptParent.cpp
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/* -*- 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 "JavaScriptParent.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "jswrapper.h"
|
||||
#include "js/Proxy.h"
|
||||
#include "js/HeapAPI.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "mozilla/Casting.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace JS;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::jsipc;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
static void
|
||||
TraceParent(JSTracer* trc, void* data)
|
||||
{
|
||||
static_cast<JavaScriptParent*>(data)->trace(trc);
|
||||
}
|
||||
|
||||
JavaScriptParent::~JavaScriptParent()
|
||||
{
|
||||
JS_RemoveExtraGCRootsTracer(danger::GetJSContext(), TraceParent, this);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::init()
|
||||
{
|
||||
if (!WrapperOwner::init())
|
||||
return false;
|
||||
|
||||
JS_AddExtraGCRootsTracer(danger::GetJSContext(), TraceParent, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ForbidUnsafeBrowserCPOWs()
|
||||
{
|
||||
static bool result;
|
||||
static bool cached = false;
|
||||
if (!cached) {
|
||||
cached = true;
|
||||
Preferences::AddBoolVarCache(&result, "dom.ipc.cpows.forbid-unsafe-from-browser", false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Should we allow CPOWs in aAddonId, even though it's marked as multiprocess
|
||||
// compatible? This is controlled by two prefs:
|
||||
// If dom.ipc.cpows.forbid-cpows-in-compat-addons is false, then we allow the CPOW.
|
||||
// If dom.ipc.cpows.forbid-cpows-in-compat-addons is true:
|
||||
// We check if aAddonId is listed in dom.ipc.cpows.allow-cpows-in-compat-addons
|
||||
// (which should be a comma-separated string). If it's present there, we allow
|
||||
// the CPOW. Otherwise we forbid the CPOW.
|
||||
static bool
|
||||
ForbidCPOWsInCompatibleAddon(const nsACString& aAddonId)
|
||||
{
|
||||
bool forbid = Preferences::GetBool("dom.ipc.cpows.forbid-cpows-in-compat-addons", false);
|
||||
if (!forbid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCString allow;
|
||||
allow.Assign(',');
|
||||
allow.Append(Preferences::GetCString("dom.ipc.cpows.allow-cpows-in-compat-addons"));
|
||||
allow.Append(',');
|
||||
|
||||
nsCString searchString(",");
|
||||
searchString.Append(aAddonId);
|
||||
searchString.Append(',');
|
||||
return allow.Find(searchString) == kNotFound;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptParent::allowMessage(JSContext* cx)
|
||||
{
|
||||
// If we're running browser code, then we allow all safe CPOWs and forbid
|
||||
// unsafe CPOWs based on a pref (which defaults to forbidden). We also allow
|
||||
// CPOWs unconditionally in selected globals (based on
|
||||
// Cu.permitCPOWsInScope).
|
||||
//
|
||||
// If we're running add-on code, then we check if the add-on is multiprocess
|
||||
// compatible (which eventually translates to a given setting of allowCPOWs
|
||||
// on the scopw). If it's not compatible, then we allow the CPOW but
|
||||
// warn. If it is marked as compatible, then we check the
|
||||
// ForbidCPOWsInCompatibleAddon; see the comment there.
|
||||
|
||||
MessageChannel* channel = GetIPCChannel();
|
||||
bool isSafe = channel->IsInTransaction();
|
||||
|
||||
bool warn = !isSafe;
|
||||
nsIGlobalObject* global = dom::GetIncumbentGlobal();
|
||||
JSObject* jsGlobal = global ? global->GetGlobalJSObject() : nullptr;
|
||||
if (jsGlobal) {
|
||||
JSAutoCompartment ac(cx, jsGlobal);
|
||||
JSAddonId* addonId = JS::AddonIdOfObject(jsGlobal);
|
||||
|
||||
if (!xpc::CompartmentPrivate::Get(jsGlobal)->allowCPOWs) {
|
||||
if (!addonId && ForbidUnsafeBrowserCPOWs() && !isSafe) {
|
||||
Telemetry::Accumulate(Telemetry::BROWSER_SHIM_USAGE_BLOCKED, 1);
|
||||
JS_ReportErrorASCII(cx, "unsafe CPOW usage forbidden");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (addonId) {
|
||||
JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(addonId));
|
||||
nsString addonIdString;
|
||||
AssignJSFlatString(addonIdString, flat);
|
||||
NS_ConvertUTF16toUTF8 addonIdCString(addonIdString);
|
||||
Telemetry::Accumulate(Telemetry::ADDON_FORBIDDEN_CPOW_USAGE, addonIdCString);
|
||||
|
||||
if (ForbidCPOWsInCompatibleAddon(addonIdCString)) {
|
||||
JS_ReportErrorASCII(cx, "CPOW usage forbidden in this add-on");
|
||||
return false;
|
||||
}
|
||||
|
||||
warn = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!warn)
|
||||
return true;
|
||||
|
||||
static bool disableUnsafeCPOWWarnings = PR_GetEnv("DISABLE_UNSAFE_CPOW_WARNINGS");
|
||||
if (!disableUnsafeCPOWWarnings) {
|
||||
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
|
||||
if (console && cx) {
|
||||
nsAutoString filename;
|
||||
uint32_t lineno = 0, column = 0;
|
||||
nsJSUtils::GetCallingLocation(cx, filename, &lineno, &column);
|
||||
nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
|
||||
error->Init(NS_LITERAL_STRING("unsafe/forbidden CPOW usage"), filename,
|
||||
EmptyString(), lineno, column,
|
||||
nsIScriptError::warningFlag, "chrome javascript");
|
||||
console->LogMessage(error);
|
||||
} else {
|
||||
NS_WARNING("Unsafe synchronous IPC message");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
JavaScriptParent::trace(JSTracer* trc)
|
||||
{
|
||||
objects_.trace(trc);
|
||||
unwaivedObjectIds_.trace(trc);
|
||||
waivedObjectIds_.trace(trc);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
JavaScriptParent::scopeForTargetObjects()
|
||||
{
|
||||
// CPWOWs from the child need to point into the parent's unprivileged junk
|
||||
// scope so that a compromised child cannot compromise the parent. In
|
||||
// practice, this means that a child process can only (a) hold parent
|
||||
// objects alive and (b) invoke them if they are callable.
|
||||
return xpc::UnprivilegedJunkScope();
|
||||
}
|
||||
|
||||
void
|
||||
JavaScriptParent::afterProcessTask()
|
||||
{
|
||||
if (savedNextCPOWNumber_ == nextCPOWNumber_)
|
||||
return;
|
||||
|
||||
savedNextCPOWNumber_ = nextCPOWNumber_;
|
||||
|
||||
MOZ_ASSERT(nextCPOWNumber_ > 0);
|
||||
if (active())
|
||||
Unused << SendDropTemporaryStrongReferences(nextCPOWNumber_ - 1);
|
||||
}
|
||||
|
||||
PJavaScriptParent*
|
||||
mozilla::jsipc::NewJavaScriptParent()
|
||||
{
|
||||
JavaScriptParent* parent = new JavaScriptParent();
|
||||
if (!parent->init()) {
|
||||
delete parent;
|
||||
return nullptr;
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
void
|
||||
mozilla::jsipc::ReleaseJavaScriptParent(PJavaScriptParent* parent)
|
||||
{
|
||||
static_cast<JavaScriptParent*>(parent)->decref();
|
||||
}
|
||||
|
||||
void
|
||||
mozilla::jsipc::AfterProcessTask()
|
||||
{
|
||||
for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
|
||||
if (PJavaScriptParent* p = LoneManagedOrNullAsserts(cp->ManagedPJavaScriptParent()))
|
||||
static_cast<JavaScriptParent*>(p)->afterProcessTask();
|
||||
}
|
||||
}
|
||||
43
js/ipc/JavaScriptParent.h
Normal file
43
js/ipc/JavaScriptParent.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_jsipc_JavaScriptParent__
|
||||
#define mozilla_jsipc_JavaScriptParent__
|
||||
|
||||
#include "JavaScriptBase.h"
|
||||
#include "mozilla/jsipc/PJavaScriptParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
class JavaScriptParent : public JavaScriptBase<PJavaScriptParent>
|
||||
{
|
||||
public:
|
||||
JavaScriptParent() : savedNextCPOWNumber_(1) {}
|
||||
virtual ~JavaScriptParent();
|
||||
|
||||
bool init();
|
||||
void trace(JSTracer* trc);
|
||||
|
||||
void drop(JSObject* obj);
|
||||
|
||||
bool allowMessage(JSContext* cx) override;
|
||||
void afterProcessTask();
|
||||
|
||||
protected:
|
||||
virtual bool isParent() override { return true; }
|
||||
virtual JSObject* scopeForTargetObjects() override;
|
||||
|
||||
private:
|
||||
uint64_t savedNextCPOWNumber_;
|
||||
};
|
||||
|
||||
} // namespace jsipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_jsipc_JavaScriptWrapper_h__
|
||||
|
||||
760
js/ipc/JavaScriptShared.cpp
Normal file
760
js/ipc/JavaScriptShared.cpp
Normal file
|
|
@ -0,0 +1,760 @@
|
|||
/* -*- 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 "JavaScriptShared.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/CPOWManagerGetter.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "WrapperFactory.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace JS;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::jsipc;
|
||||
|
||||
IdToObjectMap::IdToObjectMap()
|
||||
: table_(SystemAllocPolicy())
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
IdToObjectMap::init()
|
||||
{
|
||||
if (table_.initialized())
|
||||
return true;
|
||||
return table_.init(32);
|
||||
}
|
||||
|
||||
void
|
||||
IdToObjectMap::trace(JSTracer* trc, uint64_t minimimId)
|
||||
{
|
||||
for (Table::Range r(table_.all()); !r.empty(); r.popFront()) {
|
||||
if (r.front().key().serialNumber() >= minimimId)
|
||||
JS::TraceEdge(trc, &r.front().value(), "ipc-object");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IdToObjectMap::sweep()
|
||||
{
|
||||
for (Table::Enum e(table_); !e.empty(); e.popFront()) {
|
||||
JS::Heap<JSObject*>* objp = &e.front().value();
|
||||
JS_UpdateWeakPointerAfterGC(objp);
|
||||
if (!*objp)
|
||||
e.removeFront();
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
IdToObjectMap::find(ObjectId id)
|
||||
{
|
||||
Table::Ptr p = table_.lookup(id);
|
||||
if (!p)
|
||||
return nullptr;
|
||||
return p->value();
|
||||
}
|
||||
|
||||
bool
|
||||
IdToObjectMap::add(ObjectId id, JSObject* obj)
|
||||
{
|
||||
return table_.put(id, obj);
|
||||
}
|
||||
|
||||
void
|
||||
IdToObjectMap::remove(ObjectId id)
|
||||
{
|
||||
table_.remove(id);
|
||||
}
|
||||
|
||||
void
|
||||
IdToObjectMap::clear()
|
||||
{
|
||||
table_.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
IdToObjectMap::empty() const
|
||||
{
|
||||
return table_.empty();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
IdToObjectMap::has(const ObjectId& id, const JSObject* obj) const
|
||||
{
|
||||
auto p = table_.lookup(id);
|
||||
if (!p)
|
||||
return false;
|
||||
return p->value().unbarrieredGet() == obj;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
ObjectToIdMap::init()
|
||||
{
|
||||
return table_.initialized() || table_.init(32);
|
||||
}
|
||||
|
||||
void
|
||||
ObjectToIdMap::trace(JSTracer* trc)
|
||||
{
|
||||
table_.trace(trc);
|
||||
}
|
||||
|
||||
void
|
||||
ObjectToIdMap::sweep()
|
||||
{
|
||||
table_.sweep();
|
||||
}
|
||||
|
||||
ObjectId
|
||||
ObjectToIdMap::find(JSObject* obj)
|
||||
{
|
||||
Table::Ptr p = table_.lookup(obj);
|
||||
if (!p)
|
||||
return ObjectId::nullId();
|
||||
return p->value();
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectToIdMap::add(JSContext* cx, JSObject* obj, ObjectId id)
|
||||
{
|
||||
return table_.put(obj, id);
|
||||
}
|
||||
|
||||
void
|
||||
ObjectToIdMap::remove(JSObject* obj)
|
||||
{
|
||||
table_.remove(obj);
|
||||
}
|
||||
|
||||
void
|
||||
ObjectToIdMap::clear()
|
||||
{
|
||||
table_.clear();
|
||||
}
|
||||
|
||||
bool JavaScriptShared::sLoggingInitialized;
|
||||
bool JavaScriptShared::sLoggingEnabled;
|
||||
bool JavaScriptShared::sStackLoggingEnabled;
|
||||
|
||||
JavaScriptShared::JavaScriptShared()
|
||||
: refcount_(1),
|
||||
nextSerialNumber_(1),
|
||||
nextCPOWNumber_(1)
|
||||
{
|
||||
if (!sLoggingInitialized) {
|
||||
sLoggingInitialized = true;
|
||||
|
||||
if (PR_GetEnv("MOZ_CPOW_LOG")) {
|
||||
sLoggingEnabled = true;
|
||||
sStackLoggingEnabled = strstr(PR_GetEnv("MOZ_CPOW_LOG"), "stacks");
|
||||
} else {
|
||||
Preferences::AddBoolVarCache(&sLoggingEnabled,
|
||||
"dom.ipc.cpows.log.enabled", false);
|
||||
Preferences::AddBoolVarCache(&sStackLoggingEnabled,
|
||||
"dom.ipc.cpows.log.stack", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JavaScriptShared::~JavaScriptShared()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(cpows_.empty());
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::init()
|
||||
{
|
||||
if (!objects_.init())
|
||||
return false;
|
||||
if (!cpows_.init())
|
||||
return false;
|
||||
if (!unwaivedObjectIds_.init())
|
||||
return false;
|
||||
if (!waivedObjectIds_.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)
|
||||
{
|
||||
RootedValue idval(cx);
|
||||
if (!JS_IdToValue(cx, id, &idval))
|
||||
return false;
|
||||
|
||||
RootedString str(cx, ToString(cx, idval));
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
return AssignJSString(cx, *to, str);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::convertGeckoStringToId(JSContext* cx, const nsString& from, JS::MutableHandleId to)
|
||||
{
|
||||
RootedString str(cx, JS_NewUCStringCopyN(cx, from.BeginReading(), from.Length()));
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
return JS_StringToId(cx, str, to);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::toVariant(JSContext* cx, JS::HandleValue from, JSVariant* to)
|
||||
{
|
||||
switch (JS_TypeOfValue(cx, from)) {
|
||||
case JSTYPE_VOID:
|
||||
*to = UndefinedVariant();
|
||||
return true;
|
||||
|
||||
case JSTYPE_OBJECT:
|
||||
case JSTYPE_FUNCTION:
|
||||
{
|
||||
RootedObject obj(cx, from.toObjectOrNull());
|
||||
if (!obj) {
|
||||
MOZ_ASSERT(from.isNull());
|
||||
*to = NullVariant();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (xpc_JSObjectIsID(cx, obj)) {
|
||||
JSIID iid;
|
||||
const nsID* id = xpc_JSObjectToID(cx, obj);
|
||||
ConvertID(*id, &iid);
|
||||
*to = iid;
|
||||
return true;
|
||||
}
|
||||
|
||||
ObjectVariant objVar;
|
||||
if (!toObjectVariant(cx, obj, &objVar))
|
||||
return false;
|
||||
*to = objVar;
|
||||
return true;
|
||||
}
|
||||
|
||||
case JSTYPE_SYMBOL:
|
||||
{
|
||||
RootedSymbol sym(cx, from.toSymbol());
|
||||
|
||||
SymbolVariant symVar;
|
||||
if (!toSymbolVariant(cx, sym, &symVar))
|
||||
return false;
|
||||
*to = symVar;
|
||||
return true;
|
||||
}
|
||||
|
||||
case JSTYPE_STRING:
|
||||
{
|
||||
nsAutoJSString autoStr;
|
||||
if (!autoStr.init(cx, from))
|
||||
return false;
|
||||
*to = autoStr;
|
||||
return true;
|
||||
}
|
||||
|
||||
case JSTYPE_NUMBER:
|
||||
if (from.isInt32())
|
||||
*to = double(from.toInt32());
|
||||
else
|
||||
*to = from.toDouble();
|
||||
return true;
|
||||
|
||||
case JSTYPE_BOOLEAN:
|
||||
*to = from.toBoolean();
|
||||
return true;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::fromVariant(JSContext* cx, const JSVariant& from, MutableHandleValue to)
|
||||
{
|
||||
switch (from.type()) {
|
||||
case JSVariant::TUndefinedVariant:
|
||||
to.set(UndefinedValue());
|
||||
return true;
|
||||
|
||||
case JSVariant::TNullVariant:
|
||||
to.set(NullValue());
|
||||
return true;
|
||||
|
||||
case JSVariant::TObjectVariant:
|
||||
{
|
||||
JSObject* obj = fromObjectVariant(cx, from.get_ObjectVariant());
|
||||
if (!obj)
|
||||
return false;
|
||||
to.set(ObjectValue(*obj));
|
||||
return true;
|
||||
}
|
||||
|
||||
case JSVariant::TSymbolVariant:
|
||||
{
|
||||
Symbol* sym = fromSymbolVariant(cx, from.get_SymbolVariant());
|
||||
if (!sym)
|
||||
return false;
|
||||
to.setSymbol(sym);
|
||||
return true;
|
||||
}
|
||||
|
||||
case JSVariant::Tdouble:
|
||||
to.set(JS_NumberValue(from.get_double()));
|
||||
return true;
|
||||
|
||||
case JSVariant::Tbool:
|
||||
to.setBoolean(from.get_bool());
|
||||
return true;
|
||||
|
||||
case JSVariant::TnsString:
|
||||
{
|
||||
const nsString& old = from.get_nsString();
|
||||
JSString* str = JS_NewUCStringCopyN(cx, old.BeginReading(), old.Length());
|
||||
if (!str)
|
||||
return false;
|
||||
to.set(StringValue(str));
|
||||
return true;
|
||||
}
|
||||
|
||||
case JSVariant::TJSIID:
|
||||
{
|
||||
nsID iid;
|
||||
const JSIID& id = from.get_JSIID();
|
||||
ConvertID(id, &iid);
|
||||
|
||||
JSCompartment* compartment = GetContextCompartment(cx);
|
||||
RootedObject global(cx, JS_GetGlobalForCompartmentOrNull(cx, compartment));
|
||||
JSObject* obj = xpc_NewIDObject(cx, global, iid);
|
||||
if (!obj)
|
||||
return false;
|
||||
to.set(ObjectValue(*obj));
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_CRASH("NYI");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::toJSIDVariant(JSContext* cx, HandleId from, JSIDVariant* to)
|
||||
{
|
||||
if (JSID_IS_STRING(from)) {
|
||||
nsAutoJSString autoStr;
|
||||
if (!autoStr.init(cx, JSID_TO_STRING(from)))
|
||||
return false;
|
||||
*to = autoStr;
|
||||
return true;
|
||||
}
|
||||
if (JSID_IS_INT(from)) {
|
||||
*to = JSID_TO_INT(from);
|
||||
return true;
|
||||
}
|
||||
if (JSID_IS_SYMBOL(from)) {
|
||||
SymbolVariant symVar;
|
||||
if (!toSymbolVariant(cx, JSID_TO_SYMBOL(from), &symVar))
|
||||
return false;
|
||||
*to = symVar;
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::fromJSIDVariant(JSContext* cx, const JSIDVariant& from, MutableHandleId to)
|
||||
{
|
||||
switch (from.type()) {
|
||||
case JSIDVariant::TSymbolVariant: {
|
||||
Symbol* sym = fromSymbolVariant(cx, from.get_SymbolVariant());
|
||||
if (!sym)
|
||||
return false;
|
||||
to.set(SYMBOL_TO_JSID(sym));
|
||||
return true;
|
||||
}
|
||||
|
||||
case JSIDVariant::TnsString:
|
||||
return convertGeckoStringToId(cx, from.get_nsString(), to);
|
||||
|
||||
case JSIDVariant::Tint32_t:
|
||||
to.set(INT_TO_JSID(from.get_int32_t()));
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::toSymbolVariant(JSContext* cx, JS::Symbol* symArg, SymbolVariant* symVarp)
|
||||
{
|
||||
RootedSymbol sym(cx, symArg);
|
||||
MOZ_ASSERT(sym);
|
||||
|
||||
SymbolCode code = GetSymbolCode(sym);
|
||||
if (static_cast<uint32_t>(code) < WellKnownSymbolLimit) {
|
||||
*symVarp = WellKnownSymbol(static_cast<uint32_t>(code));
|
||||
return true;
|
||||
}
|
||||
if (code == SymbolCode::InSymbolRegistry) {
|
||||
nsAutoJSString autoStr;
|
||||
if (!autoStr.init(cx, GetSymbolDescription(sym)))
|
||||
return false;
|
||||
*symVarp = RegisteredSymbol(autoStr);
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_ReportErrorASCII(cx, "unique symbol can't be used with CPOW");
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Symbol*
|
||||
JavaScriptShared::fromSymbolVariant(JSContext* cx, const SymbolVariant& symVar)
|
||||
{
|
||||
switch (symVar.type()) {
|
||||
case SymbolVariant::TWellKnownSymbol: {
|
||||
uint32_t which = symVar.get_WellKnownSymbol().which();
|
||||
if (which < WellKnownSymbolLimit)
|
||||
return GetWellKnownSymbol(cx, static_cast<SymbolCode>(which));
|
||||
MOZ_ASSERT(false, "bad child data");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
case SymbolVariant::TRegisteredSymbol: {
|
||||
nsString key = symVar.get_RegisteredSymbol().key();
|
||||
RootedString str(cx, JS_NewUCStringCopyN(cx, key.get(), key.Length()));
|
||||
if (!str)
|
||||
return nullptr;
|
||||
return GetSymbolFor(cx, str);
|
||||
}
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
JavaScriptShared::ConvertID(const nsID& from, JSIID* to)
|
||||
{
|
||||
to->m0() = from.m0;
|
||||
to->m1() = from.m1;
|
||||
to->m2() = from.m2;
|
||||
to->m3_0() = from.m3[0];
|
||||
to->m3_1() = from.m3[1];
|
||||
to->m3_2() = from.m3[2];
|
||||
to->m3_3() = from.m3[3];
|
||||
to->m3_4() = from.m3[4];
|
||||
to->m3_5() = from.m3[5];
|
||||
to->m3_6() = from.m3[6];
|
||||
to->m3_7() = from.m3[7];
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
JavaScriptShared::ConvertID(const JSIID& from, nsID* to)
|
||||
{
|
||||
to->m0 = from.m0();
|
||||
to->m1 = from.m1();
|
||||
to->m2 = from.m2();
|
||||
to->m3[0] = from.m3_0();
|
||||
to->m3[1] = from.m3_1();
|
||||
to->m3[2] = from.m3_2();
|
||||
to->m3[3] = from.m3_3();
|
||||
to->m3[4] = from.m3_4();
|
||||
to->m3[5] = from.m3_5();
|
||||
to->m3[6] = from.m3_6();
|
||||
to->m3[7] = from.m3_7();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
JavaScriptShared::findObjectById(JSContext* cx, const ObjectId& objId)
|
||||
{
|
||||
RootedObject obj(cx, objects_.find(objId));
|
||||
if (!obj) {
|
||||
JS_ReportErrorASCII(cx, "operation not possible on dead CPOW");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Each process has a dedicated compartment for CPOW targets. All CPOWs
|
||||
// from the other process point to objects in this scope. From there, they
|
||||
// can access objects in other compartments using cross-compartment
|
||||
// wrappers.
|
||||
JSAutoCompartment ac(cx, scopeForTargetObjects());
|
||||
if (objId.hasXrayWaiver()) {
|
||||
{
|
||||
JSAutoCompartment ac2(cx, obj);
|
||||
obj = js::ToWindowProxyIfWindow(obj);
|
||||
MOZ_ASSERT(obj);
|
||||
}
|
||||
if (!xpc::WrapperFactory::WaiveXrayAndWrap(cx, &obj))
|
||||
return nullptr;
|
||||
} else {
|
||||
if (!JS_WrapObject(cx, &obj))
|
||||
return nullptr;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
static const uint64_t UnknownPropertyOp = 1;
|
||||
|
||||
bool
|
||||
JavaScriptShared::fromDescriptor(JSContext* cx, Handle<PropertyDescriptor> desc,
|
||||
PPropertyDescriptor* out)
|
||||
{
|
||||
out->attrs() = desc.attributes();
|
||||
if (!toVariant(cx, desc.value(), &out->value()))
|
||||
return false;
|
||||
|
||||
if (!toObjectOrNullVariant(cx, desc.object(), &out->obj()))
|
||||
return false;
|
||||
|
||||
if (!desc.getter()) {
|
||||
out->getter() = 0;
|
||||
} else if (desc.hasGetterObject()) {
|
||||
JSObject* getter = desc.getterObject();
|
||||
ObjectVariant objVar;
|
||||
if (!toObjectVariant(cx, getter, &objVar))
|
||||
return false;
|
||||
out->getter() = objVar;
|
||||
} else {
|
||||
MOZ_ASSERT(desc.getter() != JS_PropertyStub);
|
||||
out->getter() = UnknownPropertyOp;
|
||||
}
|
||||
|
||||
if (!desc.setter()) {
|
||||
out->setter() = 0;
|
||||
} else if (desc.hasSetterObject()) {
|
||||
JSObject* setter = desc.setterObject();
|
||||
ObjectVariant objVar;
|
||||
if (!toObjectVariant(cx, setter, &objVar))
|
||||
return false;
|
||||
out->setter() = objVar;
|
||||
} else {
|
||||
MOZ_ASSERT(desc.setter() != JS_StrictPropertyStub);
|
||||
out->setter() = UnknownPropertyOp;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
UnknownPropertyStub(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
|
||||
{
|
||||
JS_ReportErrorASCII(cx, "getter could not be wrapped via CPOWs");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
UnknownStrictPropertyStub(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp,
|
||||
ObjectOpResult& result)
|
||||
{
|
||||
JS_ReportErrorASCII(cx, "setter could not be wrapped via CPOWs");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::toDescriptor(JSContext* cx, const PPropertyDescriptor& in,
|
||||
MutableHandle<PropertyDescriptor> out)
|
||||
{
|
||||
out.setAttributes(in.attrs());
|
||||
if (!fromVariant(cx, in.value(), out.value()))
|
||||
return false;
|
||||
out.object().set(fromObjectOrNullVariant(cx, in.obj()));
|
||||
|
||||
if (in.getter().type() == GetterSetter::Tuint64_t && !in.getter().get_uint64_t()) {
|
||||
out.setGetter(nullptr);
|
||||
} else if (in.attrs() & JSPROP_GETTER) {
|
||||
Rooted<JSObject*> getter(cx);
|
||||
getter = fromObjectVariant(cx, in.getter().get_ObjectVariant());
|
||||
if (!getter)
|
||||
return false;
|
||||
out.setGetter(JS_DATA_TO_FUNC_PTR(JSGetterOp, getter.get()));
|
||||
} else {
|
||||
out.setGetter(UnknownPropertyStub);
|
||||
}
|
||||
|
||||
if (in.setter().type() == GetterSetter::Tuint64_t && !in.setter().get_uint64_t()) {
|
||||
out.setSetter(nullptr);
|
||||
} else if (in.attrs() & JSPROP_SETTER) {
|
||||
Rooted<JSObject*> setter(cx);
|
||||
setter = fromObjectVariant(cx, in.setter().get_ObjectVariant());
|
||||
if (!setter)
|
||||
return false;
|
||||
out.setSetter(JS_DATA_TO_FUNC_PTR(JSSetterOp, setter.get()));
|
||||
} else {
|
||||
out.setSetter(UnknownStrictPropertyStub);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::toObjectOrNullVariant(JSContext* cx, JSObject* obj, ObjectOrNullVariant* objVarp)
|
||||
{
|
||||
if (!obj) {
|
||||
*objVarp = NullVariant();
|
||||
return true;
|
||||
}
|
||||
|
||||
ObjectVariant objVar;
|
||||
if (!toObjectVariant(cx, obj, &objVar))
|
||||
return false;
|
||||
|
||||
*objVarp = objVar;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
JavaScriptShared::fromObjectOrNullVariant(JSContext* cx, const ObjectOrNullVariant& objVar)
|
||||
{
|
||||
if (objVar.type() == ObjectOrNullVariant::TNullVariant)
|
||||
return nullptr;
|
||||
|
||||
return fromObjectVariant(cx, objVar.get_ObjectVariant());
|
||||
}
|
||||
|
||||
CrossProcessCpowHolder::CrossProcessCpowHolder(dom::CPOWManagerGetter* managerGetter,
|
||||
const InfallibleTArray<CpowEntry>& cpows)
|
||||
: js_(nullptr),
|
||||
cpows_(cpows),
|
||||
unwrapped_(false)
|
||||
{
|
||||
// Only instantiate the CPOW manager if we might need it later.
|
||||
if (cpows.Length())
|
||||
js_ = managerGetter->GetCPOWManager();
|
||||
}
|
||||
|
||||
CrossProcessCpowHolder::~CrossProcessCpowHolder()
|
||||
{
|
||||
if (cpows_.Length() && !unwrapped_) {
|
||||
// This should only happen if a message manager message
|
||||
// containing CPOWs gets ignored for some reason. We need to
|
||||
// unwrap every incoming CPOW in this process to ensure that
|
||||
// the corresponding part of the CPOW in the other process
|
||||
// will eventually be collected. The scope for this object
|
||||
// doesn't really matter, because it immediately becomes
|
||||
// garbage.
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(xpc::PrivilegedJunkScope()))
|
||||
return;
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> cpows(cx);
|
||||
js_->Unwrap(cx, cpows_, &cpows);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CrossProcessCpowHolder::ToObject(JSContext* cx, JS::MutableHandleObject objp)
|
||||
{
|
||||
unwrapped_ = true;
|
||||
|
||||
if (!cpows_.Length())
|
||||
return true;
|
||||
|
||||
return js_->Unwrap(cx, cpows_, objp);
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::Unwrap(JSContext* cx, const InfallibleTArray<CpowEntry>& aCpows,
|
||||
JS::MutableHandleObject objp)
|
||||
{
|
||||
objp.set(nullptr);
|
||||
|
||||
if (!aCpows.Length())
|
||||
return true;
|
||||
|
||||
RootedObject obj(cx, JS_NewPlainObject(cx));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
RootedValue v(cx);
|
||||
RootedString str(cx);
|
||||
for (size_t i = 0; i < aCpows.Length(); i++) {
|
||||
const nsString& name = aCpows[i].name();
|
||||
|
||||
if (!fromVariant(cx, aCpows[i].value(), &v))
|
||||
return false;
|
||||
|
||||
if (!JS_DefineUCProperty(cx,
|
||||
obj,
|
||||
name.BeginReading(),
|
||||
name.Length(),
|
||||
v,
|
||||
JSPROP_ENUMERATE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
objp.set(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JavaScriptShared::Wrap(JSContext* cx, HandleObject aObj, InfallibleTArray<CpowEntry>* outCpows)
|
||||
{
|
||||
if (!aObj)
|
||||
return true;
|
||||
|
||||
Rooted<IdVector> ids(cx, IdVector(cx));
|
||||
if (!JS_Enumerate(cx, aObj, &ids))
|
||||
return false;
|
||||
|
||||
RootedId id(cx);
|
||||
RootedValue v(cx);
|
||||
for (size_t i = 0; i < ids.length(); i++) {
|
||||
id = ids[i];
|
||||
|
||||
nsString str;
|
||||
if (!convertIdToGeckoString(cx, id, &str))
|
||||
return false;
|
||||
|
||||
if (!JS_GetPropertyById(cx, aObj, id, &v))
|
||||
return false;
|
||||
|
||||
JSVariant var;
|
||||
if (!toVariant(cx, v, &var))
|
||||
return false;
|
||||
|
||||
outCpows->AppendElement(CpowEntry(str, var));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CPOWManager*
|
||||
mozilla::jsipc::CPOWManagerFor(PJavaScriptParent* aParent)
|
||||
{
|
||||
return static_cast<JavaScriptParent*>(aParent);
|
||||
}
|
||||
|
||||
CPOWManager*
|
||||
mozilla::jsipc::CPOWManagerFor(PJavaScriptChild* aChild)
|
||||
{
|
||||
return static_cast<JavaScriptChild*>(aChild);
|
||||
}
|
||||
236
js/ipc/JavaScriptShared.h
Normal file
236
js/ipc/JavaScriptShared.h
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
/* -*- 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_JavaScriptShared_h__
|
||||
#define mozilla_jsipc_JavaScriptShared_h__
|
||||
|
||||
#include "mozilla/dom/DOMTypes.h"
|
||||
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
#include "mozilla/jsipc/PJavaScript.h"
|
||||
#include "js/GCHashTable.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
class ObjectId {
|
||||
public:
|
||||
// Use 47 bits at most, to be safe, since jsval privates are encoded as
|
||||
// doubles. See bug 1065811 comment 12 for an explanation.
|
||||
static const size_t SERIAL_NUMBER_BITS = 47;
|
||||
static const size_t FLAG_BITS = 1;
|
||||
static const uint64_t SERIAL_NUMBER_MAX = (uint64_t(1) << SERIAL_NUMBER_BITS) - 1;
|
||||
|
||||
explicit ObjectId(uint64_t serialNumber, bool hasXrayWaiver)
|
||||
: serialNumber_(serialNumber), hasXrayWaiver_(hasXrayWaiver)
|
||||
{
|
||||
if (MOZ_UNLIKELY(serialNumber == 0 || serialNumber > SERIAL_NUMBER_MAX))
|
||||
MOZ_CRASH("Bad CPOW Id");
|
||||
}
|
||||
|
||||
bool operator==(const ObjectId& other) const {
|
||||
bool equal = serialNumber() == other.serialNumber();
|
||||
MOZ_ASSERT_IF(equal, hasXrayWaiver() == other.hasXrayWaiver());
|
||||
return equal;
|
||||
}
|
||||
|
||||
bool isNull() { return !serialNumber_; }
|
||||
|
||||
uint64_t serialNumber() const { return serialNumber_; }
|
||||
bool hasXrayWaiver() const { return hasXrayWaiver_; }
|
||||
uint64_t serialize() const {
|
||||
MOZ_ASSERT(serialNumber(), "Don't send a null ObjectId over IPC");
|
||||
return uint64_t((serialNumber() << FLAG_BITS) | ((hasXrayWaiver() ? 1 : 0) << 0));
|
||||
}
|
||||
|
||||
static ObjectId nullId() { return ObjectId(); }
|
||||
static ObjectId deserialize(uint64_t data) {
|
||||
return ObjectId(data >> FLAG_BITS, data & 1);
|
||||
}
|
||||
|
||||
// For use with StructGCPolicy.
|
||||
void trace(JSTracer*) const {}
|
||||
bool needsSweep() const { return false; }
|
||||
|
||||
private:
|
||||
ObjectId() : serialNumber_(0), hasXrayWaiver_(false) {}
|
||||
|
||||
uint64_t serialNumber_ : SERIAL_NUMBER_BITS;
|
||||
bool hasXrayWaiver_ : 1;
|
||||
};
|
||||
|
||||
class JavaScriptShared;
|
||||
|
||||
// DefaultHasher<T> requires that T coerce to an integral type. We could make
|
||||
// ObjectId do that, but doing so would weaken our type invariants, so we just
|
||||
// reimplement it manually.
|
||||
struct ObjectIdHasher
|
||||
{
|
||||
typedef ObjectId Lookup;
|
||||
static js::HashNumber hash(const Lookup& l) {
|
||||
return l.serialize();
|
||||
}
|
||||
static bool match(const ObjectId& k, const ObjectId& l) {
|
||||
return k == l;
|
||||
}
|
||||
static void rekey(ObjectId& k, const ObjectId& newKey) {
|
||||
k = newKey;
|
||||
}
|
||||
};
|
||||
|
||||
// Map ids -> JSObjects
|
||||
class IdToObjectMap
|
||||
{
|
||||
typedef js::HashMap<ObjectId, JS::Heap<JSObject*>, ObjectIdHasher, js::SystemAllocPolicy> Table;
|
||||
|
||||
public:
|
||||
IdToObjectMap();
|
||||
|
||||
bool init();
|
||||
void trace(JSTracer* trc, uint64_t minimumId = 0);
|
||||
void sweep();
|
||||
|
||||
bool add(ObjectId id, JSObject* obj);
|
||||
JSObject* find(ObjectId id);
|
||||
void remove(ObjectId id);
|
||||
|
||||
void clear();
|
||||
bool empty() const;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool has(const ObjectId& id, const JSObject* obj) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
Table table_;
|
||||
};
|
||||
|
||||
// Map JSObjects -> ids
|
||||
class ObjectToIdMap
|
||||
{
|
||||
using Hasher = js::MovableCellHasher<JS::Heap<JSObject*>>;
|
||||
using Table = JS::GCHashMap<JS::Heap<JSObject*>, ObjectId, Hasher, js::SystemAllocPolicy>;
|
||||
|
||||
public:
|
||||
bool init();
|
||||
void trace(JSTracer* trc);
|
||||
void sweep();
|
||||
|
||||
bool add(JSContext* cx, JSObject* obj, ObjectId id);
|
||||
ObjectId find(JSObject* obj);
|
||||
void remove(JSObject* obj);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
Table table_;
|
||||
};
|
||||
|
||||
class Logging;
|
||||
|
||||
class JavaScriptShared : public CPOWManager
|
||||
{
|
||||
public:
|
||||
JavaScriptShared();
|
||||
virtual ~JavaScriptShared();
|
||||
|
||||
bool init();
|
||||
|
||||
void decref();
|
||||
void incref();
|
||||
|
||||
bool Unwrap(JSContext* cx, const InfallibleTArray<CpowEntry>& aCpows, JS::MutableHandleObject objp);
|
||||
bool Wrap(JSContext* cx, JS::HandleObject aObj, InfallibleTArray<CpowEntry>* outCpows);
|
||||
|
||||
protected:
|
||||
bool toVariant(JSContext* cx, JS::HandleValue from, JSVariant* to);
|
||||
bool fromVariant(JSContext* cx, const JSVariant& from, JS::MutableHandleValue to);
|
||||
|
||||
bool toJSIDVariant(JSContext* cx, JS::HandleId from, JSIDVariant* to);
|
||||
bool fromJSIDVariant(JSContext* cx, const JSIDVariant& from, JS::MutableHandleId to);
|
||||
|
||||
bool toSymbolVariant(JSContext* cx, JS::Symbol* sym, SymbolVariant* symVarp);
|
||||
JS::Symbol* fromSymbolVariant(JSContext* cx, const SymbolVariant& symVar);
|
||||
|
||||
bool fromDescriptor(JSContext* cx, JS::Handle<JS::PropertyDescriptor> desc,
|
||||
PPropertyDescriptor* out);
|
||||
bool toDescriptor(JSContext* cx, const PPropertyDescriptor& in,
|
||||
JS::MutableHandle<JS::PropertyDescriptor> out);
|
||||
|
||||
bool toObjectOrNullVariant(JSContext* cx, JSObject* obj, ObjectOrNullVariant* objVarp);
|
||||
JSObject* fromObjectOrNullVariant(JSContext* cx, const ObjectOrNullVariant& objVar);
|
||||
|
||||
bool convertIdToGeckoString(JSContext* cx, JS::HandleId id, nsString* to);
|
||||
bool convertGeckoStringToId(JSContext* cx, const nsString& from, JS::MutableHandleId id);
|
||||
|
||||
virtual bool toObjectVariant(JSContext* cx, JSObject* obj, ObjectVariant* objVarp) = 0;
|
||||
virtual JSObject* fromObjectVariant(JSContext* cx, const ObjectVariant& objVar) = 0;
|
||||
|
||||
static void ConvertID(const nsID& from, JSIID* to);
|
||||
static void ConvertID(const JSIID& from, nsID* to);
|
||||
|
||||
JSObject* findCPOWById(const ObjectId& objId) {
|
||||
return cpows_.find(objId);
|
||||
}
|
||||
JSObject* findObjectById(JSContext* cx, const ObjectId& objId);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool hasCPOW(const ObjectId& objId, const JSObject* obj) {
|
||||
return cpows_.has(objId, obj);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool LoggingEnabled() { return sLoggingEnabled; }
|
||||
static bool StackLoggingEnabled() { return sStackLoggingEnabled; }
|
||||
|
||||
friend class Logging;
|
||||
|
||||
virtual bool isParent() = 0;
|
||||
|
||||
virtual JSObject* scopeForTargetObjects() = 0;
|
||||
|
||||
protected:
|
||||
uintptr_t refcount_;
|
||||
|
||||
IdToObjectMap objects_;
|
||||
IdToObjectMap cpows_;
|
||||
|
||||
uint64_t nextSerialNumber_;
|
||||
|
||||
// nextCPOWNumber_ should be the value of nextSerialNumber_ in the other
|
||||
// process. The next new CPOW we get should have this serial number.
|
||||
uint64_t nextCPOWNumber_;
|
||||
|
||||
// CPOW references can be weak, and any object we store in a map may be
|
||||
// GCed (at which point the CPOW will report itself "dead" to the owner).
|
||||
// This means that we don't want to store any js::Wrappers in the CPOW map,
|
||||
// because CPOW will die if the wrapper is GCed, even if the underlying
|
||||
// object is still alive.
|
||||
//
|
||||
// This presents a tricky situation for Xray waivers, since they're normally
|
||||
// represented as a special same-compartment wrapper. We have to strip them
|
||||
// off before putting them in the id-to-object and object-to-id maps, so we
|
||||
// need a way of distinguishing them at lookup-time.
|
||||
//
|
||||
// For the id-to-object map, we encode waiver-or-not information into the id
|
||||
// itself, which lets us do the right thing when accessing the object.
|
||||
//
|
||||
// For the object-to-id map, we just keep two maps, one for each type.
|
||||
ObjectToIdMap unwaivedObjectIds_;
|
||||
ObjectToIdMap waivedObjectIds_;
|
||||
ObjectToIdMap& objectIdMap(bool waiver) {
|
||||
return waiver ? waivedObjectIds_ : unwaivedObjectIds_;
|
||||
}
|
||||
|
||||
static bool sLoggingInitialized;
|
||||
static bool sLoggingEnabled;
|
||||
static bool sStackLoggingEnabled;
|
||||
};
|
||||
|
||||
} // namespace jsipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
161
js/ipc/JavaScriptTypes.ipdlh
Normal file
161
js/ipc/JavaScriptTypes.ipdlh
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/* -*- 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 DOMTypes;
|
||||
|
||||
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
struct JSIID
|
||||
{
|
||||
uint32_t m0;
|
||||
uint16_t m1;
|
||||
uint16_t m2;
|
||||
uint8_t m3_0;
|
||||
uint8_t m3_1;
|
||||
uint8_t m3_2;
|
||||
uint8_t m3_3;
|
||||
uint8_t m3_4;
|
||||
uint8_t m3_5;
|
||||
uint8_t m3_6;
|
||||
uint8_t m3_7;
|
||||
};
|
||||
|
||||
struct LocalObject
|
||||
{
|
||||
uint64_t serializedId;
|
||||
};
|
||||
|
||||
struct RemoteObject
|
||||
{
|
||||
uint64_t serializedId;
|
||||
bool isCallable;
|
||||
bool isConstructor;
|
||||
bool isDOMObject;
|
||||
nsCString objectTag;
|
||||
};
|
||||
|
||||
union ObjectVariant
|
||||
{
|
||||
LocalObject;
|
||||
RemoteObject;
|
||||
};
|
||||
|
||||
struct WellKnownSymbol
|
||||
{
|
||||
uint32_t which;
|
||||
};
|
||||
|
||||
struct RegisteredSymbol
|
||||
{
|
||||
nsString key;
|
||||
};
|
||||
|
||||
union SymbolVariant
|
||||
{
|
||||
WellKnownSymbol;
|
||||
RegisteredSymbol;
|
||||
};
|
||||
|
||||
struct UndefinedVariant {};
|
||||
struct NullVariant {};
|
||||
|
||||
union ObjectOrNullVariant
|
||||
{
|
||||
ObjectVariant;
|
||||
NullVariant;
|
||||
};
|
||||
|
||||
union JSVariant
|
||||
{
|
||||
UndefinedVariant;
|
||||
NullVariant;
|
||||
ObjectVariant;
|
||||
SymbolVariant;
|
||||
nsString; /* StringValue(x) */
|
||||
double; /* NumberValue(x) */
|
||||
bool; /* BooleanValue(x) */
|
||||
JSIID; /* XPC nsIID */
|
||||
};
|
||||
|
||||
union JSIDVariant
|
||||
{
|
||||
SymbolVariant;
|
||||
nsString;
|
||||
int32_t;
|
||||
};
|
||||
|
||||
struct ReturnSuccess
|
||||
{
|
||||
};
|
||||
|
||||
struct ReturnStopIteration
|
||||
{
|
||||
};
|
||||
|
||||
struct ReturnDeadCPOW
|
||||
{
|
||||
};
|
||||
|
||||
struct ReturnException
|
||||
{
|
||||
JSVariant exn;
|
||||
};
|
||||
|
||||
struct ReturnObjectOpResult
|
||||
{
|
||||
uint32_t code;
|
||||
};
|
||||
|
||||
union ReturnStatus
|
||||
{
|
||||
ReturnSuccess;
|
||||
ReturnStopIteration;
|
||||
ReturnDeadCPOW;
|
||||
ReturnException;
|
||||
ReturnObjectOpResult;
|
||||
};
|
||||
|
||||
union JSParam
|
||||
{
|
||||
void_t; /* value is strictly an xpc out param */
|
||||
JSVariant; /* actual value to pass through */
|
||||
};
|
||||
|
||||
union GetterSetter
|
||||
{
|
||||
uint64_t;
|
||||
ObjectVariant;
|
||||
};
|
||||
|
||||
struct PPropertyDescriptor
|
||||
{
|
||||
ObjectOrNullVariant obj;
|
||||
uint32_t attrs;
|
||||
JSVariant value;
|
||||
|
||||
// How to interpret these values depends on whether JSPROP_GETTER/SETTER
|
||||
// are set. If set, the corresponding value is a CPOW or 0 for NULL.
|
||||
// Otherwise, the following table is used:
|
||||
//
|
||||
// 0 - NULL
|
||||
// 1 - Default getter or setter.
|
||||
// 2 - Unknown
|
||||
GetterSetter getter;
|
||||
GetterSetter setter;
|
||||
};
|
||||
|
||||
struct CpowEntry
|
||||
{
|
||||
nsString name;
|
||||
JSVariant value;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
60
js/ipc/PJavaScript.ipdl
Normal file
60
js/ipc/PJavaScript.ipdl
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/* -*- 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 protocol PContent;
|
||||
include protocol PContentBridge;
|
||||
include DOMTypes;
|
||||
include JavaScriptTypes;
|
||||
|
||||
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
nested(upto inside_sync) sync protocol PJavaScript
|
||||
{
|
||||
manager PContent or PContentBridge;
|
||||
|
||||
both:
|
||||
// Sent when a CPOW has been finalized and table entries can be freed up.
|
||||
async DropObject(uint64_t objId);
|
||||
|
||||
// These roughly map to the ProxyHandler hooks that CPOWs need.
|
||||
nested(inside_sync) sync PreventExtensions(uint64_t objId) returns (ReturnStatus rs);
|
||||
nested(inside_sync) sync GetPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
|
||||
nested(inside_sync) sync GetOwnPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
|
||||
nested(inside_sync) sync DefineProperty(uint64_t objId, JSIDVariant id, PPropertyDescriptor descriptor) returns (ReturnStatus rs);
|
||||
nested(inside_sync) sync Delete(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs);
|
||||
|
||||
nested(inside_sync) sync Has(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
|
||||
nested(inside_sync) sync HasOwn(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
|
||||
nested(inside_sync) sync Get(uint64_t objId, JSVariant receiver, JSIDVariant id) returns (ReturnStatus rs, JSVariant result);
|
||||
nested(inside_sync) sync Set(uint64_t objId, JSIDVariant id, JSVariant value, JSVariant receiver) returns (ReturnStatus rs);
|
||||
|
||||
nested(inside_sync) sync IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
|
||||
nested(inside_sync) sync CallOrConstruct(uint64_t objId, JSParam[] argv, bool construct) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);
|
||||
nested(inside_sync) sync HasInstance(uint64_t objId, JSVariant v) returns (ReturnStatus rs, bool has);
|
||||
nested(inside_sync) sync GetBuiltinClass(uint64_t objId) returns (ReturnStatus rs, uint32_t classValue);
|
||||
nested(inside_sync) sync IsArray(uint64_t objId) returns (ReturnStatus rs, uint32_t ans);
|
||||
nested(inside_sync) sync ClassName(uint64_t objId) returns (nsCString name);
|
||||
nested(inside_sync) sync GetPrototype(uint64_t objId) returns (ReturnStatus rs, ObjectOrNullVariant result);
|
||||
nested(inside_sync) sync GetPrototypeIfOrdinary(uint64_t objId) returns (ReturnStatus rs, bool isOrdinary, ObjectOrNullVariant result);
|
||||
nested(inside_sync) sync RegExpToShared(uint64_t objId) returns (ReturnStatus rs, nsString source, uint32_t flags);
|
||||
|
||||
nested(inside_sync) sync GetPropertyKeys(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, JSIDVariant[] ids);
|
||||
nested(inside_sync) sync InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
|
||||
nested(inside_sync) sync DOMInstanceOf(uint64_t objId, int prototypeID, int depth) returns (ReturnStatus rs, bool instanceof);
|
||||
|
||||
parent:
|
||||
async __delete__();
|
||||
|
||||
child:
|
||||
async DropTemporaryStrongReferences(uint64_t upToObjId);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
798
js/ipc/WrapperAnswer.cpp
Normal file
798
js/ipc/WrapperAnswer.cpp
Normal file
|
|
@ -0,0 +1,798 @@
|
|||
/* -*- 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 "WrapperAnswer.h"
|
||||
#include "JavaScriptLogging.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "js/Class.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
using namespace JS;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::jsipc;
|
||||
|
||||
// Note - Using AutoJSAPI (rather than AutoEntryScript) for a trap means
|
||||
// that we don't expect it to run script. For most of these traps that will only
|
||||
// happen if the target is a scripted proxy, which is probably something that we
|
||||
// don't want to support over CPOWs. When enough code is fixed up, the long-term
|
||||
// plan is to have the JS engine throw if it encounters script when it isn't
|
||||
// expecting it.
|
||||
using mozilla::dom::AutoJSAPI;
|
||||
using mozilla::dom::AutoEntryScript;
|
||||
|
||||
static void
|
||||
MaybeForceDebugGC()
|
||||
{
|
||||
static bool sEnvVarInitialized = false;
|
||||
static bool sDebugGCs = false;
|
||||
|
||||
if (!sEnvVarInitialized)
|
||||
sDebugGCs = !!PR_GetEnv("MOZ_DEBUG_DEAD_CPOWS");
|
||||
|
||||
if (sDebugGCs) {
|
||||
JSContext* cx = nsXPConnect::GetContextInstance()->Context();
|
||||
PrepareForFullGC(cx);
|
||||
GCForReason(cx, GC_NORMAL, gcreason::COMPONENT_UTILS);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::fail(AutoJSAPI& jsapi, ReturnStatus* rs)
|
||||
{
|
||||
// By default, we set |undefined| unless we can get a more meaningful
|
||||
// exception.
|
||||
*rs = ReturnStatus(ReturnException(JSVariant(UndefinedVariant())));
|
||||
|
||||
// Note we always return true from this function, since this propagates
|
||||
// to the IPC code, and we don't want a JS failure to cause the death
|
||||
// of the child process.
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
RootedValue exn(cx);
|
||||
if (!jsapi.HasException())
|
||||
return true;
|
||||
|
||||
if (!jsapi.StealException(&exn))
|
||||
return true;
|
||||
|
||||
if (JS_IsStopIteration(exn)) {
|
||||
*rs = ReturnStatus(ReturnStopIteration());
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this fails, we still don't want to exit. Just return an invalid
|
||||
// exception.
|
||||
(void) toVariant(cx, exn, &rs->get_ReturnException().exn());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::ok(ReturnStatus* rs)
|
||||
{
|
||||
*rs = ReturnStatus(ReturnSuccess());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::ok(ReturnStatus* rs, const JS::ObjectOpResult& result)
|
||||
{
|
||||
*rs = result
|
||||
? ReturnStatus(ReturnSuccess())
|
||||
: ReturnStatus(ReturnObjectOpResult(result.failureCode()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::deadCPOW(AutoJSAPI& jsapi, ReturnStatus* rs)
|
||||
{
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS_ClearPendingException(cx);
|
||||
*rs = ReturnStatus(ReturnDeadCPOW());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvPreventExtensions(const ObjectId& objId, ReturnStatus* rs)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
ObjectOpResult success;
|
||||
if (!JS_PreventExtensions(cx, obj, success))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
LOG("%s.preventExtensions()", ReceiverObj(objId));
|
||||
return ok(rs, success);
|
||||
}
|
||||
|
||||
static void
|
||||
EmptyDesc(PPropertyDescriptor* desc)
|
||||
{
|
||||
desc->obj() = LocalObject(0);
|
||||
desc->attrs() = 0;
|
||||
desc->value() = UndefinedVariant();
|
||||
desc->getter() = 0;
|
||||
desc->setter() = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvGetPropertyDescriptor(const ObjectId& objId, const JSIDVariant& idVar,
|
||||
ReturnStatus* rs, PPropertyDescriptor* out)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
EmptyDesc(out);
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
LOG("%s.getPropertyDescriptor(%s)", ReceiverObj(objId), Identifier(idVar));
|
||||
|
||||
RootedId id(cx);
|
||||
if (!fromJSIDVariant(cx, idVar, &id))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
Rooted<PropertyDescriptor> desc(cx);
|
||||
if (!JS_GetPropertyDescriptorById(cx, obj, id, &desc))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
if (!fromDescriptor(cx, desc, out))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvGetOwnPropertyDescriptor(const ObjectId& objId, const JSIDVariant& idVar,
|
||||
ReturnStatus* rs, PPropertyDescriptor* out)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
EmptyDesc(out);
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
LOG("%s.getOwnPropertyDescriptor(%s)", ReceiverObj(objId), Identifier(idVar));
|
||||
|
||||
RootedId id(cx);
|
||||
if (!fromJSIDVariant(cx, idVar, &id))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
Rooted<PropertyDescriptor> desc(cx);
|
||||
if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
if (!fromDescriptor(cx, desc, out))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvDefineProperty(const ObjectId& objId, const JSIDVariant& idVar,
|
||||
const PPropertyDescriptor& descriptor, ReturnStatus* rs)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
LOG("define %s[%s]", ReceiverObj(objId), Identifier(idVar));
|
||||
|
||||
RootedId id(cx);
|
||||
if (!fromJSIDVariant(cx, idVar, &id))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
Rooted<PropertyDescriptor> desc(cx);
|
||||
if (!toDescriptor(cx, descriptor, &desc))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
ObjectOpResult success;
|
||||
if (!JS_DefinePropertyById(cx, obj, id, desc, success))
|
||||
return fail(jsapi, rs);
|
||||
return ok(rs, success);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvDelete(const ObjectId& objId, const JSIDVariant& idVar, ReturnStatus* rs)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
LOG("delete %s[%s]", ReceiverObj(objId), Identifier(idVar));
|
||||
|
||||
RootedId id(cx);
|
||||
if (!fromJSIDVariant(cx, idVar, &id))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
ObjectOpResult success;
|
||||
if (!JS_DeletePropertyById(cx, obj, id, success))
|
||||
return fail(jsapi, rs);
|
||||
return ok(rs, success);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvHas(const ObjectId& objId, const JSIDVariant& idVar, ReturnStatus* rs,
|
||||
bool* foundp)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
*foundp = false;
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
LOG("%s.has(%s)", ReceiverObj(objId), Identifier(idVar));
|
||||
|
||||
RootedId id(cx);
|
||||
if (!fromJSIDVariant(cx, idVar, &id))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
if (!JS_HasPropertyById(cx, obj, id, foundp))
|
||||
return fail(jsapi, rs);
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvHasOwn(const ObjectId& objId, const JSIDVariant& idVar, ReturnStatus* rs,
|
||||
bool* foundp)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
*foundp = false;
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
LOG("%s.hasOwn(%s)", ReceiverObj(objId), Identifier(idVar));
|
||||
|
||||
RootedId id(cx);
|
||||
if (!fromJSIDVariant(cx, idVar, &id))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
if (!JS_HasOwnPropertyById(cx, obj, id, foundp))
|
||||
return fail(jsapi, rs);
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvGet(const ObjectId& objId, const JSVariant& receiverVar,
|
||||
const JSIDVariant& idVar, ReturnStatus* rs, JSVariant* result)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
// We may run scripted getters.
|
||||
AutoEntryScript aes(scopeForTargetObjects(),
|
||||
"Cross-Process Object Wrapper 'get'");
|
||||
JSContext* cx = aes.cx();
|
||||
|
||||
// The outparam will be written to the buffer, so it must be set even if
|
||||
// the parent won't read it.
|
||||
*result = UndefinedVariant();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(aes, rs);
|
||||
|
||||
RootedValue receiver(cx);
|
||||
if (!fromVariant(cx, receiverVar, &receiver))
|
||||
return fail(aes, rs);
|
||||
|
||||
RootedId id(cx);
|
||||
if (!fromJSIDVariant(cx, idVar, &id))
|
||||
return fail(aes, rs);
|
||||
|
||||
JS::RootedValue val(cx);
|
||||
if (!JS_ForwardGetPropertyTo(cx, obj, id, receiver, &val))
|
||||
return fail(aes, rs);
|
||||
|
||||
if (!toVariant(cx, val, result))
|
||||
return fail(aes, rs);
|
||||
|
||||
LOG("get %s.%s = %s", ReceiverObj(objId), Identifier(idVar), OutVariant(*result));
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvSet(const ObjectId& objId, const JSIDVariant& idVar, const JSVariant& value,
|
||||
const JSVariant& receiverVar, ReturnStatus* rs)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
// We may run scripted setters.
|
||||
AutoEntryScript aes(scopeForTargetObjects(),
|
||||
"Cross-Process Object Wrapper 'set'");
|
||||
JSContext* cx = aes.cx();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(aes, rs);
|
||||
|
||||
LOG("set %s[%s] = %s", ReceiverObj(objId), Identifier(idVar), InVariant(value));
|
||||
|
||||
RootedId id(cx);
|
||||
if (!fromJSIDVariant(cx, idVar, &id))
|
||||
return fail(aes, rs);
|
||||
|
||||
RootedValue val(cx);
|
||||
if (!fromVariant(cx, value, &val))
|
||||
return fail(aes, rs);
|
||||
|
||||
RootedValue receiver(cx);
|
||||
if (!fromVariant(cx, receiverVar, &receiver))
|
||||
return fail(aes, rs);
|
||||
|
||||
ObjectOpResult result;
|
||||
if (!JS_ForwardSetPropertyTo(cx, obj, id, val, receiver, result))
|
||||
return fail(aes, rs);
|
||||
|
||||
return ok(rs, result);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvIsExtensible(const ObjectId& objId, ReturnStatus* rs, bool* result)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
*result = false;
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
LOG("%s.isExtensible()", ReceiverObj(objId));
|
||||
|
||||
bool extensible;
|
||||
if (!JS_IsExtensible(cx, obj, &extensible))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
*result = !!extensible;
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvCallOrConstruct(const ObjectId& objId,
|
||||
InfallibleTArray<JSParam>&& argv,
|
||||
const bool& construct,
|
||||
ReturnStatus* rs,
|
||||
JSVariant* result,
|
||||
nsTArray<JSParam>* outparams)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoEntryScript aes(scopeForTargetObjects(),
|
||||
"Cross-Process Object Wrapper call/construct");
|
||||
JSContext* cx = aes.cx();
|
||||
|
||||
// The outparam will be written to the buffer, so it must be set even if
|
||||
// the parent won't read it.
|
||||
*result = UndefinedVariant();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(aes, rs);
|
||||
|
||||
MOZ_ASSERT(argv.Length() >= 2);
|
||||
|
||||
RootedValue objv(cx);
|
||||
if (!fromVariant(cx, argv[0], &objv))
|
||||
return fail(aes, rs);
|
||||
|
||||
*result = JSVariant(UndefinedVariant());
|
||||
|
||||
AutoValueVector vals(cx);
|
||||
AutoValueVector outobjects(cx);
|
||||
for (size_t i = 0; i < argv.Length(); i++) {
|
||||
if (argv[i].type() == JSParam::Tvoid_t) {
|
||||
// This is an outparam.
|
||||
RootedObject obj(cx, xpc::NewOutObject(cx));
|
||||
if (!obj)
|
||||
return fail(aes, rs);
|
||||
if (!outobjects.append(ObjectValue(*obj)))
|
||||
return fail(aes, rs);
|
||||
if (!vals.append(ObjectValue(*obj)))
|
||||
return fail(aes, rs);
|
||||
} else {
|
||||
RootedValue v(cx);
|
||||
if (!fromVariant(cx, argv[i].get_JSVariant(), &v))
|
||||
return fail(aes, rs);
|
||||
if (!vals.append(v))
|
||||
return fail(aes, rs);
|
||||
}
|
||||
}
|
||||
|
||||
RootedValue rval(cx);
|
||||
{
|
||||
HandleValueArray args = HandleValueArray::subarray(vals, 2, vals.length() - 2);
|
||||
if (construct) {
|
||||
RootedObject obj(cx);
|
||||
if (!JS::Construct(cx, vals[0], args, &obj))
|
||||
return fail(aes, rs);
|
||||
rval.setObject(*obj);
|
||||
} else {
|
||||
if(!JS::Call(cx, vals[1], vals[0], args, &rval))
|
||||
return fail(aes, rs);
|
||||
}
|
||||
}
|
||||
|
||||
if (!toVariant(cx, rval, result))
|
||||
return fail(aes, rs);
|
||||
|
||||
// Prefill everything with a dummy jsval.
|
||||
for (size_t i = 0; i < outobjects.length(); i++)
|
||||
outparams->AppendElement(JSParam(void_t()));
|
||||
|
||||
// Go through each argument that was an outparam, retrieve the "value"
|
||||
// field, and add it to a temporary list. We need to do this separately
|
||||
// because the outparams vector is not rooted.
|
||||
vals.clear();
|
||||
for (size_t i = 0; i < outobjects.length(); i++) {
|
||||
RootedObject obj(cx, &outobjects[i].toObject());
|
||||
|
||||
RootedValue v(cx);
|
||||
bool found;
|
||||
if (JS_HasProperty(cx, obj, "value", &found)) {
|
||||
if (!JS_GetProperty(cx, obj, "value", &v))
|
||||
return fail(aes, rs);
|
||||
} else {
|
||||
v = UndefinedValue();
|
||||
}
|
||||
if (!vals.append(v))
|
||||
return fail(aes, rs);
|
||||
}
|
||||
|
||||
// Copy the outparams. If any outparam is already set to a void_t, we
|
||||
// treat this as the outparam never having been set.
|
||||
for (size_t i = 0; i < vals.length(); i++) {
|
||||
JSVariant variant;
|
||||
if (!toVariant(cx, vals[i], &variant))
|
||||
return fail(aes, rs);
|
||||
outparams->ReplaceElementAt(i, JSParam(variant));
|
||||
}
|
||||
|
||||
LOG("%s.call(%s) = %s", ReceiverObj(objId), argv, OutVariant(*result));
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvHasInstance(const ObjectId& objId, const JSVariant& vVar, ReturnStatus* rs, bool* bp)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
LOG("%s.hasInstance(%s)", ReceiverObj(objId), InVariant(vVar));
|
||||
|
||||
RootedValue val(cx);
|
||||
if (!fromVariant(cx, vVar, &val))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
if (!JS_HasInstance(cx, obj, val, bp))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvGetBuiltinClass(const ObjectId& objId, ReturnStatus* rs,
|
||||
uint32_t* classValue)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
*classValue = uint32_t(js::ESClass::Other);
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
LOG("%s.getBuiltinClass()", ReceiverObj(objId));
|
||||
|
||||
js::ESClass cls;
|
||||
if (!js::GetBuiltinClass(cx, obj, &cls))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
*classValue = uint32_t(cls);
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvIsArray(const ObjectId& objId, ReturnStatus* rs,
|
||||
uint32_t* ans)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
*ans = uint32_t(IsArrayAnswer::NotArray);
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
LOG("%s.isArray()", ReceiverObj(objId));
|
||||
|
||||
IsArrayAnswer answer;
|
||||
if (!JS::IsArray(cx, obj, &answer))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
*ans = uint32_t(answer);
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvClassName(const ObjectId& objId, nsCString* name)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj) {
|
||||
// This is very unfortunate, but we have no choice.
|
||||
*name = "<dead CPOW>";
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG("%s.className()", ReceiverObj(objId));
|
||||
|
||||
*name = js::ObjectClassName(cx, obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvGetPrototype(const ObjectId& objId, ReturnStatus* rs, ObjectOrNullVariant* result)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
*result = NullVariant();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
JS::RootedObject proto(cx);
|
||||
if (!JS_GetPrototype(cx, obj, &proto))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
if (!toObjectOrNullVariant(cx, proto, result))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
LOG("getPrototype(%s)", ReceiverObj(objId));
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvGetPrototypeIfOrdinary(const ObjectId& objId, ReturnStatus* rs, bool* isOrdinary,
|
||||
ObjectOrNullVariant* result)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
*result = NullVariant();
|
||||
*isOrdinary = false;
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
JS::RootedObject proto(cx);
|
||||
if (!JS_GetPrototypeIfOrdinary(cx, obj, isOrdinary, &proto))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
if (!toObjectOrNullVariant(cx, proto, result))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
LOG("getPrototypeIfOrdinary(%s)", ReceiverObj(objId));
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvRegExpToShared(const ObjectId& objId, ReturnStatus* rs,
|
||||
nsString* source, uint32_t* flags)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
RootedString sourceJSStr(cx, JS_GetRegExpSource(cx, obj));
|
||||
if (!sourceJSStr)
|
||||
return fail(jsapi, rs);
|
||||
nsAutoJSString sourceStr;
|
||||
if (!sourceStr.init(cx, sourceJSStr))
|
||||
return fail(jsapi, rs);
|
||||
source->Assign(sourceStr);
|
||||
|
||||
*flags = JS_GetRegExpFlags(cx, obj);
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvGetPropertyKeys(const ObjectId& objId, const uint32_t& flags,
|
||||
ReturnStatus* rs, nsTArray<JSIDVariant>* ids)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
LOG("%s.getPropertyKeys()", ReceiverObj(objId));
|
||||
|
||||
AutoIdVector props(cx);
|
||||
if (!js::GetPropertyKeys(cx, obj, flags, &props))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
for (size_t i = 0; i < props.length(); i++) {
|
||||
JSIDVariant id;
|
||||
if (!toJSIDVariant(cx, props[i], &id))
|
||||
return fail(jsapi, rs);
|
||||
|
||||
ids->AppendElement(id);
|
||||
}
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvInstanceOf(const ObjectId& objId, const JSIID& iid, ReturnStatus* rs,
|
||||
bool* instanceof)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
*instanceof = false;
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
LOG("%s.instanceOf()", ReceiverObj(objId));
|
||||
|
||||
nsID nsiid;
|
||||
ConvertID(iid, &nsiid);
|
||||
|
||||
nsresult rv = xpc::HasInstance(cx, obj, &nsiid, instanceof);
|
||||
if (rv != NS_OK)
|
||||
return fail(jsapi, rs);
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvDOMInstanceOf(const ObjectId& objId, const int& prototypeID,
|
||||
const int& depth, ReturnStatus* rs, bool* instanceof)
|
||||
{
|
||||
MaybeForceDebugGC();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
|
||||
return false;
|
||||
JSContext* cx = jsapi.cx();
|
||||
*instanceof = false;
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return deadCPOW(jsapi, rs);
|
||||
|
||||
LOG("%s.domInstanceOf()", ReceiverObj(objId));
|
||||
|
||||
bool tmp;
|
||||
if (!mozilla::dom::InterfaceHasInstance(cx, prototypeID, depth, obj, &tmp))
|
||||
return fail(jsapi, rs);
|
||||
*instanceof = tmp;
|
||||
|
||||
return ok(rs);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvDropObject(const ObjectId& objId)
|
||||
{
|
||||
JSObject* obj = objects_.find(objId);
|
||||
if (obj) {
|
||||
objectIdMap(objId.hasXrayWaiver()).remove(obj);
|
||||
objects_.remove(objId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
80
js/ipc/WrapperAnswer.h
Normal file
80
js/ipc/WrapperAnswer.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_jsipc_WrapperAnswer_h_
|
||||
#define mozilla_jsipc_WrapperAnswer_h_
|
||||
|
||||
#include "JavaScriptShared.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class AutoJSAPI;
|
||||
} // namespace dom
|
||||
|
||||
namespace jsipc {
|
||||
|
||||
class WrapperAnswer : public virtual JavaScriptShared
|
||||
{
|
||||
public:
|
||||
bool RecvPreventExtensions(const ObjectId& objId, ReturnStatus* rs);
|
||||
bool RecvGetPropertyDescriptor(const ObjectId& objId, const JSIDVariant& id,
|
||||
ReturnStatus* rs,
|
||||
PPropertyDescriptor* out);
|
||||
bool RecvGetOwnPropertyDescriptor(const ObjectId& objId,
|
||||
const JSIDVariant& id,
|
||||
ReturnStatus* rs,
|
||||
PPropertyDescriptor* out);
|
||||
bool RecvDefineProperty(const ObjectId& objId, const JSIDVariant& id,
|
||||
const PPropertyDescriptor& flags, ReturnStatus* rs);
|
||||
bool RecvDelete(const ObjectId& objId, const JSIDVariant& id, ReturnStatus* rs);
|
||||
|
||||
bool RecvHas(const ObjectId& objId, const JSIDVariant& id,
|
||||
ReturnStatus* rs, bool* foundp);
|
||||
bool RecvHasOwn(const ObjectId& objId, const JSIDVariant& id,
|
||||
ReturnStatus* rs, bool* foundp);
|
||||
bool RecvGet(const ObjectId& objId, const JSVariant& receiverVar,
|
||||
const JSIDVariant& id,
|
||||
ReturnStatus* rs, JSVariant* result);
|
||||
bool RecvSet(const ObjectId& objId, const JSIDVariant& id, const JSVariant& value,
|
||||
const JSVariant& receiverVar, ReturnStatus* rs);
|
||||
|
||||
bool RecvIsExtensible(const ObjectId& objId, ReturnStatus* rs,
|
||||
bool* result);
|
||||
bool RecvCallOrConstruct(const ObjectId& objId, InfallibleTArray<JSParam>&& argv,
|
||||
const bool& construct, ReturnStatus* rs, JSVariant* result,
|
||||
nsTArray<JSParam>* outparams);
|
||||
bool RecvHasInstance(const ObjectId& objId, const JSVariant& v, ReturnStatus* rs, bool* bp);
|
||||
bool RecvGetBuiltinClass(const ObjectId& objId, ReturnStatus* rs,
|
||||
uint32_t* classValue);
|
||||
bool RecvIsArray(const ObjectId& objId, ReturnStatus* rs, uint32_t* ans);
|
||||
bool RecvClassName(const ObjectId& objId, nsCString* result);
|
||||
bool RecvGetPrototype(const ObjectId& objId, ReturnStatus* rs, ObjectOrNullVariant* result);
|
||||
bool RecvGetPrototypeIfOrdinary(const ObjectId& objId, ReturnStatus* rs, bool* isOrdinary,
|
||||
ObjectOrNullVariant* result);
|
||||
bool RecvRegExpToShared(const ObjectId& objId, ReturnStatus* rs, nsString* source, uint32_t* flags);
|
||||
|
||||
bool RecvGetPropertyKeys(const ObjectId& objId, const uint32_t& flags,
|
||||
ReturnStatus* rs, nsTArray<JSIDVariant>* ids);
|
||||
bool RecvInstanceOf(const ObjectId& objId, const JSIID& iid,
|
||||
ReturnStatus* rs, bool* instanceof);
|
||||
bool RecvDOMInstanceOf(const ObjectId& objId, const int& prototypeID, const int& depth,
|
||||
ReturnStatus* rs, bool* instanceof);
|
||||
|
||||
bool RecvDropObject(const ObjectId& objId);
|
||||
|
||||
private:
|
||||
bool fail(dom::AutoJSAPI& jsapi, ReturnStatus* rs);
|
||||
bool ok(ReturnStatus* rs);
|
||||
bool ok(ReturnStatus* rs, const JS::ObjectOpResult& result);
|
||||
bool deadCPOW(dom::AutoJSAPI& jsapi, ReturnStatus* rs);
|
||||
};
|
||||
|
||||
} // namespace jsipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
1236
js/ipc/WrapperOwner.cpp
Normal file
1236
js/ipc/WrapperOwner.cpp
Normal file
File diff suppressed because it is too large
Load diff
167
js/ipc/WrapperOwner.h
Normal file
167
js/ipc/WrapperOwner.h
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/* -*- 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 "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
#include "js/Class.h"
|
||||
#include "js/Proxy.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
||||
class WrapperOwner : public virtual JavaScriptShared
|
||||
{
|
||||
public:
|
||||
typedef mozilla::ipc::IProtocol::ActorDestroyReason
|
||||
ActorDestroyReason;
|
||||
|
||||
WrapperOwner();
|
||||
bool init();
|
||||
|
||||
// Standard internal methods.
|
||||
// (The traps should be in the same order like js/Proxy.h)
|
||||
bool getOwnPropertyDescriptor(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
|
||||
JS::MutableHandle<JS::PropertyDescriptor> desc);
|
||||
bool defineProperty(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
|
||||
JS::Handle<JS::PropertyDescriptor> desc,
|
||||
JS::ObjectOpResult& result);
|
||||
bool ownPropertyKeys(JSContext* cx, JS::HandleObject proxy, JS::AutoIdVector& props);
|
||||
bool delete_(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
|
||||
JS::ObjectOpResult& result);
|
||||
bool preventExtensions(JSContext* cx, JS::HandleObject proxy, JS::ObjectOpResult& result);
|
||||
bool isExtensible(JSContext* cx, JS::HandleObject proxy, bool* extensible);
|
||||
bool has(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, bool* bp);
|
||||
bool get(JSContext* cx, JS::HandleObject proxy, JS::HandleValue receiver,
|
||||
JS::HandleId id, JS::MutableHandleValue vp);
|
||||
bool set(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
|
||||
JS::HandleValue receiver, JS::ObjectOpResult& result);
|
||||
bool callOrConstruct(JSContext* cx, JS::HandleObject proxy, const JS::CallArgs& args,
|
||||
bool construct);
|
||||
|
||||
// SpiderMonkey extensions.
|
||||
bool getPropertyDescriptor(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
|
||||
JS::MutableHandle<JS::PropertyDescriptor> desc);
|
||||
bool hasOwn(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, bool* bp);
|
||||
bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::HandleObject proxy,
|
||||
JS::AutoIdVector& props);
|
||||
bool hasInstance(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool* bp);
|
||||
bool getBuiltinClass(JSContext* cx, JS::HandleObject proxy, js::ESClass* cls);
|
||||
bool isArray(JSContext* cx, JS::HandleObject proxy, JS::IsArrayAnswer* answer);
|
||||
const char* className(JSContext* cx, JS::HandleObject proxy);
|
||||
bool getPrototype(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleObject protop);
|
||||
bool getPrototypeIfOrdinary(JSContext* cx, JS::HandleObject proxy, bool* isOrdinary,
|
||||
JS::MutableHandleObject protop);
|
||||
|
||||
bool regexp_toShared(JSContext* cx, JS::HandleObject proxy, js::RegExpGuard* g);
|
||||
|
||||
nsresult instanceOf(JSObject* obj, const nsID* id, bool* bp);
|
||||
|
||||
bool toString(JSContext* cx, JS::HandleObject callee, JS::CallArgs& args);
|
||||
bool DOMQI(JSContext* cx, JS::HandleObject callee, JS::CallArgs& args);
|
||||
|
||||
/*
|
||||
* 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 bool allowMessage(JSContext* cx) = 0;
|
||||
|
||||
void drop(JSObject* obj);
|
||||
void updatePointer(JSObject* obj, const JSObject* old);
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why);
|
||||
|
||||
virtual bool toObjectVariant(JSContext* cx, JSObject* obj, ObjectVariant* objVarp);
|
||||
virtual JSObject* fromObjectVariant(JSContext* cx, const ObjectVariant& objVar);
|
||||
JSObject* fromRemoteObjectVariant(JSContext* cx, const RemoteObject& objVar);
|
||||
JSObject* fromLocalObjectVariant(JSContext* cx, const LocalObject& objVar);
|
||||
|
||||
protected:
|
||||
ObjectId idOf(JSObject* obj);
|
||||
|
||||
private:
|
||||
ObjectId idOfUnchecked(JSObject* obj);
|
||||
|
||||
bool getPropertyKeys(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.
|
||||
//
|
||||
// If 'status' might be a ReturnObjectOpResult, which is only possible for
|
||||
// a subset of the operations below, 'result' must be passed.
|
||||
bool ok(JSContext* cx, const ReturnStatus& status, JS::ObjectOpResult& result);
|
||||
bool ok(JSContext* cx, const ReturnStatus& status);
|
||||
|
||||
bool inactive_;
|
||||
|
||||
/*** Dummy call handlers ***/
|
||||
public:
|
||||
virtual bool SendDropObject(const ObjectId& objId) = 0;
|
||||
virtual bool SendPreventExtensions(const ObjectId& objId, ReturnStatus* rs) = 0;
|
||||
virtual bool SendGetPropertyDescriptor(const ObjectId& objId, const JSIDVariant& id,
|
||||
ReturnStatus* rs,
|
||||
PPropertyDescriptor* out) = 0;
|
||||
virtual bool SendGetOwnPropertyDescriptor(const ObjectId& objId,
|
||||
const JSIDVariant& id,
|
||||
ReturnStatus* rs,
|
||||
PPropertyDescriptor* out) = 0;
|
||||
virtual bool SendDefineProperty(const ObjectId& objId, const JSIDVariant& id,
|
||||
const PPropertyDescriptor& flags,
|
||||
ReturnStatus* rs) = 0;
|
||||
virtual bool SendDelete(const ObjectId& objId, const JSIDVariant& id,
|
||||
ReturnStatus* rs) = 0;
|
||||
|
||||
virtual bool SendHas(const ObjectId& objId, const JSIDVariant& id,
|
||||
ReturnStatus* rs, bool* bp) = 0;
|
||||
virtual bool SendHasOwn(const ObjectId& objId, const JSIDVariant& id,
|
||||
ReturnStatus* rs, bool* bp) = 0;
|
||||
virtual bool SendGet(const ObjectId& objId, const JSVariant& receiverVar,
|
||||
const JSIDVariant& id,
|
||||
ReturnStatus* rs, JSVariant* result) = 0;
|
||||
virtual bool SendSet(const ObjectId& objId, const JSIDVariant& id, const JSVariant& value,
|
||||
const JSVariant& receiverVar, ReturnStatus* rs) = 0;
|
||||
|
||||
virtual bool SendIsExtensible(const ObjectId& objId, ReturnStatus* rs,
|
||||
bool* result) = 0;
|
||||
virtual bool SendCallOrConstruct(const ObjectId& objId, const nsTArray<JSParam>& argv,
|
||||
const bool& construct, ReturnStatus* rs, JSVariant* result,
|
||||
nsTArray<JSParam>* outparams) = 0;
|
||||
virtual bool SendHasInstance(const ObjectId& objId, const JSVariant& v,
|
||||
ReturnStatus* rs, bool* bp) = 0;
|
||||
virtual bool SendGetBuiltinClass(const ObjectId& objId, ReturnStatus* rs,
|
||||
uint32_t* classValue) = 0;
|
||||
virtual bool SendIsArray(const ObjectId& objId, ReturnStatus* rs,
|
||||
uint32_t* answer) = 0;
|
||||
virtual bool SendClassName(const ObjectId& objId, nsCString* result) = 0;
|
||||
virtual bool SendGetPrototype(const ObjectId& objId, ReturnStatus* rs, ObjectOrNullVariant* result) = 0;
|
||||
virtual bool SendGetPrototypeIfOrdinary(const ObjectId& objId, ReturnStatus* rs, bool* isOrdinary,
|
||||
ObjectOrNullVariant* result) = 0;
|
||||
virtual bool SendRegExpToShared(const ObjectId& objId, ReturnStatus* rs, nsString* source,
|
||||
uint32_t* flags) = 0;
|
||||
|
||||
virtual bool SendGetPropertyKeys(const ObjectId& objId, const uint32_t& flags,
|
||||
ReturnStatus* rs, nsTArray<JSIDVariant>* ids) = 0;
|
||||
virtual bool SendInstanceOf(const ObjectId& objId, const JSIID& iid,
|
||||
ReturnStatus* rs, bool* instanceof) = 0;
|
||||
virtual bool SendDOMInstanceOf(const ObjectId& objId, const int& prototypeID, const int& depth,
|
||||
ReturnStatus* rs, bool* instanceof) = 0;
|
||||
};
|
||||
|
||||
} // namespace jsipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_jsipc_WrapperOwner_h__
|
||||
41
js/ipc/moz.build
Normal file
41
js/ipc/moz.build
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'CPOWTimer.cpp',
|
||||
'JavaScriptChild.cpp',
|
||||
'JavaScriptParent.cpp',
|
||||
'JavaScriptShared.cpp',
|
||||
'WrapperAnswer.cpp',
|
||||
'WrapperOwner.cpp',
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'JavaScriptTypes.ipdlh',
|
||||
'PJavaScript.ipdl',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
DEFINES['BIN_SUFFIX'] = '"%s"' % CONFIG['BIN_SUFFIX']
|
||||
|
||||
EXPORTS.mozilla.jsipc = [
|
||||
'CpowHolder.h',
|
||||
'CrossProcessObjectWrappers.h',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/base',
|
||||
'/js/ipc',
|
||||
'/js/src',
|
||||
'/js/xpconnect/src',
|
||||
'/js/xpconnect/wrappers',
|
||||
]
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-shadow']
|
||||
Loading…
Add table
Add a link
Reference in a new issue