Implement CPOW support in MessageManager (bug 870180, r=smaug,billm).

This commit is contained in:
David Anderson 2013-07-10 15:05:39 -07:00
parent 66de98b043
commit 0930e61030
29 changed files with 649 additions and 146 deletions

View File

@ -17,4 +17,4 @@
#
# Modifying this file will now automatically clobber the buildbot machines \o/
#
Bug 870407 - move CMMSRCS to mozbuild
Bug 870180 - CPOWs

View File

@ -162,9 +162,8 @@ interface nsIMessageListener : nsISupports
* sync: %true or false%.
* data: %structured clone of the sent message data%,
* json: %same as .data, deprecated%,
* objects: %array of handles or null, always null if sync is false%
* objects: %named table of jsvals/objects, or null%
* }
* @note objects property isn't implemented yet.
*
* Each listener is invoked with its own copy of the message
* parameter.
@ -232,7 +231,8 @@ interface nsIMessageSender : nsIMessageListenerManager
*/
[implicit_jscontext, optional_argc]
void sendAsyncMessage([optional] in AString messageName,
[optional] in jsval obj);
[optional] in jsval obj,
[optional] in jsval objects);
};
/**
@ -255,7 +255,8 @@ interface nsIMessageBroadcaster : nsIMessageListenerManager
*/
[implicit_jscontext, optional_argc]
void broadcastAsyncMessage([optional] in AString messageName,
[optional] in jsval obj);
[optional] in jsval obj,
[optional] in jsval objects);
/**
* Number of subordinate message managers.
@ -278,7 +279,8 @@ interface nsISyncMessageSender : nsIMessageSender
*/
[implicit_jscontext, optional_argc]
jsval sendSyncMessage([optional] in AString messageName,
[optional] in jsval obj);
[optional] in jsval obj,
[optional] in jsval objects);
};
[scriptable, builtinclass, uuid(894ff2d4-39a3-4df8-9d76-8ee329975488)]

View File

@ -46,6 +46,7 @@ LOCAL_INCLUDES += \
-I$(topsrcdir)/content/xul/document/src \
-I$(topsrcdir)/dom/base \
-I$(topsrcdir)/dom/ipc \
-I$(topsrcdir)/js/ipc \
-I$(topsrcdir)/image/src \
-I$(topsrcdir)/js/xpconnect/src \
-I$(topsrcdir)/layout/base \

View File

