Bug 1605566 - MessagePort + wasm - part 4 - Implement RefMessageBodyService, r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D59615

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andrea Marchesini 2020-01-22 09:33:29 +00:00
parent 4da71e81af
commit 6c0733d2e8
8 changed files with 259 additions and 24 deletions

View File

@ -67,7 +67,7 @@ class SharedJSAllocatedData final {
return sharedData.forget();
}
NS_INLINE_DECL_REFCOUNTING(SharedJSAllocatedData)
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedJSAllocatedData)
JSStructuredCloneData& Data() { return mData; }
size_t DataLength() const { return mData.Size(); }

View File

@ -31,6 +31,7 @@
#include "nsGlobalWindow.h"
#include "nsPresContext.h"
#include "SharedMessagePortMessage.h"
#include "RefMessageBodyService.h"
#include "nsIBFCacheEntry.h"
#include "mozilla/dom/Document.h"
@ -122,7 +123,7 @@ class PostMessageRunnable final : public CancelableRunnable {
MarkerTracingType::START);
}
mData->Read(cx, &value, rv);
mData->Read(cx, &value, mPort->mRefMessageBodyService, rv);
if (isTimelineRecording) {
end = MakeUnique<MessagePortTimelineMarker>(
@ -196,6 +197,7 @@ NS_IMPL_RELEASE_INHERITED(MessagePort, DOMEventTargetHelper)
MessagePort::MessagePort(nsIGlobalObject* aGlobal, State aState)
: DOMEventTargetHelper(aGlobal),
mRefMessageBodyService(RefMessageBodyService::GetOrCreate()),
mState(aState),
mMessageQueueEnabled(false),
mIsKeptAlive(false),
@ -340,7 +342,8 @@ void MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
MarkerTracingType::START);
}
data->Write(aCx, aMessage, transferable, aRv);
data->Write(aCx, aMessage, transferable, mIdentifier->uuid(),
mRefMessageBodyService, aRv);
if (isTimelineRecording) {
end = MakeUnique<MessagePortTimelineMarker>(
@ -489,6 +492,10 @@ void MessagePort::CloseInternal(bool aSoftly) {
mMessages.Clear();
}
// Let's inform the RefMessageBodyService that any our shared messages are
// now invalid.
mRefMessageBodyService->ForgetPort(mIdentifier->uuid());
if (mState == eStateUnshippedEntangled) {
MOZ_DIAGNOSTIC_ASSERT(mUnshippedEntangledPort);
@ -657,6 +664,11 @@ void MessagePort::Disentangle() {
messages);
mActor->SendDisentangle(messages);
}
// Let's inform the RefMessageBodyService that any our shared messages are
// now invalid.
mRefMessageBodyService->ForgetPort(mIdentifier->uuid());
// Only clear mMessages after the MessageData instances have gone out of scope
// because they borrow mMessages' underlying JSStructuredCloneDatas.
mMessages.Clear();

View File

@ -27,6 +27,7 @@ class MessagePortChild;
struct PostMessageOptions;
class PostMessageRunnable;
class SharedMessagePortMessage;
class RefMessageBodyService;
class StrongWorkerRef;
// A class to hold a MessagePortIdentifier from
@ -207,6 +208,8 @@ class MessagePort final : public DOMEventTargetHelper {
RefPtr<MessagePort> mUnshippedEntangledPort;
RefPtr<RefMessageBodyService> mRefMessageBodyService;
nsTArray<RefPtr<SharedMessagePortMessage>> mMessages;
nsTArray<RefPtr<SharedMessagePortMessage>> mMessagesForTheOtherPort;

View File

@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "RefMessageBodyService.h"
namespace mozilla {
namespace dom {
StaticMutex sRefMessageBodyServiceMutex;
// Raw pointer because the service is kept alive by MessagePorts.
// See the CTOR and the DTOR of this object.
RefMessageBodyService* sService;
// static
already_AddRefed<RefMessageBodyService> RefMessageBodyService::GetOrCreate() {
StaticMutexAutoLock lock(sRefMessageBodyServiceMutex);
RefPtr<RefMessageBodyService> service = GetOrCreateInternal(lock);
return service.forget();
}
// static
RefMessageBodyService* RefMessageBodyService::GetOrCreateInternal(
const StaticMutexAutoLock& aProofOfLock) {
if (!sService) {
sService = new RefMessageBodyService();
}
return sService;
}
RefMessageBodyService::RefMessageBodyService() {
MOZ_DIAGNOSTIC_ASSERT(sService == nullptr);
}
RefMessageBodyService::~RefMessageBodyService() {
MOZ_DIAGNOSTIC_ASSERT(sService == this);
sService = nullptr;
}
nsID RefMessageBodyService::Register(already_AddRefed<RefMessageBody> aBody,
ErrorResult& aRv) {
RefPtr<RefMessageBody> body = aBody;
MOZ_ASSERT(body);
nsID uuid = {};
aRv = nsContentUtils::GenerateUUIDInPlace(uuid);
if (NS_WARN_IF(aRv.Failed())) {
return nsID();
}
StaticMutexAutoLock lock(sRefMessageBodyServiceMutex);
GetOrCreateInternal(lock)->mMessages.Put(uuid, body);
return uuid;
}
already_AddRefed<RefMessageBody> RefMessageBodyService::Steal(nsID& aID) {
StaticMutexAutoLock lock(sRefMessageBodyServiceMutex);
if (!sService) {
return nullptr;
}
RefPtr<RefMessageBody> body;
sService->mMessages.Remove(aID, getter_AddRefs(body));
return body.forget();
}
void RefMessageBodyService::ForgetPort(nsID& aPortID) {
StaticMutexAutoLock lock(sRefMessageBodyServiceMutex);
if (!sService) {
return;
}
for (auto iter = sService->mMessages.ConstIter(); !iter.Done(); iter.Next()) {
if (iter.UserData()->PortID() == aPortID) {
iter.Remove();
}
}
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_RefMessageBodyService_h
#define mozilla_dom_RefMessageBodyService_h
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/StructuredCloneHolder.h"
#include "mozilla/StaticMutex.h"
#include "nsRefPtrHashtable.h"
namespace mozilla {
namespace dom {
class RefMessageBody final {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefMessageBody)
RefMessageBody(nsID& aPortID,
UniquePtr<ipc::StructuredCloneData>&& aCloneData)
: mPortID(aPortID), mCloneData(std::move(aCloneData)) {}
const nsID& PortID() const { return mPortID; }
ipc::StructuredCloneData* CloneData() { return mCloneData.get(); }
private:
~RefMessageBody() = default;
nsID mPortID;
UniquePtr<ipc::StructuredCloneData> mCloneData;
};
class RefMessageBodyService final {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefMessageBodyService)
static already_AddRefed<RefMessageBodyService> GetOrCreate();
void ForgetPort(nsID& aPortID);
nsID Register(already_AddRefed<RefMessageBody> aBody, ErrorResult& aRv);
already_AddRefed<RefMessageBody> Steal(nsID& aID);
private:
RefMessageBodyService();
~RefMessageBodyService();
static RefMessageBodyService* GetOrCreateInternal(
const StaticMutexAutoLock& aProofOfLock);
nsRefPtrHashtable<nsIDHashKey, RefMessageBody> mMessages;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_RefMessageBodyService_h

View File

@ -4,6 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "RefMessageBodyService.h"
#include "SharedMessagePortMessage.h"
#include "MessagePort.h"
#include "MessagePortChild.h"
@ -19,6 +20,62 @@ using namespace ipc;
namespace dom {
SharedMessagePortMessage::SharedMessagePortMessage() : mRefDataId({}) {}
void SharedMessagePortMessage::Write(
JSContext* aCx, JS::Handle<JS::Value> aValue,
JS::Handle<JS::Value> aTransfers, nsID& aPortID,
RefMessageBodyService* aRefMessageBodyService, ErrorResult& aRv) {
MOZ_ASSERT(!mCloneData && !mRefData);
MOZ_ASSERT(aRefMessageBodyService);
mCloneData = MakeUnique<ipc::StructuredCloneData>(
JS::StructuredCloneScope::UnknownDestination);
mCloneData->Write(aCx, aValue, aTransfers, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
if (mCloneData->CloneScope() == JS::StructuredCloneScope::DifferentProcess) {
return;
}
MOZ_ASSERT(mCloneData->CloneScope() == JS::StructuredCloneScope::SameProcess);
RefPtr<RefMessageBody> refData =
new RefMessageBody(aPortID, std::move(mCloneData));
mRefDataId = aRefMessageBodyService->Register(refData.forget(), aRv);
}
void SharedMessagePortMessage::Read(
JSContext* aCx, JS::MutableHandle<JS::Value> aValue,
RefMessageBodyService* aRefMessageBodyService, ErrorResult& aRv) {
MOZ_ASSERT(aRefMessageBodyService);
if (mCloneData) {
return mCloneData->Read(aCx, aValue, aRv);
}
MOZ_ASSERT(!mRefData);
mRefData = aRefMessageBodyService->Steal(mRefDataId);
if (!mRefData) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;
}
mRefData->CloneData()->Read(aCx, aValue, aRv);
}
bool SharedMessagePortMessage::TakeTransferredPortsAsSequence(
Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts) {
if (mCloneData) {
return mCloneData->TakeTransferredPortsAsSequence(aPorts);
}
MOZ_ASSERT(mRefData);
return mRefData->CloneData()->TakeTransferredPortsAsSequence(aPorts);
}
/* static */
void SharedMessagePortMessage::FromSharedToMessagesChild(
MessagePortChild* aActor,
@ -34,18 +91,15 @@ void SharedMessagePortMessage::FromSharedToMessagesChild(
for (auto& data : aData) {
MessageData* message = aArray.AppendElement();
if (data->CloneScope() ==
StructuredCloneHolder::StructuredCloneScope::DifferentProcess) {
if (data->mCloneData) {
ClonedMessageData clonedData;
data->BuildClonedMessageDataForBackgroundChild(backgroundManager,
clonedData);
data->mCloneData->BuildClonedMessageDataForBackgroundChild(
backgroundManager, clonedData);
*message = clonedData;
continue;
}
MOZ_ASSERT(data->CloneScope() ==
StructuredCloneHolder::StructuredCloneScope::SameProcess);
*message = RefMessageData(); // TODO
*message = RefMessageData(data->mRefDataId);
}
}
@ -63,10 +117,12 @@ bool SharedMessagePortMessage::FromMessagesToSharedChild(
RefPtr<SharedMessagePortMessage> data = new SharedMessagePortMessage();
if (message.type() == MessageData::TClonedMessageData) {
data->StealFromClonedMessageDataForBackgroundChild(message);
data->mCloneData = MakeUnique<ipc::StructuredCloneData>(
JS::StructuredCloneScope::UnknownDestination);
data->mCloneData->StealFromClonedMessageDataForBackgroundChild(message);
} else {
MOZ_ASSERT(message.type() == MessageData::TRefMessageData);
// TODO
data->mRefDataId = message.get_RefMessageData().uuid();
}
if (!aData.AppendElement(data, mozilla::fallible)) {
@ -94,18 +150,15 @@ bool SharedMessagePortMessage::FromSharedToMessagesParent(
for (auto& data : aData) {
MessageData* message = aArray.AppendElement(mozilla::fallible);
if (data->CloneScope() ==
StructuredCloneHolder::StructuredCloneScope::DifferentProcess) {
if (data->mCloneData) {
ClonedMessageData clonedData;
data->BuildClonedMessageDataForBackgroundParent(backgroundManager,
clonedData);
data->mCloneData->BuildClonedMessageDataForBackgroundParent(
backgroundManager, clonedData);
*message = clonedData;
continue;
}
MOZ_ASSERT(data->CloneScope() ==
StructuredCloneHolder::StructuredCloneScope::SameProcess);
*message = RefMessageData(); // TODO
*message = RefMessageData(data->mRefDataId);
}
return true;
@ -125,10 +178,12 @@ bool SharedMessagePortMessage::FromMessagesToSharedParent(
RefPtr<SharedMessagePortMessage> data = new SharedMessagePortMessage();
if (message.type() == MessageData::TClonedMessageData) {
data->StealFromClonedMessageDataForBackgroundParent(message);
data->mCloneData = MakeUnique<ipc::StructuredCloneData>(
JS::StructuredCloneScope::UnknownDestination);
data->mCloneData->StealFromClonedMessageDataForBackgroundParent(message);
} else {
MOZ_ASSERT(message.type() == MessageData::TRefMessageData);
// TODO
data->mRefDataId = message.get_RefMessageData().uuid();
}
if (!aData.AppendElement(data, mozilla::fallible)) {

View File

@ -15,13 +15,14 @@ namespace dom {
class MessagePortChild;
class MessagePortMessage;
class MessagePortParent;
class RefMessageBody;
class RefMessageBodyService;
class SharedMessagePortMessage final : public ipc::StructuredCloneData {
class SharedMessagePortMessage final {
public:
NS_INLINE_DECL_REFCOUNTING(SharedMessagePortMessage)
SharedMessagePortMessage()
: ipc::StructuredCloneData(StructuredCloneScope::UnknownDestination) {}
SharedMessagePortMessage();
// Note that the populated MessageData borrows the underlying
// JSStructuredCloneData from the SharedMessagePortMessage, so the caller is
@ -49,8 +50,23 @@ class SharedMessagePortMessage final : public ipc::StructuredCloneData {
nsTArray<MessageData>& aArray,
FallibleTArray<RefPtr<SharedMessagePortMessage>>& aData);
void Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue,
RefMessageBodyService* aRefMessageBodyService, ErrorResult& aRv);
void Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
JS::Handle<JS::Value> aTransfers, nsID& aPortID,
RefMessageBodyService* aRefMessageBodyService, ErrorResult& aRv);
bool TakeTransferredPortsAsSequence(
Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts);
private:
~SharedMessagePortMessage() = default;
UniquePtr<ipc::StructuredCloneData> mCloneData;
RefPtr<RefMessageBody> mRefData;
nsID mRefDataId;
};
} // namespace dom

View File

@ -22,6 +22,7 @@ UNIFIED_SOURCES += [
'MessagePortChild.cpp',
'MessagePortParent.cpp',
'MessagePortService.cpp',
'RefMessageBodyService.cpp',
'SharedMessagePortMessage.cpp',
]