Bug 554941 - [E10s] CPOW for synchronous TabChildGlobal messages, r=bnewman

This commit is contained in:
Olli Pettay 2010-03-27 18:54:57 +02:00
parent 3905ca35a7
commit 1795ed6f2e
12 changed files with 171 additions and 40 deletions

View File

@ -284,6 +284,7 @@ nsresult
nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
const nsAString& aMessage,
PRBool aSync, const nsAString& aJSON,
JSObject* aObjectsArray,
nsTArray<nsString>* aJSONRetVal)
{
if (mListeners.Length()) {
@ -347,6 +348,8 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
JS_DefineProperty(mContext, param, "sync",
BOOLEAN_TO_JSVAL(aSync), NULL, NULL, JSPROP_ENUMERATE);
JS_DefineProperty(mContext, param, "json", json, NULL, NULL, JSPROP_ENUMERATE);
JS_DefineProperty(mContext, param, "objects", OBJECT_TO_JSVAL(aObjectsArray),
NULL, NULL, JSPROP_ENUMERATE);
jsval thisValue = JSVAL_VOID;
nsAutoGCRoot resultGCRoot3(&thisValue, &rv);
@ -397,7 +400,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
}
}
return mParentManager ? mParentManager->ReceiveMessage(aTarget, aMessage,
aSync, aJSON,
aSync, aJSON, aObjectsArray,
aJSONRetVal) : NS_OK;
}

View File

@ -48,6 +48,7 @@
class nsAXPCNativeCallContext;
struct JSContext;
struct JSObject;
struct nsMessageListenerInfo
{
@ -103,6 +104,7 @@ public:
nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
PRBool aSync, const nsAString& aJSON,
JSObject* aObjectsArray,
nsTArray<nsString>* aJSONRetVal);
void AddChildManager(nsFrameMessageManager* aManager);
void RemoveChildManager(nsFrameMessageManager* aManager)
@ -115,6 +117,7 @@ public:
nsresult GetParamsForMessage(nsAString& aMessageName, nsAString& aJSON);
nsresult SendAsyncMessageInternal(const nsAString& aMessage,
const nsAString& aJSON);
JSContext* GetJSContext() { return mContext; }
protected:
nsTArray<nsMessageListenerInfo> mListeners;
nsCOMArray<nsIContentFrameMessageManager> mChildManagers;

View File

@ -126,6 +126,7 @@ ContentProcessParent::DestroyTestShell(TestShellParent* aTestShell)
ContentProcessParent::ContentProcessParent()
: mMonitor("ContentProcessParent::mMonitor")
, mRunToCompletionDepth(0)
, mShouldCallUnblockChild(false)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content);
@ -217,6 +218,18 @@ ContentProcessParent::DeallocPNecko(PNeckoParent* necko)
return true;
}
void
ContentProcessParent::ReportChildAlreadyBlocked()
{
if (!mRunToCompletionDepth) {
#ifdef DEBUG
printf("Running to completion...\n");
#endif
mRunToCompletionDepth = 1;
mShouldCallUnblockChild = false;
}
}
bool
ContentProcessParent::RequestRunToCompletion()
{
@ -226,8 +239,8 @@ ContentProcessParent::RequestRunToCompletion()
printf("Running to completion...\n");
#endif
mRunToCompletionDepth = 1;
mShouldCallUnblockChild = true;
}
return !!mRunToCompletionDepth;
}
@ -266,7 +279,10 @@ ContentProcessParent::AfterProcessNextEvent(nsIThreadInternal *thread,
#ifdef DEBUG
printf("... ran to completion.\n");
#endif
UnblockChild();
if (mShouldCallUnblockChild) {
mShouldCallUnblockChild = false;
UnblockChild();
}
}
if (mOldObserver)

View File

@ -83,6 +83,7 @@ public:
TestShellParent* CreateTestShell();
bool DestroyTestShell(TestShellParent* aTestShell);
void ReportChildAlreadyBlocked();
bool RequestRunToCompletion();
protected:
@ -113,6 +114,7 @@ private:
GeckoChildProcessHost* mSubprocess;
int mRunToCompletionDepth;
bool mShouldCallUnblockChild;
nsCOMPtr<nsIThreadObserver> mOldObserver;
};

View File