@ -87,6 +87,7 @@
#include "jsapi.h"
#include "mozilla/dom/HTMLIFrameElement.h"
#include "nsSandboxFlags.h"
#include "JavaScriptParent.h"
#include "mozilla/dom/StructuredCloneUtils.h"
@ -2202,17 +2203,29 @@ nsFrameLoader::DoLoadFrameScript(const nsAString& aURL)
class nsAsyncMessageToChild : public nsRunnable
{
public:
nsAsyncMessageToChild(nsFrameLoader* aFrameLoader,
nsAsyncMessageToChild(JSContext* aCx,
nsFrameLoader* aFrameLoader,
const nsAString& aMessage,
const StructuredCloneData& aData)
: mFrameLoader(aFrameLoader), mMessage(aMessage)
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
: mRuntime(js::GetRuntime(aCx)), mFrameLoader(aFrameLoader), mMessage(aMessage), mCpows(aCpows)
{
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
NS_RUNTIMEABORT("OOM");
}
if (mCpows && !js_AddObjectRoot(mRuntime, &mCpows)) {
NS_RUNTIMEABORT("OOM");
}
mClosure = aData.mClosure;
}
~nsAsyncMessageToChild()
{
if (mCpows) {
JS_RemoveObjectRootRT(mRuntime, &mCpows);
}
}
NS_IMETHOD Run()
{
nsInProcessTabChildGlobal* tabChild =
@ -2224,21 +2237,27 @@ public:
data.mDataLength = mData.nbytes();
data.mClosure = mClosure;
SameProcessCpowHolder cpows(mRuntime, JS::Handle<JSObject *>::fromMarkedLocation(&mCpows));
nsRefPtr<nsFrameMessageManager> mm = tabChild->GetInnerManager();
mm->ReceiveMessage(static_cast<EventTarget*>(tabChild), mMessage,
false, &data, JS::NullPtr(), nullptr);
false, &data, &cpows, nullptr);
}
return NS_OK;
}
JSRuntime* mRuntime;
nsRefPtr<nsFrameLoader> mFrameLoader;
nsString mMessage;
JSAutoStructuredCloneBuffer mData;
StructuredCloneClosure mClosure;
JSObject* mCpows;
};
bool
nsFrameLoader::DoSendAsyncMessage(const nsAString& aMessage,
const StructuredCloneData& aData)
nsFrameLoader::DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
{
TabParent* tabParent = mRemoteBrowser;
if (tabParent) {
@ -2247,11 +2266,15 @@ nsFrameLoader::DoSendAsyncMessage(const nsAString& aMessage,
if (!BuildClonedMessageDataForParent(cp, aData, data)) {
return false;
}
return tabParent->SendAsyncMessage(nsString(aMessage), data);
InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
if (aCpows && !cp->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
return tabParent->SendAsyncMessage(nsString(aMessage), data, cpows);
}
if (mChildMessageManager) {
nsRefPtr<nsIRunnable> ev = new nsAsyncMessageToChild(this, aMessage, aData);
nsRefPtr<nsIRunnable> ev = new nsAsyncMessageToChild(aCx, this, aMessage, aData, aCpows);
NS_DispatchToCurrentThread(ev);
return true;
}

View File

@ -186,8 +186,10 @@ public:
* MessageManagerCallback methods that we override.
*/
virtual bool DoLoadFrameScript(const nsAString& aURL) MOZ_OVERRIDE;
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData) MOZ_OVERRIDE;
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows);
virtual bool CheckPermission(const nsAString& aPermission) MOZ_OVERRIDE;
virtual bool CheckManifestURL(const nsAString& aManifestURL) MOZ_OVERRIDE;
virtual bool CheckAppHasPermission(const nsAString& aPermission) MOZ_OVERRIDE;

View File

@ -31,6 +31,8 @@
#include "xpcpublic.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/StructuredCloneUtils.h"
#include "JavaScriptChild.h"
#include "JavaScriptParent.h"
#include <algorithm>
#ifdef ANDROID
@ -220,6 +222,18 @@ mozilla::dom::ipc::UnpackClonedMessageDataForChild(const ClonedMessageData& aDat
return UnpackClonedMessageData<Child>(aData);
}
bool
SameProcessCpowHolder::ToObject(JSContext* aCx, JSObject** aObjp)
{
*aObjp = mObj;
if (!mObj) {
return true;
}
return JS_WrapObject(aCx, aObjp);
}
// nsIMessageListenerManager
NS_IMETHODIMP
@ -311,11 +325,11 @@ JSONCreator(const jschar* aBuf, uint32_t aLen, void* aData)
static bool
GetParamsForMessage(JSContext* aCx,
const JS::Value& aObject,
const JS::Value& aJSON,
JSAutoStructuredCloneBuffer& aBuffer,
StructuredCloneClosure& aClosure)
{
if (WriteStructuredClone(aCx, aObject, aBuffer, aClosure)) {
if (WriteStructuredClone(aCx, aJSON, aBuffer, aClosure)) {
return true;
}
JS_ClearPendingException(aCx);
@ -325,7 +339,7 @@ GetParamsForMessage(JSContext* aCx,
// properly cases when interface is implemented in JS and used
// as a dictionary.
nsAutoString json;
JS::Rooted<JS::Value> v(aCx, aObject);
JS::Rooted<JS::Value> v(aCx, aJSON);
NS_ENSURE_TRUE(JS_Stringify(aCx, v.address(), nullptr, JSVAL_NULL,
JSONCreator, &json), false);
NS_ENSURE_TRUE(!json.IsEmpty(), false);
@ -342,7 +356,8 @@ GetParamsForMessage(JSContext* aCx,
NS_IMETHODIMP
nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName,
const JS::Value& aObject,
const JS::Value& aJSON,
const JS::Value& aObjects,
JSContext* aCx,
uint8_t aArgc,
JS::Value* aRetval)
@ -357,14 +372,19 @@ nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName,
StructuredCloneData data;
JSAutoStructuredCloneBuffer buffer;
if (aArgc >= 2 &&
!GetParamsForMessage(aCx, aObject, buffer, data.mClosure)) {
!GetParamsForMessage(aCx, aJSON, buffer, data.mClosure)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
data.mData = buffer.data();
data.mDataLength = buffer.nbytes();
JS::RootedObject objects(aCx);
if (aArgc >= 3 && aObjects.isObject()) {
objects = &aObjects.toObject();
}
InfallibleTArray<nsString> retval;
if (mCallback->DoSendSyncMessage(aMessageName, data, &retval)) {
if (mCallback->DoSendSyncMessage(aCx, aMessageName, data, objects, &retval)) {
uint32_t len = retval.Length();
JS::Rooted<JSObject*> dataArray(aCx, JS_NewArrayObject(aCx, len, nullptr));
NS_ENSURE_TRUE(dataArray, NS_ERROR_OUT_OF_MEMORY);
@ -389,20 +409,22 @@ nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName,
}
nsresult
nsFrameMessageManager::DispatchAsyncMessageInternal(const nsAString& aMessage,
const StructuredCloneData& aData)
nsFrameMessageManager::DispatchAsyncMessageInternal(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
{
if (mIsBroadcaster) {
int32_t len = mChildManagers.Count();
for (int32_t i = 0; i < len; ++i) {
static_cast<nsFrameMessageManager*>(mChildManagers[i])->
DispatchAsyncMessageInternal(aMessage, aData);
DispatchAsyncMessageInternal(aCx, aMessage, aData, aCpows);
}
return NS_OK;
}
NS_ENSURE_TRUE(mCallback, NS_ERROR_NOT_INITIALIZED);
if (!mCallback->DoSendAsyncMessage(aMessage, aData)) {
if (!mCallback->DoSendAsyncMessage(aCx, aMessage, aData, aCpows)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
@ -410,7 +432,8 @@ nsFrameMessageManager::DispatchAsyncMessageInternal(const nsAString& aMessage,
nsresult
nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
const JS::Value& aObject,
const JS::Value& aJSON,
const JS::Value& aObjects,
JSContext* aCx,
uint8_t aArgc)
{
@ -418,14 +441,19 @@ nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
JSAutoStructuredCloneBuffer buffer;
if (aArgc >= 2 &&
!GetParamsForMessage(aCx, aObject, buffer, data.mClosure)) {
!GetParamsForMessage(aCx, aJSON, buffer, data.mClosure)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
JS::RootedObject objects(aCx);
if (aArgc >= 3 && aObjects.isObject()) {
objects = &aObjects.toObject();
}
data.mData = buffer.data();
data.mDataLength = buffer.nbytes();
return DispatchAsyncMessageInternal(aMessageName, data);
return DispatchAsyncMessageInternal(aCx, aMessageName, data, objects);
}
@ -433,11 +461,12 @@ nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
NS_IMETHODIMP
nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName,
const JS::Value& aObject,
const JS::Value& aJSON,
const JS::Value& aObjects,
JSContext* aCx,
uint8_t aArgc)
{
return DispatchAsyncMessage(aMessageName, aObject, aCx, aArgc);
return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aCx, aArgc);
}
@ -445,11 +474,12 @@ nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName,
NS_IMETHODIMP
nsFrameMessageManager::BroadcastAsyncMessage(const nsAString& aMessageName,
const JS::Value& aObject,
const JS::Value& aJSON,
const JS::Value& aObjects,
JSContext* aCx,
uint8_t aArgc)
{
return DispatchAsyncMessage(aMessageName, aObject, aCx, aArgc);
return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aCx, aArgc);
}
NS_IMETHODIMP
@ -631,11 +661,10 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
const nsAString& aMessage,
bool aSync,
const StructuredCloneData* aCloneData,
JS::Handle<JSObject*> aObjectsArray,
CpowHolder* aCpows,
InfallibleTArray<nsString>* aJSONRetVal)
{
AutoSafeJSContext ctx;
JS::Rooted<JSObject*> objectsArray(ctx, aObjectsArray);
if (mListeners.Length()) {
nsCOMPtr<nsIAtom> name = do_GetAtom(aMessage);
MMListenerRemover lr(this);
@ -663,20 +692,21 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
nsContentUtils::WrapNative(ctx, global, aTarget, targetv.address(),
nullptr, true);
// To keep compatibility with e10s message manager,
// define empty objects array.
if (!objectsArray) {
// Because we want JS messages to have always the same properties,
// create array even if len == 0.
objectsArray = JS_NewArrayObject(ctx, 0, nullptr);
if (!objectsArray) {
return NS_ERROR_OUT_OF_MEMORY;
JS::RootedObject cpows(ctx);
if (aCpows) {
if (!aCpows->ToObject(ctx, cpows.address())) {
return NS_ERROR_UNEXPECTED;
}
}
JS::Rooted<JS::Value> objectsv(ctx, JS::ObjectValue(*objectsArray));
if (!JS_WrapValue(ctx, objectsv.address()))
if (!cpows) {
cpows = JS_NewObject(ctx, nullptr, nullptr, nullptr);
if (!cpows) {
return NS_ERROR_UNEXPECTED;
}
}
JS::RootedValue cpowsv(ctx, JS::ObjectValue(*cpows));
JS::Rooted<JS::Value> json(ctx, JS::NullValue());
if (aCloneData && aCloneData->mDataLength &&
@ -696,7 +726,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
BOOLEAN_TO_JSVAL(aSync), nullptr, nullptr, JSPROP_ENUMERATE);
JS_DefineProperty(ctx, param, "json", json, nullptr, nullptr, JSPROP_ENUMERATE); // deprecated
JS_DefineProperty(ctx, param, "data", json, nullptr, nullptr, JSPROP_ENUMERATE);
JS_DefineProperty(ctx, param, "objects", objectsv, nullptr, nullptr, JSPROP_ENUMERATE);
JS_DefineProperty(ctx, param, "objects", cpowsv, nullptr, nullptr, JSPROP_ENUMERATE);
JS::Rooted<JS::Value> thisValue(ctx, JS::UndefinedValue());
@ -754,7 +784,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
nsRefPtr<nsFrameMessageManager> kungfuDeathGrip = mParentManager;
return mParentManager ? mParentManager->ReceiveMessage(aTarget, aMessage,
aSync, aCloneData,
objectsArray,
aCpows,
aJSONRetVal) : NS_OK;
}
@ -1040,20 +1070,33 @@ nsFrameMessageManager* nsFrameMessageManager::sParentProcessManager = nullptr;
nsFrameMessageManager* nsFrameMessageManager::sSameProcessParentManager = nullptr;
nsTArray<nsCOMPtr<nsIRunnable> >* nsFrameMessageManager::sPendingSameProcessAsyncMessages = nullptr;
class nsAsyncMessageToSameProcessChild : public nsRunnable
{
public:
nsAsyncMessageToSameProcessChild(const nsAString& aMessage,
const StructuredCloneData& aData)
: mMessage(aMessage)
nsAsyncMessageToSameProcessChild(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
: mRuntime(js::GetRuntime(aCx)),
mMessage(aMessage),
mCpows(aCpows)
{
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
NS_RUNTIMEABORT("OOM");
}
if (mCpows && !js_AddObjectRoot(mRuntime, &mCpows)) {
NS_RUNTIMEABORT("OOM");
}
mClosure = aData.mClosure;
}
~nsAsyncMessageToSameProcessChild()
{
if (mCpows) {
JS_RemoveObjectRootRT(mRuntime, &mCpows);
}
}
NS_IMETHOD Run()
{
if (nsFrameMessageManager::sChildProcessManager) {
@ -1062,15 +1105,19 @@ public:
data.mDataLength = mData.nbytes();
data.mClosure = mClosure;
SameProcessCpowHolder cpows(mRuntime, JS::Handle<JSObject *>::fromMarkedLocation(&mCpows));
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sChildProcessManager;
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), mMessage,
false, &data, JS::NullPtr(), nullptr);
false, &data, &cpows, nullptr);
}
return NS_OK;
}
JSRuntime* mRuntime;
nsString mMessage;
JSAutoStructuredCloneBuffer mData;
StructuredCloneClosure mClosure;
JSObject* mCpows;
};
@ -1089,11 +1136,13 @@ public:
MOZ_COUNT_DTOR(SameParentProcessMessageManagerCallback);
}
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const StructuredCloneData& aData)
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
{
nsRefPtr<nsIRunnable> ev =
new nsAsyncMessageToSameProcessChild(aMessage, aData);
new nsAsyncMessageToSameProcessChild(aCx, aMessage, aData, aCpows);
NS_DispatchToCurrentThread(ev);
return true;
}
@ -1133,8 +1182,10 @@ public:
MOZ_COUNT_DTOR(ChildProcessMessageManagerCallback);
}
virtual bool DoSendSyncMessage(const nsAString& aMessage,
virtual bool DoSendSyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
InfallibleTArray<nsString>* aJSONRetVal)
{
mozilla::dom::ContentChild* cc =
@ -1146,11 +1197,17 @@ public:
if (!BuildClonedMessageDataForChild(cc, aData, data)) {
return false;
}
return cc->SendSyncMessage(nsString(aMessage), data, aJSONRetVal);
InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
return cc->SendSyncMessage(nsString(aMessage), data, cpows, aJSONRetVal);
}
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData)
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
{
mozilla::dom::ContentChild* cc =
mozilla::dom::ContentChild::GetSingleton();
@ -1161,7 +1218,11 @@ public:
if (!BuildClonedMessageDataForChild(cc, aData, data)) {
return false;
}
return cc->SendAsyncMessage(nsString(aMessage), data);
InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
return cc->SendAsyncMessage(nsString(aMessage), data, cpows);
}
};
@ -1170,16 +1231,30 @@ public:
class nsAsyncMessageToSameProcessParent : public nsRunnable
{
public:
nsAsyncMessageToSameProcessParent(const nsAString& aMessage,
const StructuredCloneData& aData)
: mMessage(aMessage)
nsAsyncMessageToSameProcessParent(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
: mRuntime(js::GetRuntime(aCx)),
mMessage(aMessage),
mCpows(aCpows)
{
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
NS_RUNTIMEABORT("OOM");
}
if (mCpows && !js_AddObjectRoot(mRuntime, &mCpows)) {
NS_RUNTIMEABORT("OOM");
}
mClosure = aData.mClosure;
}
~nsAsyncMessageToSameProcessParent()
{
if (mCpows) {
JS_RemoveObjectRootRT(mRuntime, &mCpows);
}
}
NS_IMETHOD Run()
{
if (nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
@ -1191,16 +1266,20 @@ public:
data.mDataLength = mData.nbytes();
data.mClosure = mClosure;
SameProcessCpowHolder cpows(mRuntime, JS::Handle<JSObject *>::fromMarkedLocation(&mCpows));
nsRefPtr<nsFrameMessageManager> ppm =
nsFrameMessageManager::sSameProcessParentManager;
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
mMessage, false, &data, JS::NullPtr(), nullptr);
mMessage, false, &data, &cpows, nullptr);
}
return NS_OK;
}
JSRuntime* mRuntime;
nsString mMessage;
JSAutoStructuredCloneBuffer mData;
StructuredCloneClosure mClosure;
JSObject* mCpows;
};
/**
@ -1218,8 +1297,10 @@ public:
MOZ_COUNT_DTOR(SameChildProcessMessageManagerCallback);
}
virtual bool DoSendSyncMessage(const nsAString& aMessage,
virtual bool DoSendSyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
InfallibleTArray<nsString>* aJSONRetVal)
{
nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
@ -1232,21 +1313,24 @@ public:
}
}
if (nsFrameMessageManager::sSameProcessParentManager) {
SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows);
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), aMessage,
true, &aData, JS::NullPtr(), aJSONRetVal);
true, &aData, &cpows, aJSONRetVal);
}
return true;
}
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData)
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
{
if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
nsFrameMessageManager::sPendingSameProcessAsyncMessages = new nsTArray<nsCOMPtr<nsIRunnable> >;
}
nsCOMPtr<nsIRunnable> ev =
new nsAsyncMessageToSameProcessParent(aMessage, aData);
new nsAsyncMessageToSameProcessParent(aCx, aMessage, aData, aCpows);
nsFrameMessageManager::sPendingSameProcessAsyncMessages->AppendElement(ev);
NS_DispatchToCurrentThread(ev);
return true;

View File

@ -1,4 +1,5 @@
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=4 sw=4 tw=99 et: */
/* 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/. */
@ -51,15 +52,19 @@ public:
return true;
}
virtual bool DoSendSyncMessage(const nsAString& aMessage,
virtual bool DoSendSyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
InfallibleTArray<nsString>* aJSONRetVal)
{
return true;
}
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData)
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
{
return true;
}
@ -86,11 +91,11 @@ public:
protected:
bool BuildClonedMessageDataForParent(ContentParent* aParent,
const StructuredCloneData& aData,
ClonedMessageData& aClonedData);
const StructuredCloneData& aData,
ClonedMessageData& aClonedData);
bool BuildClonedMessageDataForChild(ContentChild* aChild,
const StructuredCloneData& aData,
ClonedMessageData& aClonedData);
const StructuredCloneData& aData,
ClonedMessageData& aClonedData);
};
StructuredCloneData UnpackClonedMessageDataForParent(const ClonedMessageData& aData);
@ -110,6 +115,25 @@ struct nsMessageListenerInfo
nsCOMPtr<nsIAtom> mMessage;
};
class CpowHolder
{
public:
virtual bool ToObject(JSContext* cx, JSObject** objp) = 0;
};
class MOZ_STACK_CLASS SameProcessCpowHolder : public CpowHolder
{
public:
SameProcessCpowHolder(JSRuntime *aRuntime, JS::Handle<JSObject *> aObj)
: mObj(aRuntime, aObj)
{
}
bool ToObject(JSContext* aCx, JSObject** aObjp);
private:
JS::RootedObject mObj;
};
class nsFrameMessageManager MOZ_FINAL : public nsIContentFrameMessageManager,
public nsIMessageBroadcaster,
@ -183,7 +207,7 @@ public:
nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
bool aSync, const StructuredCloneData* aCloneData,
JS::Handle<JSObject*> aObjectsArray,
CpowHolder* aCpows,
InfallibleTArray<nsString>* aJSONRetVal);
void AddChildManager(nsFrameMessageManager* aManager,
@ -202,11 +226,14 @@ public:
}
nsresult DispatchAsyncMessage(const nsAString& aMessageName,
const JS::Value& aObject,
const JS::Value& aJSON,
const JS::Value& aObjects,
JSContext* aCx,
uint8_t aArgc);
nsresult DispatchAsyncMessageInternal(const nsAString& aMessage,
const StructuredCloneData& aData);
nsresult DispatchAsyncMessageInternal(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows);
void RemoveFromParent();
nsFrameMessageManager* GetParentManager() { return mParentManager; }
void SetParentManager(nsFrameMessageManager* aParent)

