Bug 1571063 - Simplify BrowsingContext field sync logic, r=farre

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nika Layzell 2019-08-07 17:07:19 +00:00
parent 52c343cca6
commit ea27710b35
10 changed files with 147 additions and 183 deletions

View File

@ -852,57 +852,72 @@ void BrowsingContext::PostMessageMoz(JSContext* aCx,
}
void BrowsingContext::Transaction::Commit(BrowsingContext* aBrowsingContext) {
if (!Validate(aBrowsingContext, nullptr)) {
MOZ_CRASH("Cannot commit invalid BrowsingContext transaction");
}
if (XRE_IsContentProcess()) {
ContentChild* cc = ContentChild::GetSingleton();
// Increment the field epoch for fields affected by this transaction. We
// only need to do this in content.
#define MOZ_BC_FIELD_RACY(name, ...) \
if (m##name) { \
aBrowsingContext->mFieldEpochs.m##name++; \
uint64_t epoch = cc->NextBrowsingContextFieldEpoch();
#define MOZ_BC_FIELD(name, ...) \
if (m##name) { \
aBrowsingContext->mEpochs.name = epoch; \
}
#define MOZ_BC_FIELD(...) /* nothing */
#include "mozilla/dom/BrowsingContextFieldList.h"
ContentChild* cc = ContentChild::GetSingleton();
cc->SendCommitBrowsingContextTransaction(aBrowsingContext, *this,
aBrowsingContext->mFieldEpochs);
cc->SendCommitBrowsingContextTransaction(aBrowsingContext, *this, epoch);
} else {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
aBrowsingContext->Group()->EachParent([&](ContentParent* aParent) {
const FieldEpochs& childEpochs =
aBrowsingContext->Canonical()->GetFieldEpochsForChild(aParent);
Unused << aParent->SendCommitBrowsingContextTransaction(
aBrowsingContext, *this, childEpochs);
aBrowsingContext, *this, aParent->GetBrowsingContextFieldEpoch());
});
}
Apply(aBrowsingContext, nullptr);
Apply(aBrowsingContext);
}
bool BrowsingContext::Transaction::Validate(BrowsingContext* aBrowsingContext,
ContentParent* aSource) {
#define MOZ_BC_FIELD(name, ...) \
if (m##name && !aBrowsingContext->MaySet##name(*m##name, aSource)) { \
NS_WARNING("Invalid attempt to set BC field " #name); \
return false; \
}
#include "mozilla/dom/BrowsingContextFieldList.h"
mValidated = true;
return true;
}
void BrowsingContext::Transaction::Apply(BrowsingContext* aBrowsingContext,
ContentParent* aSource,
const FieldEpochs* aEpochs) {
// Filter out racy fields which have been updated in this process since this
// transaction was committed in the parent. This should only ever occur in the
// content process.
if (aEpochs) {
MOZ_ASSERT(XRE_IsContentProcess());
#define MOZ_BC_FIELD_RACY(name, ...) \
if (m##name) { \
if (aEpochs->m##name < aBrowsingContext->mFieldEpochs.m##name) { \
m##name.reset(); \
} \
}
#define MOZ_BC_FIELD(...) /* nothing */
#include "mozilla/dom/BrowsingContextFieldList.h"
}
bool BrowsingContext::Transaction::Validate(BrowsingContext* aBrowsingContext,
ContentParent* aSource,
uint64_t aEpoch) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess(),
"Should only be called in content process");
#define MOZ_BC_FIELD(name, ...) \
if (m##name) { \
aBrowsingContext->WillSet##name(*m##name, aSource); \
aBrowsingContext->m##name = std::move(*m##name); \
aBrowsingContext->DidSet##name(aSource); \
m##name.reset(); \
// Clear fields which are obsoleted by the epoch.
#define MOZ_BC_FIELD(name, ...) \
if (m##name && aBrowsingContext->mEpochs.name < aEpoch) { \
m##name.reset(); \
}
#include "mozilla/dom/BrowsingContextFieldList.h"
return Validate(aBrowsingContext, aSource);
}
void BrowsingContext::Transaction::Apply(BrowsingContext* aBrowsingContext) {
MOZ_RELEASE_ASSERT(mValidated,
"Must validate BrowsingContext Transaction before Apply");
#define MOZ_BC_FIELD(name, ...) \
if (m##name) { \
aBrowsingContext->m##name = std::move(*m##name); \
aBrowsingContext->DidSet##name(); \
m##name.reset(); \
}
#include "mozilla/dom/BrowsingContextFieldList.h"
}
@ -969,7 +984,7 @@ void BrowsingContext::StartDelayedAutoplayMediaComponents() {
mDocShell->StartDelayedAutoplayMediaComponents();
}
void BrowsingContext::DidSetIsActivatedByUserGesture(ContentParent* aSource) {
void BrowsingContext::DidSetIsActivatedByUserGesture() {
MOZ_ASSERT(!mParent, "Set user activation flag on non top-level context!");
USER_ACTIVATION_LOG(
"Set user gesture activation %d for %s browsing context 0x%08" PRIx64,
@ -1044,6 +1059,10 @@ bool IPDLParamTraits<dom::BrowsingContext*>::Read(
void IPDLParamTraits<dom::BrowsingContext::Transaction>::Write(
IPC::Message* aMessage, IProtocol* aActor,
const dom::BrowsingContext::Transaction& aTransaction) {
MOZ_RELEASE_ASSERT(
aTransaction.mValidated,
"Must validate BrowsingContext Transaction before sending");
#define MOZ_BC_FIELD(name, ...) \
WriteIPDLParam(aMessage, aActor, aTransaction.m##name);
#include "mozilla/dom/BrowsingContextFieldList.h"
@ -1052,6 +1071,8 @@ void IPDLParamTraits<dom::BrowsingContext::Transaction>::Write(
bool IPDLParamTraits<dom::BrowsingContext::Transaction>::Read(
const IPC::Message* aMessage, PickleIterator* aIterator, IProtocol* aActor,
dom::BrowsingContext::Transaction* aTransaction) {
aTransaction->mValidated = false;
#define MOZ_BC_FIELD(name, ...) \
if (!ReadIPDLParam(aMessage, aIterator, aActor, &aTransaction->m##name)) { \
return false; \
@ -1061,27 +1082,6 @@ bool IPDLParamTraits<dom::BrowsingContext::Transaction>::Read(
return true;
}
void IPDLParamTraits<dom::BrowsingContext::FieldEpochs>::Write(
IPC::Message* aMessage, IProtocol* aActor,
const dom::BrowsingContext::FieldEpochs& aEpochs) {
#define MOZ_BC_FIELD_RACY(name, ...) \
WriteIPDLParam(aMessage, aActor, aEpochs.m##name);
#define MOZ_BC_FIELD(...) /* nothing */
#include "mozilla/dom/BrowsingContextFieldList.h"
}
bool IPDLParamTraits<dom::BrowsingContext::FieldEpochs>::Read(
const IPC::Message* aMessage, PickleIterator* aIterator, IProtocol* aActor,
dom::BrowsingContext::FieldEpochs* aEpochs) {
#define MOZ_BC_FIELD_RACY(name, ...) \
if (!ReadIPDLParam(aMessage, aIterator, aActor, &aEpochs->m##name)) { \
return false; \
}
#define MOZ_BC_FIELD(...) /* nothing */
#include "mozilla/dom/BrowsingContextFieldList.h"
return true;
}
void IPDLParamTraits<dom::BrowsingContext::IPCInitializer>::Write(
IPC::Message* aMessage, IProtocol* aActor,
const dom::BrowsingContext::IPCInitializer& aInit) {

View File

@ -68,8 +68,10 @@ class BrowsingContextBase {
type m##name; \
\
/* shadow to validate fields. aSource is setter process or null*/ \
void WillSet##name(type const& aValue, ContentParent* aSource) {} \
void DidSet##name(ContentParent* aSource) {}
bool MaySet##name(type const& aValue, ContentParent* aSource) { \
return true; \
} \
void DidSet##name() {}
#include "mozilla/dom/BrowsingContextFieldList.h"
};
@ -291,17 +293,6 @@ class BrowsingContext : public nsWrapperCache, public BrowsingContextBase {
void StartDelayedAutoplayMediaComponents();
/**
* Each synced racy field in a BrowsingContext needs to have a epoch value
* which is used to resolve race conflicts by ensuring that only the last
* message received in the parent process wins.
*/
struct FieldEpochs {
#define MOZ_BC_FIELD(...) /* nothing */
#define MOZ_BC_FIELD_RACY(name, ...) uint64_t m##name = 0;
#include "mozilla/dom/BrowsingContextFieldList.h"
};
/**
* Transaction object. This object is used to specify and then commit
* modifications to synchronized fields in BrowsingContexts.
@ -309,36 +300,36 @@ class BrowsingContext : public nsWrapperCache, public BrowsingContextBase {
class Transaction {
public:
// Apply the changes from this transaction to the specified BrowsingContext
// in all processes. This method will call the correct `WillSet` and
// in all processes. This method will call the correct `MaySet` and
// `DidSet` methods, as well as move the value.
//
// NOTE: This method mutates `this`, resetting all members to `Nothing()`
void Commit(BrowsingContext* aOwner);
// You probably don't want to directly call this method - instead call
// `Commit`, which will perform the necessary synchronization.
// This method should be called before invoking `Apply` on this transaction
// object.
//
// |aSource| is the ContentParent which is performing the mutation in the
// parent process.
void Apply(BrowsingContext* aOwner, ContentParent* aSource,
const FieldEpochs* aEpochs = nullptr);
MOZ_MUST_USE bool Validate(BrowsingContext* aOwner, ContentParent* aSource,
uint64_t aEpoch);
MOZ_MUST_USE bool Validate(BrowsingContext* aOwner, ContentParent* aSource);
bool HasNonRacyField() const {
#define MOZ_BC_FIELD(name, ...) \
if (m##name.isSome()) { \
return true; \
}
#define MOZ_BC_FIELD_RACY(...) /* nothing */
#include "mozilla/dom/BrowsingContextFieldList.h"
return false;
}
// You probably don't want to directly call this method - instead call
// `Commit`, which will perform the necessary synchronization.
//
// `Validate` must be called before calling this method.
void Apply(BrowsingContext* aOwner);
#define MOZ_BC_FIELD(name, type) mozilla::Maybe<type> m##name;
#include "mozilla/dom/BrowsingContextFieldList.h"
private:
friend struct mozilla::ipc::IPDLParamTraits<Transaction>;
// Has `Validate` been called on this method yet?
// NOTE: This field is not synced, and must be called in every process.
bool mValidated = false;
};
#define MOZ_BC_FIELD(name, type) \
@ -449,15 +440,16 @@ class BrowsingContext : public nsWrapperCache, public BrowsingContextBase {
};
// Ensure that opener is in the same BrowsingContextGroup.
void WillSetOpener(const uint64_t& aValue, ContentParent* aSource) {
bool MaySetOpener(const uint64_t& aValue, ContentParent* aSource) {
if (aValue != 0) {
RefPtr<BrowsingContext> opener = Get(aValue);
MOZ_RELEASE_ASSERT(opener && opener->Group() == Group());
return opener && opener->Group() == Group();
}
return true;
}
// Ensure that we only set the flag on the top level browsing context.
void DidSetIsActivatedByUserGesture(ContentParent* aSource);
void DidSetIsActivatedByUserGesture();
// Type of BrowsingContent
const Type mType;
@ -479,7 +471,17 @@ class BrowsingContext : public nsWrapperCache, public BrowsingContextBase {
JS::Heap<JSObject*> mWindowProxy;
LocationProxy mLocation;
FieldEpochs mFieldEpochs;
// Whenever a `Transaction` is committed, it is associated with a new
// "Browsing Context Epoch". The epoch is associated with a specific content
// process. This `mEpochs` field tracks the epoch of the most recent comitted
// transaction in this process, and is used to resolve races between processes
// and ensure browsing context field consistency.
//
// This field is only used by content processes.
struct {
#define MOZ_BC_FIELD(name, ...) uint64_t name;
#include "mozilla/dom/BrowsingContextFieldList.h"
} mEpochs;
// Is the most recent Document in this BrowsingContext loaded within this
// process? This may be true with a null mDocShell after the Window has been
@ -509,7 +511,6 @@ extern bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
JS::MutableHandle<JSObject*> aRetVal);
typedef BrowsingContext::Transaction BrowsingContextTransaction;
typedef BrowsingContext::FieldEpochs BrowsingContextFieldEpochs;
typedef BrowsingContext::IPCInitializer BrowsingContextInitializer;
typedef BrowsingContext::Children BrowsingContextChildren;
@ -535,16 +536,6 @@ struct IPDLParamTraits<dom::BrowsingContext::Transaction> {
dom::BrowsingContext::Transaction* aTransaction);
};
template <>
struct IPDLParamTraits<dom::BrowsingContext::FieldEpochs> {
static void Write(IPC::Message* aMessage, IProtocol* aActor,
const dom::BrowsingContext::FieldEpochs& aEpochs);
static bool Read(const IPC::Message* aMessage, PickleIterator* aIterator,
IProtocol* aActor,
dom::BrowsingContext::FieldEpochs* aEpochs);
};
template <>
struct IPDLParamTraits<dom::BrowsingContext::IPCInitializer> {
static void Write(IPC::Message* aMessage, IProtocol* aActor,

View File

@ -4,18 +4,14 @@
* 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/. */
// By defualt, synced fields may only be set by the currently active process,
// however a field can be marked as `MOZ_BC_FIELD_RACY` to relax this
// restriction, and allow it to be set from any process.
// Fields are, by default, settable by any process and readable by any process.
// Racy sets will be resolved as-if they occurred in the order the parent
// process finds out about them.
//
// Process restrictions on racy fields may be added in `WillSet{name}`
// validators.
#ifndef MOZ_BC_FIELD_RACY
# define MOZ_BC_FIELD_RACY MOZ_BC_FIELD
#endif
MOZ_BC_FIELD_RACY(Name, nsString)
MOZ_BC_FIELD_RACY(Closed, bool)
// Process restrictions may be added by declaring a method `MaySet{name}` on
// `BrowsingContext`.
MOZ_BC_FIELD(Name, nsString)
MOZ_BC_FIELD(Closed, bool)
MOZ_BC_FIELD(CrossOriginPolicy, nsILoadInfo::CrossOriginPolicy)
MOZ_BC_FIELD(InheritedCrossOriginPolicy, nsILoadInfo::CrossOriginPolicy)
MOZ_BC_FIELD(OpenerPolicy, nsILoadInfo::CrossOriginOpenerPolicy)
@ -26,7 +22,6 @@ MOZ_BC_FIELD(OpenerId, uint64_t)
// Toplevel browsing contexts only. This field controls whether the browsing
// context is currently considered to be activated by a gesture.
MOZ_BC_FIELD_RACY(IsActivatedByUserGesture, bool)
MOZ_BC_FIELD(IsActivatedByUserGesture, bool)
#undef MOZ_BC_FIELD
#undef MOZ_BC_FIELD_RACY

View File

@ -136,31 +136,6 @@ void CanonicalBrowsingContext::SetEmbedderWindowGlobal(
mEmbedderWindowGlobal = aGlobal;
}
bool CanonicalBrowsingContext::ValidateTransaction(
const Transaction& aTransaction, ContentParent* aProcess) {
if (MOZ_LOG_TEST(GetLog(), LogLevel::Debug)) {
#define MOZ_BC_FIELD(name, ...) \
if (aTransaction.m##name.isSome()) { \
MOZ_LOG(GetLog(), LogLevel::Debug, \
("Validate Transaction 0x%08" PRIx64 " set " #name \
" (from: 0x%08" PRIx64 " owner: 0x%08" PRIx64 ")", \
Id(), aProcess ? static_cast<uint64_t>(aProcess->ChildID()) : 0, \
mProcessId)); \
}
#include "mozilla/dom/BrowsingContextFieldList.h"
}
// Check that the correct process is performing sets for transactions with
// non-racy fields.
if (aTransaction.HasNonRacyField()) {
if (NS_WARN_IF(aProcess && mProcessId != aProcess->ChildID())) {
return false;
}
}
return true;
}
JSObject* CanonicalBrowsingContext::WrapObject(
JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
return CanonicalBrowsingContext_Binding::Wrap(aCx, this, aGivenProto);
@ -209,20 +184,5 @@ void CanonicalBrowsingContext::NotifyMediaMutedChanged(bool aMuted) {
});
}
void CanonicalBrowsingContext::SetFieldEpochsForChild(
ContentParent* aChild, const BrowsingContext::FieldEpochs& aEpochs) {
mChildFieldEpochs.Put(aChild->ChildID(), aEpochs);
}
const BrowsingContext::FieldEpochs&
CanonicalBrowsingContext::GetFieldEpochsForChild(ContentParent* aChild) {
static const BrowsingContext::FieldEpochs sDefaultFieldEpochs;
if (auto entry = mChildFieldEpochs.Lookup(aChild->ChildID())) {
return entry.Data();
}
return sDefaultFieldEpochs;
}
} // namespace dom
} // namespace mozilla

View File

@ -78,15 +78,6 @@ class CanonicalBrowsingContext final : public BrowsingContext {
// other top level windows in other processes.
void NotifyMediaMutedChanged(bool aMuted);
// Validate that the given process is allowed to perform the given
// transaction. aSource is |nullptr| if set in the parent process.
bool ValidateTransaction(const Transaction& aTransaction,
ContentParent* aSource);
void SetFieldEpochsForChild(ContentParent* aChild,
const FieldEpochs& aEpochs);
const FieldEpochs& GetFieldEpochsForChild(ContentParent* aChild);
protected:
void Traverse(nsCycleCollectionTraversalCallback& cb);
void Unlink();
@ -108,10 +99,6 @@ class CanonicalBrowsingContext final : public BrowsingContext {
nsTHashtable<nsRefPtrHashKey<WindowGlobalParent>> mWindowGlobals;
RefPtr<WindowGlobalParent> mCurrentWindowGlobal;
RefPtr<WindowGlobalParent> mEmbedderWindowGlobal;
// Generation information for each content process which has interacted with
// this CanonicalBrowsingContext, by ChildID.
nsDataHashtable<nsUint64HashKey, FieldEpochs> mChildFieldEpochs;
};
} // namespace dom

View File

@ -4045,10 +4045,18 @@ mozilla::ipc::IPCResult ContentChild::RecvWindowPostMessage(
mozilla::ipc::IPCResult ContentChild::RecvCommitBrowsingContextTransaction(
BrowsingContext* aContext, BrowsingContext::Transaction&& aTransaction,
BrowsingContext::FieldEpochs&& aEpochs) {
if (aContext) {
aTransaction.Apply(aContext, nullptr, &aEpochs);
uint64_t aEpoch) {
if (!aContext || aContext->IsDiscarded()) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
("ChildIPC: Trying to send a message to dead or detached context"));
return IPC_OK();
}
if (!aTransaction.Validate(aContext, nullptr, aEpoch)) {
return IPC_FAIL(this, "Invalid BrowsingContext transaction from Parent");
}
aTransaction.Apply(aContext);
return IPC_OK();
}

View File

@ -696,6 +696,15 @@ class ContentChild final : public PContentChild,
void HoldBrowsingContextGroup(BrowsingContextGroup* aBCG);
void ReleaseBrowsingContextGroup(BrowsingContextGroup* aBCG);
// See `BrowsingContext::mEpochs` for an explanation of this field.
uint64_t GetBrowsingContextFieldEpoch() const {
return mBrowsingContextFieldEpoch;
}
uint64_t NextBrowsingContextFieldEpoch() {
mBrowsingContextFieldEpoch++;
return mBrowsingContextFieldEpoch;
}
#ifdef NIGHTLY_BUILD
// Fetch the current number of pending input events.
//
@ -747,7 +756,7 @@ class ContentChild final : public PContentChild,
mozilla::ipc::IPCResult RecvCommitBrowsingContextTransaction(
BrowsingContext* aContext, BrowsingContext::Transaction&& aTransaction,
BrowsingContext::FieldEpochs&& aEpochs);
uint64_t aEpoch);
#ifdef NIGHTLY_BUILD
virtual PContentChild::Result OnMessageReceived(const Message& aMsg) override;
@ -839,6 +848,9 @@ class ContentChild final : public PContentChild,
nsTArray<RefPtr<BrowsingContextGroup>> mBrowsingContextGroupHolder;
// See `BrowsingContext::mEpochs` for an explanation of this field.
uint64_t mBrowsingContextFieldEpoch = 0;
DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
};

View File

@ -6060,29 +6060,33 @@ void ContentParent::OnBrowsingContextGroupUnsubscribe(
mozilla::ipc::IPCResult ContentParent::RecvCommitBrowsingContextTransaction(
BrowsingContext* aContext, BrowsingContext::Transaction&& aTransaction,
BrowsingContext::FieldEpochs&& aEpochs) {
uint64_t aEpoch) {
// Record the new BrowsingContextFieldEpoch associated with this transaction.
// This should be done unconditionally, so that we're always in-sync.
//
// The order the parent process receives transactions is considered the
// "canonical" ordering, so we don't need to worry about doing any
// epoch-related validation.
MOZ_ASSERT(aEpoch == mBrowsingContextFieldEpoch + 1,
"Child process skipped an epoch?");
mBrowsingContextFieldEpoch = aEpoch;
if (!aContext || aContext->IsDiscarded()) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
("ParentIPC: Trying to run transaction on missing context."));
return IPC_OK();
}
// Check if the transaction is valid.
if (!aContext->Canonical()->ValidateTransaction(aTransaction, this)) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Error,
("ParentIPC: Trying to run invalid transaction."));
return IPC_FAIL_NO_REASON(this);
if (!aTransaction.Validate(aContext, this)) {
return IPC_FAIL(this, "Invalid BrowsingContext transaction from Child");
}
aContext->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
Unused << aParent->SendCommitBrowsingContextTransaction(
aContext, aTransaction,
aContext->Canonical()->GetFieldEpochsForChild(aParent));
aContext, aTransaction, aParent->GetBrowsingContextFieldEpoch());
});
aTransaction.Apply(aContext, this);
aContext->Canonical()->SetFieldEpochsForChild(this, aEpochs);
aTransaction.Apply(aContext);
return IPC_OK();
}
} // namespace dom

View File

@ -1058,7 +1058,7 @@ class ContentParent final : public PContentParent,
mozilla::ipc::IPCResult RecvCommitBrowsingContextTransaction(
BrowsingContext* aContext, BrowsingContext::Transaction&& aTransaction,
BrowsingContext::FieldEpochs&& aEpochs);
uint64_t aEpoch);
mozilla::ipc::IPCResult RecvFirstIdle();
@ -1218,6 +1218,11 @@ class ContentParent final : public PContentParent,
void OnBrowsingContextGroupSubscribe(BrowsingContextGroup* aGroup);
void OnBrowsingContextGroupUnsubscribe(BrowsingContextGroup* aGroup);
// See `BrowsingContext::mEpochs` for an explanation of this field.
uint64_t GetBrowsingContextFieldEpoch() const {
return mBrowsingContextFieldEpoch;
}
void UpdateNetworkLinkType();
static bool ShouldSyncPreference(const char16_t* aData);
@ -1360,6 +1365,9 @@ class ContentParent final : public PContentParent,
#endif
nsTHashtable<nsRefPtrHashKey<BrowsingContextGroup>> mGroups;
// See `BrowsingContext::mEpochs` for an explanation of this field.
uint64_t mBrowsingContextFieldEpoch = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(ContentParent, NS_CONTENTPARENT_IID)

View File

@ -99,7 +99,6 @@ using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h";
using refcounted class nsIInputStream from "mozilla/ipc/IPCStreamUtils.h";
using refcounted class mozilla::dom::BrowsingContext from "mozilla/dom/BrowsingContext.h";
using mozilla::dom::BrowsingContextTransaction from "mozilla/dom/BrowsingContext.h";
using mozilla::dom::BrowsingContextFieldEpochs from "mozilla/dom/BrowsingContext.h";
using mozilla::dom::BrowsingContextInitializer from "mozilla/dom/BrowsingContext.h";
using base::SharedMemoryHandle from "base/shared_memory.h";
using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h";
@ -1390,7 +1389,7 @@ parent:
both:
async CommitBrowsingContextTransaction(BrowsingContext aContext,
BrowsingContextTransaction aTransaction,
BrowsingContextFieldEpochs aEpochs);
uint64_t aEpoch);
async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
Principal aPrincipal, ClonedMessageData aData);