@ -41,6 +41,7 @@ include protocol "PContentProcess.ipdl";
include protocol "PDocumentRenderer.ipdl";
include protocol "PDocumentRendererShmem.ipdl";
include protocol "PContextWrapper.ipdl";
include protocol "PObjectWrapper.ipdl";
include "mozilla/TabTypes.h";
include "TabMessageUtils.h";
@ -94,7 +95,9 @@ parent:
PContextWrapper();
sync sendSyncMessageToParent(nsString aMessage, nsString aJSON) returns (nsString[] retval);
rpc sendSyncMessageToParent(nsString aMessage, nsString aJSON, PObjectWrapper[] aObjects)
returns (nsString[] retval);
sendAsyncMessageToParent(nsString aMessage, nsString aJSON);
child:
createWidget(MagicWindowHandle parentWidget);

View File

@ -102,6 +102,7 @@ ContentListener::HandleEvent(nsIDOMEvent* aEvent)
}
TabChild::TabChild()
: mCx(nsnull), mContextWrapper(nsnull), mTabChildGlobal(nsnull)
{
printf("creating %d!\n", NS_IsMainThread());
}
@ -757,10 +758,9 @@ TabChild::RecvsendAsyncMessageToChild(const nsString& aMessage,
const nsString& aJSON)
{
if (mTabChildGlobal) {
nsTArray<nsString> dummy;
static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get())->
ReceiveMessage(static_cast<nsPIDOMEventTarget*>(mTabChildGlobal),
aMessage, PR_FALSE, aJSON, nsnull);
aMessage, PR_FALSE, aJSON, nsnull, nsnull);
}
return true;
}
@ -846,16 +846,57 @@ TabChild::InitTabChildGlobal()
JS_SetGlobalObject(cx, global);
mContextWrapper = new ContextWrapperChild(mCx);
SendPContextWrapperConstructor(mContextWrapper);
return true;
}
nsresult
TabChild::GetObjectsForMessage(nsTArray<mozilla::jsipc::PObjectWrapperChild*>& aObjects)
{
nsAXPCNativeCallContext* ncc = nsnull;
nsresult rv = nsContentUtils::XPConnect()->GetCurrentNativeCallContext(&ncc);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_STATE(ncc);
JSContext* ctx = nsnull;
rv = ncc->GetJSContext(&ctx);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 argc;
jsval* argv = nsnull;
ncc->GetArgc(&argc);
ncc->GetArgvPtr(&argv);
JSAutoRequest ar(ctx);
JSObject* obj = nsnull;
nsAutoGCRoot resultGCRoot(&obj, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// First parameter is the message name, second is the JSON.
for (PRUint32 i = 2; i < argc; ++i) {
if (JSVAL_IS_OBJECT(argv[i])) {
obj = JSVAL_TO_OBJECT(argv[i]);
} else if (!JS_ValueToObject(ctx, argv[i], &obj)) {
obj = nsnull;
}
// GetOrCreateWrapper is null safe!
aObjects.AppendElement(mContextWrapper->GetOrCreateWrapper(obj));
}
return NS_OK;
}
bool SendSyncMessageToParent(void* aCallbackData,
const nsAString& aMessage,
const nsAString& aJSON,
nsTArray<nsString>* aJSONRetVal)
{
nsTArray<mozilla::jsipc::PObjectWrapperChild*> objects;
static_cast<TabChild*>(aCallbackData)->GetObjectsForMessage(objects);
return static_cast<TabChild*>(aCallbackData)->
SendsendSyncMessageToParent(nsString(aMessage), nsString(aJSON), aJSONRetVal);
CallsendSyncMessageToParent(nsString(aMessage), nsString(aJSON), objects,
aJSONRetVal);
}
bool SendAsyncMessageToParent(void* aCallbackData,

View File

@ -75,6 +75,7 @@ namespace mozilla {
namespace jsipc {
class PContextWrapperChild;
class ContextWrapperChild;
}
namespace dom {
@ -244,6 +245,7 @@ public:
virtual PContextWrapperChild* AllocPContextWrapper();
virtual bool DeallocPContextWrapper(PContextWrapperChild* actor);
nsresult GetObjectsForMessage(nsTArray<PObjectWrapperChild*>& aObjects);
private:
bool InitTabChildGlobal();
@ -253,6 +255,8 @@ private:
JSContext* mCx;
mozilla::jsipc::ContextWrapperChild* mContextWrapper;
nsCOMPtr<nsIChannel> mChannel;
TabChildGlobal* mTabChildGlobal;

View File

@ -55,6 +55,8 @@
#include "nsIWebProgressListener2.h"
#include "nsFrameLoader.h"
#include "nsNetUtil.h"
#include "jsarray.h"
#include "nsContentUtils.h"
using mozilla::ipc::DocumentRendererParent;
using mozilla::ipc::DocumentRendererShmemParent;
@ -443,9 +445,20 @@ TabParent::GetGlobalJSObject(JSContext* cx, JSObject** globalp)
ManagedPContextWrapperParent(cwps);
if (cwps.Length() < 1)
return false;
NS_ASSERTION(cwps.Length() == 1, "More than one PContextWrapper?");
// This is temporary until we decide whether to return
// TabChildGlobal or top level page's global object.
// Currently this returns the page global object.
// Note, TabChildGlobal's context doesn't report its global object here!
NS_ASSERTION(cwps.Length() <= 2, "More than two PContextWrappers?");
ContextWrapperParent* cwp = static_cast<ContextWrapperParent*>(cwps[0]);
return (cwp->GetGlobalJSObject(cx, globalp));
if (cwp->GetGlobalObjectWrapper()) {
return cwp->GetGlobalJSObject(cx, globalp);
} else if (cwps.Length() == 2) {
cwp = static_cast<ContextWrapperParent*>(cwps[1]);
return cwp->GetGlobalJSObject(cx, globalp);
}
return false;
}
void
@ -469,40 +482,62 @@ TabParent::SendKeyEvent(const nsAString& aType,
}
bool
TabParent::RecvsendSyncMessageToParent(const nsString& aMessage,
const nsString& aJSON,
nsTArray<nsString>* aJSONRetVal)
TabParent::AnswersendSyncMessageToParent(const nsString& aMessage,
const nsString& aJSON,
const nsTArray<PObjectWrapperParent*>& aObjects,
nsTArray<nsString>* aJSONRetVal)
{
nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner =
do_QueryInterface(mFrameElement);
if (frameLoaderOwner) {
nsRefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
if (frameLoader && frameLoader->GetFrameMessageManager()) {
frameLoader->GetFrameMessageManager()->ReceiveMessage(mFrameElement,
aMessage,
PR_TRUE,
aJSON,
aJSONRetVal);
}
}
return true;
static_cast<ContentProcessParent*>(Manager())->ReportChildAlreadyBlocked();
return ReceiveMessage(aMessage, PR_TRUE, aJSON, &aObjects, aJSONRetVal);
}
bool
TabParent::RecvsendAsyncMessageToParent(const nsString& aMessage,
const nsString& aJSON)
{
return ReceiveMessage(aMessage, PR_FALSE, aJSON, nsnull);
}
bool
TabParent::ReceiveMessage(const nsString& aMessage,
PRBool aSync,
const nsString& aJSON,
const nsTArray<PObjectWrapperParent*>* aObjects,
nsTArray<nsString>* aJSONRetVal)
{
nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner =
do_QueryInterface(mFrameElement);
if (frameLoaderOwner) {
nsRefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
if (frameLoader && frameLoader->GetFrameMessageManager()) {
nsTArray<nsString> dummy;
frameLoader->GetFrameMessageManager()->ReceiveMessage(mFrameElement,
aMessage,
PR_FALSE,
aJSON,
nsnull);
nsFrameMessageManager* manager = frameLoader->GetFrameMessageManager();
JSContext* ctx = manager->GetJSContext();
JSAutoRequest ar(ctx);
jsval* dest;
PRUint32 len = aObjects ? aObjects->Length() : 0;
// Because we want JS messages to have always the same properties,
// create array even if len == 0.
JSObject* objectsArray =
js_NewArrayObjectWithCapacity(ctx, len, &dest);
if (!objectsArray) {
return false;
}
nsresult rv = NS_OK;
nsAutoGCRoot arrayGCRoot(&objectsArray, &rv);
NS_ENSURE_SUCCESS(rv, false);
for (PRUint32 i = 0; i < len; ++i) {
mozilla::jsipc::ObjectWrapperParent* wrapper =
static_cast<mozilla::jsipc::ObjectWrapperParent*>(aObjects->ElementAt(i));
dest[i] = OBJECT_TO_JSVAL(wrapper ? wrapper->GetJSObject(ctx) : nsnull);
}
manager->ReceiveMessage(mFrameElement,
aMessage,
aSync,
aJSON,
objectsArray,
aJSONRetVal);
}
}
return true;

View File

@ -60,6 +60,7 @@ namespace mozilla {
namespace jsipc {
class PContextWrapperParent;
class PObjectWrapperParent;
}
namespace dom {
@ -114,9 +115,10 @@ public:
bool* aAllowRefresh);
virtual bool AnswercreateWindow(PIFrameEmbeddingParent** retval);
virtual bool RecvsendSyncMessageToParent(const nsString& aMessage,
const nsString& aJSON,
nsTArray<nsString>* aJSONRetVal);
virtual bool AnswersendSyncMessageToParent(const nsString& aMessage,
const nsString& aJSON,
const nsTArray<PObjectWrapperParent*>&,
nsTArray<nsString>* aJSONRetVal);
virtual bool RecvsendAsyncMessageToParent(const nsString& aMessage,
const nsString& aJSON);
@ -163,6 +165,12 @@ public:
NS_DECL_NSIWEBPROGRESS
protected:
bool ReceiveMessage(const nsString& aMessage,
PRBool aSync,
const nsString& aJSON,
const nsTArray<PObjectWrapperParent*>* aObjects,
nsTArray<nsString>* aJSONRetVal = nsnull);
TabParentListenerInfo* GetListenerInfo(nsIWebProgressListener *aListener);
nsIDOMElement* mFrameElement;

View File

@ -15,7 +15,7 @@ addEventListener("click",
dump(e.target + "\n");
if (e.target instanceof Components.interfaces.nsIDOMHTMLAnchorElement &&
dshell == docShell) {
var retval = sendSyncMessage("linkclick", { href : e.target.href });
var retval = sendSyncMessage("linkclick", { href : e.target.href }, e, 123, "a string");
dump(uneval(retval[0]) + "\n");
// Test here also that both retvals are the same
sendAsyncMessage("linkclick-reply-object", uneval(retval[0]) == uneval(retval[1]) ? retval[0] : "");

View File

@ -98,8 +98,19 @@
// 2. Test that adding message listener works, and that receiving a sync message works.
messageManager.addMessageListener("linkclick",
function(m) {
document.getElementById("messageLog").value = m.name + ": " + m.json.href;
return { message: "linkclick-received" };
// This checks that json and CPOW sending works in sync messages.
if (m.objects.length == 3 &amp;&amp;
m.objects[0].target.href == m.json.href &amp;&amp;
m.objects[1] == 123 &amp;&amp;
m.objects[2] == "a string") {
// Test that crossProcessObjectWrapper can be used in sync messages.
if ((document.getElementById('page')
.QueryInterface(Components.interfaces.nsIFrameLoaderOwner)
.crossProcessObjectWrapper + "").indexOf("Window") >= 0) {
document.getElementById("messageLog").value = m.name + ": " + m.json.href;
return { message: "linkclick-received" };
}
}
});
// 3. Test that returning multiple json results works.
@ -124,9 +135,14 @@
// 5. Final test to check that everything went ok.
messageManager.addMessageListener("chrome-message-reply",
function(m) {
// Check that 'this' and .target values are handled correctly.
// Check that 'this' and .target values are handled correctly
// Check also that crossProcessObjectWrapper can be used in
// asynchronous message handlers.
if (m.target == document.getElementById("page") &amp;&amp;
this == messageManager) {
this == messageManager &amp;&amp;
(document.getElementById('page')
.QueryInterface(Components.interfaces.nsIFrameLoaderOwner)
.crossProcessObjectWrapper + "").indexOf("Window") >= 0) {
// Check that the message properties are enumerable.
var hasName = false;
var hasSync = false;

View File

@ -73,7 +73,7 @@ namespace {
JSOPTION_DONT_REPORT_UNCAUGHT)))
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
mStack.Push(cx);
mStack.Push(cx, PR_FALSE);
}
~AutoContextPusher() {