View File

@ -25,8 +25,10 @@ using mozilla::dom::StructuredCloneData;
using mozilla::dom::StructuredCloneClosure;
bool
nsInProcessTabChildGlobal::DoSendSyncMessage(const nsAString& aMessage,
const StructuredCloneData& aData,
nsInProcessTabChildGlobal::DoSendSyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
InfallibleTArray<nsString>* aJSONRetVal)
{
nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
@ -37,9 +39,9 @@ nsInProcessTabChildGlobal::DoSendSyncMessage(const nsAString& aMessage,
async->Run();
}
if (mChromeMessageManager) {
SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows);
nsRefPtr<nsFrameMessageManager> mm = mChromeMessageManager;
mm->ReceiveMessage(mOwner, aMessage, true, &aData, JS::NullPtr(),
aJSONRetVal);
mm->ReceiveMessage(mOwner, aMessage, true, &aData, &cpows, aJSONRetVal);
}
return true;
}
@ -47,17 +49,33 @@ nsInProcessTabChildGlobal::DoSendSyncMessage(const nsAString& aMessage,
class nsAsyncMessageToParent : public nsRunnable
{
public:
nsAsyncMessageToParent(nsInProcessTabChildGlobal* aTabChild,
nsAsyncMessageToParent(JSContext* aCx,
nsInProcessTabChildGlobal* aTabChild,
const nsAString& aMessage,
const StructuredCloneData& aData)
: mTabChild(aTabChild), mMessage(aMessage), mRun(false)
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
: mRuntime(js::GetRuntime(aCx)),
mTabChild(aTabChild),
mMessage(aMessage),
mCpows(aCpows),
mRun(false)
{
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
NS_RUNTIMEABORT("OOM");
}
if (mCpows && !js_AddObjectRoot(mRuntime, &mCpows)) {
NS_RUNTIMEABORT("OOM");
}
mClosure = aData.mClosure;
}
~nsAsyncMessageToParent()
{
if (mCpows) {
JS_RemoveObjectRootRT(mRuntime, &mCpows);
}
}
NS_IMETHOD Run()
{
if (mRun) {
@ -72,27 +90,32 @@ public:
data.mDataLength = mData.nbytes();
data.mClosure = mClosure;
SameProcessCpowHolder cpows(mRuntime, JS::Handle<JSObject *>::fromMarkedLocation(&mCpows));
nsRefPtr<nsFrameMessageManager> mm = mTabChild->mChromeMessageManager;
mm->ReceiveMessage(mTabChild->mOwner, mMessage, false, &data,
JS::NullPtr(), nullptr);
mm->ReceiveMessage(mTabChild->mOwner, mMessage, false, &data, &cpows, nullptr);
}
return NS_OK;
}
JSRuntime* mRuntime;
nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
nsString mMessage;
JSAutoStructuredCloneBuffer mData;
StructuredCloneClosure mClosure;
JSObject* mCpows;
// True if this runnable has already been called. This can happen if DoSendSyncMessage
// is called while waiting for an asynchronous message send.
bool mRun;
};
bool
nsInProcessTabChildGlobal::DoSendAsyncMessage(const nsAString& aMessage,
const StructuredCloneData& aData)
nsInProcessTabChildGlobal::DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
{
nsCOMPtr<nsIRunnable> ev =
new nsAsyncMessageToParent(this, aMessage, aData);
new nsAsyncMessageToParent(aCx, this, aMessage, aData, aCpows);
mASyncMessages.AppendElement(ev);
NS_DispatchToCurrentThread(ev);
return true;

View File

@ -41,12 +41,13 @@ public:
NS_FORWARD_SAFE_NSIMESSAGESENDER(mMessageManager)
NS_IMETHOD SendSyncMessage(const nsAString& aMessageName,
const JS::Value& aObject,
const JS::Value& aRemote,
JSContext* aCx,
uint8_t aArgc,
JS::Value* aRetval)
{
return mMessageManager
? mMessageManager->SendSyncMessage(aMessageName, aObject, aCx, aArgc, aRetval)
? mMessageManager->SendSyncMessage(aMessageName, aObject, aRemote, aCx, aArgc, aRetval)
: NS_ERROR_NULL_POINTER;
}
NS_IMETHOD GetContent(nsIDOMWindow** aContent) MOZ_OVERRIDE;
@ -66,11 +67,15 @@ public:
/**
* MessageManagerCallback methods that we override.
*/
virtual bool DoSendSyncMessage(const nsAString& aMessage,
virtual bool DoSendSyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
InfallibleTArray<nsString>* aJSONRetVal) MOZ_OVERRIDE;
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData) MOZ_OVERRIDE;
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows);
virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
NS_IMETHOD AddEventListener(const nsAString& aType,

View File

@ -61,6 +61,9 @@ MOCHITEST_CHROME_FILES = \
host_bug814638.xul \
test_document_register.xul \
frame_bug814638.xul \
test_cpows.xul \
cpows_parent.xul \
cpows_child.js \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,58 @@
dump('loaded child cpow test\n');
content.document.title = "Hello, Kitty";
(function start() {
sync_test();
async_test();
sendAsyncMessage("cpows:done", {});
}
)();
function ok(condition, message) {
dump('condition: ' + condition + ', ' + message + '\n');
if (!condition) {
sendAsyncMessage("cpows:fail", { message: message });
throw 'failed check: ' + message;
}
}
var sync_obj;
var async_obj;
function make_object()
{
let o = { };
o.i = 5;
o.b = true;
o.s = "hello";
o.x = { i: 10 };
o.f = function () { return 99; }
return { "data": o,
"document": content.document
};
}
function make_json()
{
return { check: "ok" };
}
function sync_test()
{
dump('beginning cpow sync test\n');
sync_obj = make_object();
sendSyncMessage("cpows:sync",
make_json(),
make_object());
}
function async_test()
{
dump('beginning cpow async test\n');
async_obj = make_object();
sendAsyncMessage("cpows:async",
make_json(),
async_obj);
}

View File

@ -0,0 +1,90 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window title="MessageManager CPOW tests"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="start()">
<!-- test results are displayed in the html:body -->
<label value="CPOWs"/>
<script type="application/javascript"><![CDATA[
var test_state = "remote";
var test_node = null;
function ok(condition, message) {
return opener.wrappedJSObject.ok(condition, message);
}
function testCpowMessage(message) {
ok(message.json.check == "ok", "correct json");
let data = message.objects.data;
let document = message.objects.document;
ok(data.i === 5, "integer property");
ok(data.b === true, "boolean property");
ok(data.s === "hello", "string property");
ok(data.x.i === 10, "nested property");
ok(data.f() === 99, "function call");
ok(document.title === "Hello, Kitty", "document node");
data.i = 6;
data.b = false;
data.s = "bye";
data.x = null;
ok(data.i === 6, "integer property");
ok(data.b === false, "boolean property");
ok(data.s === "bye", "string property");
ok(data.x === null, "nested property");
}
function recvAsyncMessage(message) {
testCpowMessage(message);
}
function recvSyncMessage(message) {
testCpowMessage(message);
}
function recvFailMessage(message) {
ok(false, message.json.message);
}
function recvDoneMessage(message) {
if (test_state == "remote") {
test_node.parentNode.removeChild(test_node);
run_tests("inprocess");
return;
}
finish();
}
function run_tests(type) {
var node = document.getElementById('cpowbrowser_' + type);
test_state = type;
test_node = node;
var mm = node.messageManager;
mm.addMessageListener("cpows:async", recvAsyncMessage);
mm.addMessageListener("cpows:sync", recvSyncMessage);
mm.addMessageListener("cpows:done", recvDoneMessage);
mm.addMessageListener("cpows:fail", recvFailMessage);
mm.loadFrameScript("chrome://mochitests/content/chrome/content/base/test/chrome/cpows_child.js", true);
}
function start() {
run_tests('remote');
}
function finish() {
opener.setTimeout("done()", 0);
window.close();
}
]]></script>
<browser type="content" src="about:blank" id="cpowbrowser_remote" remote="true"/>
<browser type="content" src="about:blank" id="cpowbrowser_inprocess"/>
</window>

View File

@ -0,0 +1,27 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window title="Test CPOWs"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
</body>
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
SimpleTest.waitForExplicitFinish();
function done() {
SimpleTest.finish();
}
addLoadEvent(function() {
window.open("cpows_parent.xul", "", "chrome");
});
]]></script>
</window>

