diff --git a/content/base/public/nsIMessageManager.idl b/content/base/public/nsIMessageManager.idl index 134f6a8e0b6f..2b8f731f4bc1 100644 --- a/content/base/public/nsIMessageManager.idl +++ b/content/base/public/nsIMessageManager.idl @@ -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)] diff --git a/content/base/src/Makefile.in b/content/base/src/Makefile.in index e91a27665878..534d65d9c75a 100644 --- a/content/base/src/Makefile.in +++ b/content/base/src/Makefile.in @@ -50,6 +50,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 \ diff --git a/content/base/src/nsFrameLoader.cpp b/content/base/src/nsFrameLoader.cpp index 169bd16f00de..e23249f2dc93 100644 --- a/content/base/src/nsFrameLoader.cpp +++ b/content/base/src/nsFrameLoader.cpp @@ -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 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::fromMarkedLocation(&mCpows)); + nsRefPtr mm = tabChild->GetInnerManager(); mm->ReceiveMessage(static_cast(tabChild), mMessage, - false, &data, JS::NullPtr(), nullptr); + false, &data, &cpows, nullptr); } return NS_OK; } + JSRuntime* mRuntime; nsRefPtr 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 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 cpows; + if (aCpows && !cp->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) { + return false; + } + return tabParent->SendAsyncMessage(nsString(aMessage), data, cpows); } if (mChildMessageManager) { - nsRefPtr ev = new nsAsyncMessageToChild(this, aMessage, aData); + nsRefPtr ev = new nsAsyncMessageToChild(aCx, this, aMessage, aData, aCpows); NS_DispatchToCurrentThread(ev); return true; } diff --git a/content/base/src/nsFrameLoader.h b/content/base/src/nsFrameLoader.h index 669631edf87f..315a8b0f7f34 100644 --- a/content/base/src/nsFrameLoader.h +++ b/content/base/src/nsFrameLoader.h @@ -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 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; diff --git a/content/base/src/nsFrameMessageManager.cpp b/content/base/src/nsFrameMessageManager.cpp index 9768aabf3574..0ec31525f34f 100644 --- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -31,6 +31,8 @@ #include "xpcpublic.h" #include "mozilla/Preferences.h" #include "mozilla/dom/StructuredCloneUtils.h" +#include "JavaScriptChild.h" +#include "JavaScriptParent.h" #include #ifdef ANDROID @@ -220,6 +222,18 @@ mozilla::dom::ipc::UnpackClonedMessageDataForChild(const ClonedMessageData& aDat return UnpackClonedMessageData(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 v(aCx, aObject); + JS::Rooted 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 retval; - if (mCallback->DoSendSyncMessage(aMessageName, data, &retval)) { + if (mCallback->DoSendSyncMessage(aCx, aMessageName, data, objects, &retval)) { uint32_t len = retval.Length(); JS::Rooted 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 aCpows) { if (mIsBroadcaster) { int32_t len = mChildManagers.Count(); for (int32_t i = 0; i < len; ++i) { static_cast(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 aObjectsArray, + CpowHolder* aCpows, InfallibleTArray* aJSONRetVal) { AutoSafeJSContext ctx; - JS::Rooted objectsArray(ctx, aObjectsArray); if (mListeners.Length()) { nsCOMPtr 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 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 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 thisValue(ctx, JS::UndefinedValue()); @@ -754,7 +784,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, nsRefPtr 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 >* 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 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::fromMarkedLocation(&mCpows)); + nsRefPtr ppm = nsFrameMessageManager::sChildProcessManager; ppm->ReceiveMessage(static_cast(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 aCpows) { nsRefPtr 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 aCpows, InfallibleTArray* 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 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 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 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 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::fromMarkedLocation(&mCpows)); + nsRefPtr ppm = nsFrameMessageManager::sSameProcessParentManager; ppm->ReceiveMessage(static_cast(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 aCpows, InfallibleTArray* aJSONRetVal) { nsTArray > asyncMessages; @@ -1232,21 +1313,24 @@ public: } } if (nsFrameMessageManager::sSameProcessParentManager) { + SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows); nsRefPtr ppm = nsFrameMessageManager::sSameProcessParentManager; ppm->ReceiveMessage(static_cast(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 aCpows) { if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) { nsFrameMessageManager::sPendingSameProcessAsyncMessages = new nsTArray >; } nsCOMPtr ev = - new nsAsyncMessageToSameProcessParent(aMessage, aData); + new nsAsyncMessageToSameProcessParent(aCx, aMessage, aData, aCpows); nsFrameMessageManager::sPendingSameProcessAsyncMessages->AppendElement(ev); NS_DispatchToCurrentThread(ev); return true; diff --git a/content/base/src/nsFrameMessageManager.h b/content/base/src/nsFrameMessageManager.h index d60c478170b4..4ef103146966 100644 --- a/content/base/src/nsFrameMessageManager.h +++ b/content/base/src/nsFrameMessageManager.h @@ -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 aCpows, InfallibleTArray* 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 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 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 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 aObjectsArray, + CpowHolder* aCpows, InfallibleTArray* 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 aCpows); void RemoveFromParent(); nsFrameMessageManager* GetParentManager() { return mParentManager; } void SetParentManager(nsFrameMessageManager* aParent) diff --git a/content/base/src/nsInProcessTabChildGlobal.cpp b/content/base/src/nsInProcessTabChildGlobal.cpp index 9e6ab066dd0e..8b9b5e4e549f 100644 --- a/content/base/src/nsInProcessTabChildGlobal.cpp +++ b/content/base/src/nsInProcessTabChildGlobal.cpp @@ -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 aCpows, InfallibleTArray* aJSONRetVal) { nsTArray > asyncMessages; @@ -37,9 +39,9 @@ nsInProcessTabChildGlobal::DoSendSyncMessage(const nsAString& aMessage, async->Run(); } if (mChromeMessageManager) { + SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows); nsRefPtr 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 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::fromMarkedLocation(&mCpows)); + nsRefPtr 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 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 aCpows) { nsCOMPtr ev = - new nsAsyncMessageToParent(this, aMessage, aData); + new nsAsyncMessageToParent(aCx, this, aMessage, aData, aCpows); mASyncMessages.AppendElement(ev); NS_DispatchToCurrentThread(ev); return true; diff --git a/content/base/src/nsInProcessTabChildGlobal.h b/content/base/src/nsInProcessTabChildGlobal.h index 15cbf1b0bf63..706edfdfdc14 100644 --- a/content/base/src/nsInProcessTabChildGlobal.h +++ b/content/base/src/nsInProcessTabChildGlobal.h @@ -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 aCpows, InfallibleTArray* 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 aCpows); virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor) MOZ_OVERRIDE; NS_IMETHOD AddEventListener(const nsAString& aType, diff --git a/content/base/test/chrome/Makefile.in b/content/base/test/chrome/Makefile.in index 42dc24100a6e..3961f2e3d7a5 100644 --- a/content/base/test/chrome/Makefile.in +++ b/content/base/test/chrome/Makefile.in @@ -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 diff --git a/content/base/test/chrome/cpows_child.js b/content/base/test/chrome/cpows_child.js new file mode 100644 index 000000000000..edfbf5f311d4 --- /dev/null +++ b/content/base/test/chrome/cpows_child.js @@ -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); +} + diff --git a/content/base/test/chrome/cpows_parent.xul b/content/base/test/chrome/cpows_parent.xul new file mode 100644 index 000000000000..52461b42bcf2 --- /dev/null +++ b/content/base/test/chrome/cpows_parent.xul @@ -0,0 +1,90 @@ + + + + + + + diff --git a/content/base/test/chrome/test_cpows.xul b/content/base/test/chrome/test_cpows.xul new file mode 100644 index 000000000000..0f10f509439a --- /dev/null +++ b/content/base/test/chrome/test_cpows.xul @@ -0,0 +1,27 @@ + + + + + + + + + + + + + diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 6a71b7018a7a..0464ddffca3a 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -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& aCpows) { nsRefPtr cpm = nsFrameMessageManager::sChildProcessManager; if (cpm) { StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData); + CpowIdHolder cpows(GetCPOWManager(), aCpows); cpm->ReceiveMessage(static_cast(cpm.get()), - aMsg, false, &cloneData, JS::NullPtr(), nullptr); + aMsg, false, &cloneData, &cpows, nullptr); } return true; } diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 824e9d0ae180..bdae4f9f4799 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -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& aCpows); virtual bool RecvGeolocationUpdate(const GeoPosition& somewhere); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index eb598f19e3a6..4a9a357ea572 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -868,7 +868,7 @@ ContentParent::ActorDestroy(ActorDestroyReason why) if (ppm) { ppm->ReceiveMessage(static_cast(ppm.get()), CHILD_PROCESS_SHUTDOWN_MESSAGE, false, - nullptr, JS::NullPtr(), nullptr); + nullptr, nullptr, nullptr); } nsCOMPtr kungFuDeathGrip(static_cast(this)); @@ -2308,26 +2308,30 @@ ContentParent::RecvTestPermissionFromPrincipal(const IPC::Principal& aPrincipal, bool ContentParent::RecvSyncMessage(const nsString& aMsg, const ClonedMessageData& aData, + const InfallibleTArray& aCpows, InfallibleTArray* aRetvals) { nsRefPtr ppm = mMessageManager; if (ppm) { StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); + CpowIdHolder cpows(GetCPOWManager(), aCpows); ppm->ReceiveMessage(static_cast(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& aCpows) { nsRefPtr ppm = mMessageManager; if (ppm) { StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); + CpowIdHolder cpows(GetCPOWManager(), aCpows); ppm->ReceiveMessage(static_cast(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 aCpows) { ClonedMessageData data; if (!BuildClonedMessageDataForParent(this, aData, data)) { return false; } - return SendAsyncMessage(nsString(aMessage), data); + InfallibleTArray cpows; + if (!GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) { + return false; + } + return SendAsyncMessage(nsString(aMessage), data, cpows); } bool diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index abdaa21c3b74..cc68aa900125 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -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 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& aCpows, InfallibleTArray* aRetvals); virtual bool RecvAsyncMessage(const nsString& aMsg, - const ClonedMessageData& aData); + const ClonedMessageData& aData, + const InfallibleTArray& aCpows); virtual bool RecvFilePathUpdateNotify(const nsString& aType, const nsString& aStorageName, diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index c80c0395b7df..9bc7228a17b5 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -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); /** diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index faac1357685c..cc7bdb12bb88 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -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); }; } diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index f4f1ba1d50a3..9d4f3d3f99a7 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -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 mm = static_cast(mTabChildGlobal->mMessageManager.get()); mm->ReceiveMessage(static_cast(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& aCpows) { if (mTabChildGlobal) { nsCOMPtr kungFuDeathGrip(GetGlobal()); StructuredCloneData cloneData = UnpackClonedMessageDataForChild(aData); nsRefPtr mm = static_cast(mTabChildGlobal->mMessageManager.get()); + CpowIdHolder cpows(static_cast(Manager())->GetCPOWManager(), aCpows); mm->ReceiveMessage(static_cast(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 aCpows, InfallibleTArray* 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 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 aCpows) { ContentChild* cc = Manager(); ClonedMessageData data; if (!BuildClonedMessageDataForChild(cc, aData, data)) { return false; } - return SendAsyncMessage(nsString(aMessage), data); + InfallibleTArray cpows; + if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) { + return false; + } + return SendAsyncMessage(nsString(aMessage), data, cpows); } diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index 04d4dba4f2ca..27b949c00e19 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -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 aCpows, InfallibleTArray* 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 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& aCpows); virtual PDocumentRendererChild* AllocPDocumentRendererChild(const nsRect& documentRect, const gfxMatrix& transform, diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 84198656efe8..9634ca4fdd6c 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -52,6 +52,7 @@ #include "nsThreadUtils.h" #include "private/pprio.h" #include "StructuredCloneUtils.h" +#include "JavaScriptParent.h" #include "TabChild.h" #include @@ -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& aCpows, InfallibleTArray* aJSONRetVal) { StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); - return ReceiveMessage(aMessage, true, &cloneData, aJSONRetVal); + CpowIdHolder cpows(static_cast(Manager())->GetCPOWManager(), aCpows); + return ReceiveMessage(aMessage, true, &cloneData, &cpows, aJSONRetVal); } bool TabParent::RecvAsyncMessage(const nsString& aMessage, - const ClonedMessageData& aData) + const ClonedMessageData& aData, + const InfallibleTArray& aCpows) { StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); - return ReceiveMessage(aMessage, false, &cloneData, nullptr); + CpowIdHolder cpows(static_cast(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* aJSONRetVal) { nsRefPtr frameLoader = GetFrameLoader(); if (frameLoader && frameLoader->GetFrameMessageManager()) { nsRefPtr 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 objectsArray(ctx, JS_NewArrayObject(ctx, len, NULL)); - if (!objectsArray) { - return false; - } manager->ReceiveMessage(mFrameElement, aMessage, aSync, aCloneData, - objectsArray, + aCpows, aJSONRetVal); } return true; diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 79cfe1c49424..421f1bab7a41 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -30,6 +30,7 @@ class mozIApplication; class nsFrameLoader; class nsIDOMElement; class nsIURI; +class CpowHolder; namespace mozilla { @@ -122,9 +123,11 @@ public: virtual bool AnswerCreateWindow(PBrowserParent** retval); virtual bool RecvSyncMessage(const nsString& aMessage, const ClonedMessageData& aData, + const InfallibleTArray& aCpows, InfallibleTArray* aJSONRetVal); virtual bool RecvAsyncMessage(const nsString& aMessage, - const ClonedMessageData& aData); + const ClonedMessageData& aData, + const InfallibleTArray& aCpows); virtual bool RecvNotifyIMEFocus(const bool& aFocus, nsIMEUpdatePreference* aPreference, uint32_t* aSeqno); @@ -233,6 +236,7 @@ protected: bool ReceiveMessage(const nsString& aMessage, bool aSync, const StructuredCloneData* aCloneData, + CpowHolder* aCpows, InfallibleTArray* aJSONRetVal = nullptr); virtual bool Recv__delete__() MOZ_OVERRIDE; diff --git a/js/ipc/JavaScriptChild.cpp b/js/ipc/JavaScriptChild.cpp index bdafc801c20e..7280f6558a02 100644 --- a/js/ipc/JavaScriptChild.cpp +++ b/js/ipc/JavaScriptChild.cpp @@ -197,6 +197,10 @@ JavaScriptChild::AnswerGet(const ObjectId &objId, const ObjectId &receiverId, 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)); if (!obj) return false; diff --git a/js/ipc/JavaScriptParent.cpp b/js/ipc/JavaScriptParent.cpp index ccc67c9619c9..a733ce2405eb 100644 --- a/js/ipc/JavaScriptParent.cpp +++ b/js/ipc/JavaScriptParent.cpp @@ -455,14 +455,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(); } diff --git a/js/ipc/JavaScriptShared.cpp b/js/ipc/JavaScriptShared.cpp index 7a9ef3231136..43376963f022 100644 --- a/js/ipc/JavaScriptShared.cpp +++ b/js/ipc/JavaScriptShared.cpp @@ -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 &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 *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; +} + diff --git a/js/ipc/JavaScriptShared.h b/js/ipc/JavaScriptShared.h index 517e7a184a14..0eb321614110 100644 --- a/js/ipc/JavaScriptShared.h +++ b/js/ipc/JavaScriptShared.h @@ -21,6 +21,24 @@ namespace jsipc { typedef uint64_t ObjectId; +class JavaScriptShared; + +class CpowIdHolder : public CpowHolder +{ + public: + CpowIdHolder(JavaScriptShared *js, const InfallibleTArray &cpows) + : js_(js), + cpows_(cpows) + { + } + + bool ToObject(JSContext *cx, JSObject **objp); + + private: + JavaScriptShared *js_; + const InfallibleTArray &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 &aCpows, JSObject **objp); + bool Wrap(JSContext *cx, JS::HandleObject aObj, InfallibleTArray *outCpows); + protected: bool toVariant(JSContext *cx, jsval from, JSVariant *to); bool toValue(JSContext *cx, const JSVariant &from, JS::MutableHandleValue to); diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 355d00dba18f..f44f3494abef 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -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 /* diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 53e3da620087..297ab7284077 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1084,6 +1084,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) {