diff --git a/docshell/base/CanonicalBrowsingContext.cpp b/docshell/base/CanonicalBrowsingContext.cpp index 4c5c1304934b..a3893f6681dc 100644 --- a/docshell/base/CanonicalBrowsingContext.cpp +++ b/docshell/base/CanonicalBrowsingContext.cpp @@ -168,14 +168,24 @@ void CanonicalBrowsingContext::ReplacedBy( mStatusFilter = nullptr; } aNewContext->mWebProgress = std::move(mWebProgress); - aNewContext->mFields.SetWithoutSyncing(GetBrowserId()); - aNewContext->mFields.SetWithoutSyncing(GetHistoryID()); - aNewContext->mFields.SetWithoutSyncing( - GetExplicitActive()); + + // Use the Transaction for the fields which need to be updated whether or not + // the new context has been attached before. + // SetWithoutSyncing can be used if context hasn't been attached. + Transaction txn; + txn.SetBrowserId(GetBrowserId()); + txn.SetHistoryID(GetHistoryID()); + txn.SetExplicitActive(GetExplicitActive()); + if (aNewContext->EverAttached()) { + MOZ_ALWAYS_SUCCEEDS(txn.Commit(aNewContext)); + } else { + txn.CommitWithoutSyncing(aNewContext); + } // XXXBFCache name handling is still a bit broken in Fission in general, // at least in case name should be cleared. if (aRemotenessOptions.mTryUseBFCache) { + MOZ_ASSERT(!aNewContext->EverAttached()); aNewContext->mFields.SetWithoutSyncing(GetName()); aNewContext->mFields.SetWithoutSyncing( GetHasLoadedNonInitialDocument()); diff --git a/docshell/base/SyncedContext.h b/docshell/base/SyncedContext.h index 0a44c97cc4ac..90c34dbc6463 100644 --- a/docshell/base/SyncedContext.h +++ b/docshell/base/SyncedContext.h @@ -74,6 +74,16 @@ class Transaction { mozilla::ipc::IPCResult CommitFromIPC(const MaybeDiscarded& aOwner, uint64_t aEpoch, ContentChild* aSource); + // Apply the changes from this transaction to the specified Context WITHOUT + // syncing the changes to other processes. + // + // Unlike `Commit`, this method will NOT call the corresponding `CanSet` or + // `DidSet` methods, and can be performed when the target context is + // unattached or discarded. + // + // NOTE: YOU PROBABLY DO NOT WANT TO USE THIS METHOD + void CommitWithoutSyncing(Context* aOwner); + private: friend struct mozilla::ipc::IPDLParamTraits>; diff --git a/docshell/base/SyncedContextInlines.h b/docshell/base/SyncedContextInlines.h index b47016f2a66b..4ad8b99296ac 100644 --- a/docshell/base/SyncedContextInlines.h +++ b/docshell/base/SyncedContextInlines.h @@ -223,6 +223,22 @@ void Transaction::Apply(Context* aOwner, bool aFromIPC) { mModified.clear(); } +template +void Transaction::CommitWithoutSyncing(Context* aOwner) { + MOZ_LOG( + Context::GetSyncLog(), LogLevel::Debug, + ("Transaction::CommitWithoutSyncing(#%" PRIx64 "): %s", aOwner->Id(), + FormatTransaction(mModified, aOwner->mFields.mValues, mValues) + .get())); + + EachIndex([&](auto idx) { + if (mModified.contains(idx)) { + aOwner->mFields.mValues.Get(idx) = std::move(mValues.Get(idx)); + } + }); + mModified.clear(); +} + inline CanSetResult AsCanSetResult(CanSetResult aValue) { return aValue; } inline CanSetResult AsCanSetResult(bool aValue) { return aValue ? CanSetResult::Allow : CanSetResult::Deny;