View File

@ -321,6 +321,8 @@ ContentChild::Init(MessageLoop* aIOLoop,
SendGetProcessAttributes(&mID, &mIsForApp, &mIsForBrowser);
GetCPOWManager();
if (mIsForApp && !mIsForBrowser) {
SetProcessName(NS_LITERAL_STRING("(Preallocated app)"));
} else {
@ -1059,13 +1061,15 @@ ContentChild::RecvNotifyVisited(const URIParams& aURI)
bool
ContentChild::RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData)
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows)
{
nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
if (cpm) {
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData);
CpowIdHolder cpows(GetCPOWManager(), aCpows);
cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
aMsg, false, &cloneData, JS::NullPtr(), nullptr);
aMsg, false, &cloneData, &cpows, nullptr);
}
return true;
}

View File

@ -178,7 +178,8 @@ public:
virtual bool RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData);
virtual bool RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData);
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows);
virtual bool RecvGeolocationUpdate(const GeoPosition& somewhere);

View File

@ -868,7 +868,7 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
if (ppm) {
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
CHILD_PROCESS_SHUTDOWN_MESSAGE, false,
nullptr, JS::NullPtr(), nullptr);
nullptr, nullptr, nullptr);
}
nsCOMPtr<nsIThreadObserver>
kungFuDeathGrip(static_cast<nsIThreadObserver*>(this));
@ -2308,26 +2308,30 @@ ContentParent::RecvTestPermissionFromPrincipal(const IPC::Principal& aPrincipal,
bool
ContentParent::RecvSyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
InfallibleTArray<nsString>* aRetvals)
{
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
if (ppm) {
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(GetCPOWManager(), aCpows);
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
aMsg, true, &cloneData, JS::NullPtr(), aRetvals);
aMsg, true, &cloneData, &cpows, aRetvals);
}
return true;
}
bool
ContentParent::RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData)
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows)
{
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
if (ppm) {
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(GetCPOWManager(), aCpows);
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
aMsg, false, &cloneData, JS::NullPtr(), nullptr);
aMsg, false, &cloneData, &cpows, nullptr);
}
return true;
}
@ -2531,14 +2535,20 @@ ContentParent::RecvPrivateDocShellsExist(const bool& aExist)
}
bool
ContentParent::DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData)
ContentParent::DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
{
ClonedMessageData data;
if (!BuildClonedMessageDataForParent(this, aData, data)) {
return false;
}
return SendAsyncMessage(nsString(aMessage), data);
InfallibleTArray<CpowEntry> cpows;
if (!GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
return SendAsyncMessage(nsString(aMessage), data, cpows);
}
bool

View File

@ -114,8 +114,10 @@ public:
/**
* MessageManagerCallback methods that we override.
*/
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData) MOZ_OVERRIDE;
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows) MOZ_OVERRIDE;
virtual bool CheckPermission(const nsAString& aPermission) MOZ_OVERRIDE;
virtual bool CheckManifestURL(const nsAString& aManifestURL) MOZ_OVERRIDE;
virtual bool CheckAppHasPermission(const nsAString& aPermission) MOZ_OVERRIDE;
@ -199,7 +201,6 @@ private:
// using them.
using PContentParent::SendPBrowserConstructor;
using PContentParent::SendPTestShellConstructor;
using PContentParent::SendPJavaScriptConstructor;
// No more than one of !!aApp, aIsForBrowser, and aIsForPreallocated may be
// true.
@ -372,9 +373,11 @@ private:
virtual bool RecvSyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
InfallibleTArray<nsString>* aRetvals);
virtual bool RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData);
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows);
virtual bool RecvFilePathUpdateNotify(const nsString& aType,
const nsString& aStorageName,

View File

@ -14,6 +14,7 @@ include protocol PRenderFrame;
include protocol POfflineCacheUpdate;
include protocol PIndexedDB;
include DOMTypes;
include JavaScriptTypes;
include URIParams;
include "gfxMatrix.h";
@ -67,7 +68,7 @@ rpc protocol PBrowser
manages PIndexedDB;
both:
AsyncMessage(nsString aMessage, ClonedMessageData aData);
AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows);
parent:
/**
@ -80,7 +81,7 @@ parent:
rpc CreateWindow() returns (PBrowser window);
sync SyncMessage(nsString aMessage, ClonedMessageData aData)
sync SyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows)
returns (nsString[] retval);
/**

View File

@ -22,6 +22,7 @@ include protocol PStorage;
include protocol PTestShell;
include protocol PJavaScript;
include DOMTypes;
include JavaScriptTypes;
include InputStreamParams;
include PTabContext;
include URIParams;
@ -190,7 +191,7 @@ both:
async PBlob(BlobConstructorParams params);
PJavaScript();
async PJavaScript();
child:
/**
@ -329,7 +330,7 @@ parent:
sync ReadFontList() returns (FontListEntry[] retValue);
sync SyncMessage(nsString aMessage, ClonedMessageData aData)
sync SyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows)
returns (nsString[] retval);
ShowAlertNotification(nsString imageUrl,
@ -427,7 +428,7 @@ parent:
async SetFakeVolumeState(nsString fsName, int32_t fsState);
both:
AsyncMessage(nsString aMessage, ClonedMessageData aData);
AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows);
};
}

View File

@ -84,6 +84,7 @@
#include "StructuredCloneUtils.h"
#include "xpcpublic.h"
#include "nsViewportInfo.h"
#include "JavaScriptChild.h"
#define BROWSER_ELEMENT_CHILD_SCRIPT \
NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js")
@ -97,6 +98,7 @@ using namespace mozilla::layout;
using namespace mozilla::docshell;
using namespace mozilla::dom::indexedDB;
using namespace mozilla::widget;
using namespace mozilla::jsipc;
NS_IMPL_ISUPPORTS1(ContentListener, nsIDOMEventListener)
@ -1454,7 +1456,7 @@ TabChild::DispatchMessageManagerMessage(const nsAString& aMessageName,
nsRefPtr<nsFrameMessageManager> mm =
static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal),
aMessageName, false, &cloneData, JS::NullPtr(), nullptr);
aMessageName, false, &cloneData, nullptr, nullptr);
}
static void
@ -2030,15 +2032,17 @@ TabChild::RecvLoadRemoteScript(const nsString& aURL)
bool
TabChild::RecvAsyncMessage(const nsString& aMessage,
const ClonedMessageData& aData)
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows)
{
if (mTabChildGlobal) {
nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(GetGlobal());
StructuredCloneData cloneData = UnpackClonedMessageDataForChild(aData);
nsRefPtr<nsFrameMessageManager> mm =
static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
CpowIdHolder cpows(static_cast<ContentChild*>(Manager())->GetCPOWManager(), aCpows);
mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal),
aMessage, false, &cloneData, JS::NullPtr(), nullptr);
aMessage, false, &cloneData, &cpows, nullptr);
}
return true;
}
@ -2332,8 +2336,10 @@ TabChild::DeallocPIndexedDBChild(PIndexedDBChild* aActor)
}
bool
TabChild::DoSendSyncMessage(const nsAString& aMessage,
TabChild::DoSendSyncMessage(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
InfallibleTArray<nsString>* aJSONRetVal)
{
ContentChild* cc = Manager();
@ -2341,19 +2347,29 @@ TabChild::DoSendSyncMessage(const nsAString& aMessage,
if (!BuildClonedMessageDataForChild(cc, aData, data)) {
return false;
}
return SendSyncMessage(nsString(aMessage), data, aJSONRetVal);
InfallibleTArray<CpowEntry> cpows;
if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
return SendSyncMessage(nsString(aMessage), data, cpows, aJSONRetVal);
}
bool
TabChild::DoSendAsyncMessage(const nsAString& aMessage,
const StructuredCloneData& aData)
TabChild::DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows)
{
ContentChild* cc = Manager();
ClonedMessageData data;
if (!BuildClonedMessageDataForChild(cc, aData, data)) {
return false;
}
return SendAsyncMessage(nsString(aMessage), data);
InfallibleTArray<CpowEntry> cpows;
if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
return SendAsyncMessage(nsString(aMessage), data, cpows);
}

View File

@ -78,12 +78,13 @@ public:
NS_FORWARD_SAFE_NSIMESSAGESENDER(mMessageManager)
NS_IMETHOD SendSyncMessage(const nsAString& aMessageName,
const JS::Value& aObject,
const JS::Value& aRemote,
JSContext* aCx,
uint8_t aArgc,
JS::Value* aRetval)
{
return mMessageManager
? mMessageManager->SendSyncMessage(aMessageName, aObject, aCx, aArgc, aRetval)
? mMessageManager->SendSyncMessage(aMessageName, aObject, aRemote, aCx, aArgc, aRetval)
: NS_ERROR_NULL_POINTER;
}
NS_IMETHOD GetContent(nsIDOMWindow** aContent) MOZ_OVERRIDE;
@ -187,11 +188,15 @@ public:
/**
* MessageManagerCallback methods that we override.
*/
virtual bool DoSendSyncMessage(const nsAString& aMessage,
virtual bool DoSendSyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
InfallibleTArray<nsString>* aJSONRetVal);
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData);
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows);
virtual bool RecvLoadURL(const nsCString& uri);
virtual bool RecvCacheFileDescriptor(const nsString& aPath,
@ -228,7 +233,8 @@ public:
virtual bool RecvActivateFrameEvent(const nsString& aType, const bool& capture);
virtual bool RecvLoadRemoteScript(const nsString& aURL);
virtual bool RecvAsyncMessage(const nsString& aMessage,
const ClonedMessageData& aData);
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows);
virtual PDocumentRendererChild*
AllocPDocumentRendererChild(const nsRect& documentRect, const gfxMatrix& transform,

View File

@ -52,6 +52,7 @@
#include "nsThreadUtils.h"
#include "private/pprio.h"
#include "StructuredCloneUtils.h"
#include "JavaScriptParent.h"
#include "TabChild.h"
#include <algorithm>
@ -62,6 +63,7 @@ using namespace mozilla::layout;
using namespace mozilla::services;
using namespace mozilla::widget;
using namespace mozilla::dom::indexedDB;
using namespace mozilla::jsipc;
// The flags passed by the webProgress notifications are 16 bits shifted
// from the ones registered by webProgressListeners.
@ -708,18 +710,22 @@ TabParent::TryCapture(const nsGUIEvent& aEvent)
bool
TabParent::RecvSyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
InfallibleTArray<nsString>* aJSONRetVal)
{
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
return ReceiveMessage(aMessage, true, &cloneData, aJSONRetVal);
CpowIdHolder cpows(static_cast<ContentParent*>(Manager())->GetCPOWManager(), aCpows);
return ReceiveMessage(aMessage, true, &cloneData, &cpows, aJSONRetVal);
}
bool
TabParent::RecvAsyncMessage(const nsString& aMessage,
const ClonedMessageData& aData)
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows)
{
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
return ReceiveMessage(aMessage, false, &cloneData, nullptr);
CpowIdHolder cpows(static_cast<ContentParent*>(Manager())->GetCPOWManager(), aCpows);
return ReceiveMessage(aMessage, false, &cloneData, &cpows, nullptr);
}
bool
@ -1084,26 +1090,19 @@ bool
TabParent::ReceiveMessage(const nsString& aMessage,
bool aSync,
const StructuredCloneData* aCloneData,
CpowHolder* aCpows,
InfallibleTArray<nsString>* aJSONRetVal)
{
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
if (frameLoader && frameLoader->GetFrameMessageManager()) {
nsRefPtr<nsFrameMessageManager> manager =
frameLoader->GetFrameMessageManager();
AutoSafeJSContext ctx;
uint32_t len = 0; //TODO: obtain a real value in bug 572685
// Because we want JS messages to have always the same properties,
// create array even if len == 0.
JS::Rooted<JSObject*> objectsArray(ctx, JS_NewArrayObject(ctx, len, NULL));
if (!objectsArray) {
return false;
}
manager->ReceiveMessage(mFrameElement,
aMessage,
aSync,
aCloneData,
objectsArray,
aCpows,
aJSONRetVal);
}
return true;

View File

@ -31,6 +31,7 @@ class mozIApplication;
class nsFrameLoader;
class nsIDOMElement;
class nsIURI;
class CpowHolder;
namespace mozilla {
@ -123,9 +124,11 @@ public:
virtual bool AnswerCreateWindow(PBrowserParent** retval);
virtual bool RecvSyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
InfallibleTArray<nsString>* aJSONRetVal);
virtual bool RecvAsyncMessage(const nsString& aMessage,
const ClonedMessageData& aData);
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows);
virtual bool RecvNotifyIMEFocus(const bool& aFocus,
nsIMEUpdatePreference* aPreference,
uint32_t* aSeqno);
@ -234,6 +237,7 @@ protected:
bool ReceiveMessage(const nsString& aMessage,
bool aSync,
const StructuredCloneData* aCloneData,
CpowHolder* aCpows,
InfallibleTArray<nsString>* aJSONRetVal = nullptr);
virtual bool Recv__delete__() MOZ_OVERRIDE;

View File

@ -348,6 +348,8 @@ JavaScriptChild::AnswerGet(const ObjectId &objId, const ObjectId &receiverId, co
AutoSafeJSContext cx;
JSAutoRequest request(cx);
// The outparam will be written to the buffer, so it must be set even if
// the parent won't read it.
*result = void_t();
RootedObject obj(cx, findObject(objId));

View File

@ -494,14 +494,11 @@ CPOWProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy)
void
JavaScriptParent::drop(JSObject *obj)
{
if (inactive_)
return;
ObjectId objId = idOf(obj);
objects_.remove(objId);
if (!SendDropObject(objId))
MOZ_CRASH();
if (!inactive_ && !SendDropObject(objId))
(void)0;
decref();
}

View File

@ -395,3 +395,78 @@ JavaScriptShared::toDescriptor(JSContext *cx, const PPropertyDescriptor &in, JSP
return true;
}
bool
CpowIdHolder::ToObject(JSContext *cx, JSObject **objp)
{
return js_->Unwrap(cx, cpows_, objp);
}
bool
JavaScriptShared::Unwrap(JSContext *cx, const InfallibleTArray<CpowEntry> &aCpows, JSObject **objp)
{
*objp = NULL;
if (!aCpows.Length())
return true;
RootedObject obj(cx, JS_NewObject(cx, NULL, NULL, NULL));
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 (!toValue(cx, aCpows[i].value(), &v))
return false;
if (!JS_DefineUCProperty(cx,
obj,
name.BeginReading(),
name.Length(),
v,
NULL,
NULL,
JSPROP_ENUMERATE))
{
return false;
}
}
*objp = obj;
return true;
}
bool
JavaScriptShared::Wrap(JSContext *cx, HandleObject aObj, InfallibleTArray<CpowEntry> *outCpows)
{
if (!aObj)
return true;
AutoIdArray ids(cx, JS_Enumerate(cx, aObj));
if (!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.address()))
return false;
JSVariant var;
if (!toVariant(cx, v, &var))
return false;
outCpows->AppendElement(CpowEntry(str, var));
}
return true;
}

View File

@ -21,6 +21,24 @@ namespace jsipc {
typedef uint64_t ObjectId;
class JavaScriptShared;
class CpowIdHolder : public CpowHolder
{
public:
CpowIdHolder(JavaScriptShared *js, const InfallibleTArray<CpowEntry> &cpows)
: js_(js),
cpows_(cpows)
{
}
bool ToObject(JSContext *cx, JSObject **objp);
private:
JavaScriptShared *js_;
const InfallibleTArray<CpowEntry> &cpows_;
};
// Map ids -> JSObjects
class ObjectStore
{
@ -70,6 +88,9 @@ class JavaScriptShared
static const uint32_t OBJECT_EXTRA_BITS = 1;
static const uint32_t OBJECT_IS_CALLABLE = (1 << 0);
bool Unwrap(JSContext *cx, const InfallibleTArray<CpowEntry> &aCpows, JSObject **objp);
bool Wrap(JSContext *cx, JS::HandleObject aObj, InfallibleTArray<CpowEntry> *outCpows);
protected:
bool toVariant(JSContext *cx, jsval from, JSVariant *to);
bool toValue(JSContext *cx, const JSVariant &from, JS::MutableHandleValue to);

View File

@ -139,6 +139,12 @@ js_ObjectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValu
JS_FRIEND_API(const char *)
js_ObjectClassName(JSContext *cx, JS::HandleObject obj);
JS_FRIEND_API(bool)
js_AddObjectRoot(JSRuntime *rt, JSObject **objp);
JS_FRIEND_API(void)
js_RemoveObjectRoot(JSRuntime *rt, JSObject **objp);
#ifdef DEBUG
/*

View File

@ -1085,6 +1085,18 @@ js::AddScriptRoot(JSContext *cx, JSScript **rp, const char *name)
return AddRoot(cx, rp, name, JS_GC_ROOT_SCRIPT_PTR);
}
extern JS_FRIEND_API(bool)
js_AddObjectRoot(JSRuntime *rt, JSObject **objp)
{
return AddRoot(rt, objp, NULL, JS_GC_ROOT_OBJECT_PTR);
}
extern JS_FRIEND_API(void)
js_RemoveObjectRoot(JSRuntime *rt, JSObject **objp)
{
js_RemoveRoot(rt, objp);
}
JS_FRIEND_API(void)
js_RemoveRoot(JSRuntime *rt, void *rp)
{