123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/performance_manager/v8_memory/v8_context_tracker_internal.h"
- #include <utility>
- #include "base/check.h"
- #include "components/performance_manager/v8_memory/v8_context_tracker_helpers.h"
- namespace performance_manager {
- namespace v8_memory {
- namespace internal {
- ////////////////////////////////////////////////////////////////////////////////
- // ExecutionContextData implementation:
- ExecutionContextData::ExecutionContextData(
- ProcessData* process_data,
- const blink::ExecutionContextToken& token,
- mojom::IframeAttributionDataPtr iframe_attribution_data)
- : ExecutionContextState(token, std::move(iframe_attribution_data)),
- process_data_(process_data) {}
- ExecutionContextData::~ExecutionContextData() {
- DCHECK(!IsTracked());
- DCHECK(ShouldDestroy());
- DCHECK_EQ(0u, main_nondetached_v8_context_count_);
- }
- bool ExecutionContextData::IsTracked() const {
- return previous() || next();
- }
- bool ExecutionContextData::ShouldDestroy() const {
- return v8_context_count_ == 0 && !remote_frame_data_;
- }
- void ExecutionContextData::SetRemoteFrameData(
- base::PassKey<RemoteFrameData>,
- RemoteFrameData* remote_frame_data) {
- DCHECK(!remote_frame_data_);
- DCHECK(remote_frame_data);
- remote_frame_data_ = remote_frame_data;
- }
- bool ExecutionContextData::ClearRemoteFrameData(
- base::PassKey<RemoteFrameData>) {
- DCHECK(remote_frame_data_);
- remote_frame_data_ = nullptr;
- return ShouldDestroy();
- }
- void ExecutionContextData::IncrementV8ContextCount(
- base::PassKey<V8ContextData>) {
- ++v8_context_count_;
- }
- bool ExecutionContextData::DecrementV8ContextCount(
- base::PassKey<V8ContextData>) {
- DCHECK_LT(0u, v8_context_count_);
- DCHECK_LT(main_nondetached_v8_context_count_, v8_context_count_);
- --v8_context_count_;
- return ShouldDestroy();
- }
- bool ExecutionContextData::MarkDestroyed(base::PassKey<ProcessData>) {
- if (destroyed)
- return false;
- destroyed = true;
- return true;
- }
- bool ExecutionContextData::MarkMainV8ContextCreated(
- base::PassKey<V8ContextTrackerDataStore>) {
- if (main_nondetached_v8_context_count_ >= v8_context_count_)
- return false;
- if (main_nondetached_v8_context_count_ >= 1)
- return false;
- ++main_nondetached_v8_context_count_;
- return true;
- }
- void ExecutionContextData::MarkMainV8ContextDetached(
- base::PassKey<V8ContextData>) {
- DCHECK_LT(0u, main_nondetached_v8_context_count_);
- --main_nondetached_v8_context_count_;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // RemoteFrameData implementation:
- RemoteFrameData::RemoteFrameData(ProcessData* process_data,
- const blink::RemoteFrameToken& token,
- ExecutionContextData* execution_context_data)
- : process_data_(process_data),
- token_(token),
- execution_context_data_(execution_context_data) {
- DCHECK(process_data);
- DCHECK(execution_context_data);
- execution_context_data->SetRemoteFrameData(PassKey(), this);
- }
- RemoteFrameData::~RemoteFrameData() {
- DCHECK(!IsTracked());
- // If this is the last reference keeping alive a tracked ExecutionContextData,
- // then clean it up as well. Untracked ExecutionContextDatas will go out of
- // scope on their own.
- if (execution_context_data_->ClearRemoteFrameData(PassKey()) &&
- execution_context_data_->IsTracked()) {
- // Reset `execution_context_data_` to nullptr because it will be destroyed
- // using the token below.
- blink::ExecutionContextToken token = execution_context_data_->GetToken();
- execution_context_data_ = nullptr;
- process_data_->data_store()->Destroy(token);
- }
- }
- bool RemoteFrameData::IsTracked() const {
- return previous() || next();
- }
- ////////////////////////////////////////////////////////////////////////////////
- // V8ContextData implementation:
- V8ContextData::V8ContextData(ProcessData* process_data,
- const mojom::V8ContextDescription& description,
- ExecutionContextData* execution_context_data)
- : V8ContextState(description, execution_context_data),
- process_data_(process_data) {
- DCHECK(process_data);
- DCHECK_EQ(static_cast<bool>(execution_context_data),
- static_cast<bool>(description.execution_context_token));
- if (execution_context_data) {
- DCHECK_EQ(execution_context_data->GetToken(),
- description.execution_context_token.value());
- // These must be same process.
- DCHECK_EQ(process_data, execution_context_data->process_data());
- execution_context_data->IncrementV8ContextCount(PassKey());
- }
- }
- V8ContextData::~V8ContextData() {
- DCHECK(!IsTracked());
- // Mark as detached if necessary so that main world counts are appropriately
- // updated even during tear down code paths.
- MarkDetachedImpl();
- // If this is the last reference keeping alive a tracked ExecutionContextData,
- // then clean it up as well. Untracked ExecutionContextDatas will go out of
- // scope on their own.
- auto* execution_context_data = GetExecutionContextData();
- if (execution_context_data &&
- execution_context_data->DecrementV8ContextCount(PassKey()) &&
- execution_context_data->IsTracked()) {
- // Reset the execution_context_state to nullptr because it will be
- // destroyed using the token below.
- blink::ExecutionContextToken token = execution_context_data->GetToken();
- execution_context_state = nullptr;
- process_data_->data_store()->Destroy(token);
- }
- }
- bool V8ContextData::IsTracked() const {
- return previous() || next();
- }
- ExecutionContextData* V8ContextData::GetExecutionContextData() const {
- return static_cast<ExecutionContextData*>(execution_context_state);
- }
- void V8ContextData::SetWasTracked(base::PassKey<V8ContextTrackerDataStore>) {
- DCHECK(!was_tracked_);
- was_tracked_ = true;
- }
- bool V8ContextData::MarkDetached(base::PassKey<ProcessData>) {
- return MarkDetachedImpl();
- }
- bool V8ContextData::IsMainV8Context() const {
- auto* ec_data = GetExecutionContextData();
- if (!ec_data)
- return false;
- // ExecutionContexts hosting worklets have no main world (there can be many
- // worklets sharing an ExecutionContext).
- if (IsWorkletToken(ec_data->GetToken()))
- return false;
- // We've already checked sane combinations of ExecutionContextToken types and
- // world types in ValidateV8ContextDescription, so don't need to be overly
- // thorough here.
- // Only main frames and workers can be "main" contexts.
- auto world_type = description.world_type;
- return world_type == mojom::V8ContextWorldType::kMain ||
- world_type == mojom::V8ContextWorldType::kWorkerOrWorklet;
- }
- bool V8ContextData::MarkDetachedImpl() {
- if (detached)
- return false;
- detached = true;
- // The EC is notified of the main V8 context only when it is passed to the
- // data store (at which point |was_tracked_| is set to true). Only do the
- // symmetric operation if the first occurred.
- if (IsMainV8Context() && was_tracked_) {
- if (auto* ec_data = GetExecutionContextData())
- ec_data->MarkMainV8ContextDetached(PassKey());
- }
- return true;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // ProcessData implementation:
- ProcessData::ProcessData(const ProcessNodeImpl* process_node)
- : data_store_(GetDataStore(process_node)) {}
- ProcessData::~ProcessData() {
- DCHECK(execution_context_datas_.empty());
- DCHECK(remote_frame_datas_.empty());
- DCHECK(v8_context_datas_.empty());
- }
- void ProcessData::TearDown() {
- // First, remove any RemoteFrameData references owned by this ProcessData
- // that are keeping alive ExecutionContextDatas in other ProcessDatas. This
- // can cause ExecutionContextDatas to be torn down.
- while (!remote_frame_datas_.empty()) {
- auto* node = remote_frame_datas_.head();
- data_store_->Destroy(node->value()->GetToken());
- }
- // Drain the list of V8ContextTokens. This will also indirectly clean up and
- // ExecutionContextDatas that are only being kept alive by V8ContextData
- // references.
- while (!v8_context_datas_.empty()) {
- auto* node = v8_context_datas_.head();
- data_store_->Destroy(node->value()->GetToken());
- }
- // Any ExecutionContextDatas still alive are only being kept alive because of
- // RemoteFrameData references from another ProcessData. Clean those up.
- while (!execution_context_datas_.empty()) {
- auto* node = execution_context_datas_.head();
- auto* ec_data = node->value();
- auto* rfd = ec_data->remote_frame_data();
- DCHECK(rfd);
- DCHECK_EQ(0u, ec_data->v8_context_count());
- data_store_->Destroy(rfd->GetToken());
- }
- // We now expect everything to have been cleaned up.
- DCHECK(execution_context_datas_.empty());
- DCHECK(remote_frame_datas_.empty());
- DCHECK(v8_context_datas_.empty());
- }
- void ProcessData::Add(base::PassKey<V8ContextTrackerDataStore>,
- ExecutionContextData* ec_data) {
- DCHECK(ec_data);
- DCHECK_EQ(this, ec_data->process_data());
- DCHECK(!ec_data->ShouldDestroy());
- DCHECK(!ec_data->IsTracked());
- execution_context_datas_.Append(ec_data);
- counts_.IncrementExecutionContextDataCount();
- }
- void ProcessData::Add(base::PassKey<V8ContextTrackerDataStore>,
- RemoteFrameData* rf_data) {
- DCHECK(rf_data);
- DCHECK_EQ(this, rf_data->process_data());
- DCHECK(!rf_data->IsTracked());
- remote_frame_datas_.Append(rf_data);
- }
- void ProcessData::Add(base::PassKey<V8ContextTrackerDataStore>,
- V8ContextData* v8_data) {
- DCHECK(v8_data);
- DCHECK_EQ(this, v8_data->process_data());
- DCHECK(!v8_data->IsTracked());
- v8_context_datas_.Append(v8_data);
- counts_.IncrementV8ContextDataCount();
- }
- void ProcessData::Remove(base::PassKey<V8ContextTrackerDataStore>,
- ExecutionContextData* ec_data) {
- DCHECK(ec_data);
- DCHECK_EQ(this, ec_data->process_data());
- DCHECK(ec_data->IsTracked());
- DCHECK(ec_data->ShouldDestroy());
- counts_.DecrementExecutionContextDataCount(ec_data->destroyed);
- ec_data->RemoveFromList();
- }
- void ProcessData::Remove(base::PassKey<V8ContextTrackerDataStore>,
- RemoteFrameData* rf_data) {
- DCHECK(rf_data);
- DCHECK_EQ(this, rf_data->process_data());
- DCHECK(rf_data->IsTracked());
- rf_data->RemoveFromList();
- }
- void ProcessData::Remove(base::PassKey<V8ContextTrackerDataStore>,
- V8ContextData* v8_data) {
- DCHECK(v8_data);
- DCHECK_EQ(this, v8_data->process_data());
- DCHECK(v8_data->IsTracked());
- counts_.DecrementV8ContextDataCount(v8_data->detached);
- v8_data->RemoveFromList();
- }
- bool ProcessData::MarkDestroyed(base::PassKey<V8ContextTrackerDataStore>,
- ExecutionContextData* ec_data) {
- bool result = ec_data->MarkDestroyed(PassKey());
- if (result)
- counts_.MarkExecutionContextDataDestroyed();
- return result;
- }
- bool ProcessData::MarkDetached(base::PassKey<V8ContextTrackerDataStore>,
- V8ContextData* v8_data) {
- bool result = v8_data->MarkDetached(PassKey());
- if (result)
- counts_.MarkV8ContextDataDetached();
- return result;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // V8ContextTrackerDataStore implementation:
- V8ContextTrackerDataStore::V8ContextTrackerDataStore() = default;
- V8ContextTrackerDataStore::~V8ContextTrackerDataStore() {
- DCHECK(global_execution_context_datas_.empty());
- DCHECK(global_remote_frame_datas_.empty());
- DCHECK(global_v8_context_datas_.empty());
- }
- void V8ContextTrackerDataStore::Pass(
- std::unique_ptr<ExecutionContextData> ec_data) {
- DCHECK(ec_data.get());
- ec_data->process_data()->Add(PassKey(), ec_data.get());
- auto result = global_execution_context_datas_.insert(std::move(ec_data));
- DCHECK(result.second);
- }
- void V8ContextTrackerDataStore::Pass(std::unique_ptr<RemoteFrameData> rf_data) {
- DCHECK(rf_data.get());
- rf_data->process_data()->Add(PassKey(), rf_data.get());
- auto result = global_remote_frame_datas_.insert(std::move(rf_data));
- DCHECK(result.second);
- }
- bool V8ContextTrackerDataStore::Pass(std::unique_ptr<V8ContextData> v8_data) {
- DCHECK(v8_data.get());
- auto* ec_data = v8_data->GetExecutionContextData();
- if (ec_data && v8_data->IsMainV8Context()) {
- if (!ec_data->MarkMainV8ContextCreated(PassKey()))
- return false;
- }
- v8_data->process_data()->Add(PassKey(), v8_data.get());
- v8_data->SetWasTracked(PassKey());
- auto result = global_v8_context_datas_.insert(std::move(v8_data));
- DCHECK(result.second);
- return true;
- }
- ExecutionContextData* V8ContextTrackerDataStore::Get(
- const blink::ExecutionContextToken& token) {
- auto it = global_execution_context_datas_.find(token);
- if (it == global_execution_context_datas_.end())
- return nullptr;
- return it->get();
- }
- RemoteFrameData* V8ContextTrackerDataStore::Get(
- const blink::RemoteFrameToken& token) {
- auto it = global_remote_frame_datas_.find(token);
- if (it == global_remote_frame_datas_.end())
- return nullptr;
- return it->get();
- }
- V8ContextData* V8ContextTrackerDataStore::Get(
- const blink::V8ContextToken& token) {
- auto it = global_v8_context_datas_.find(token);
- if (it == global_v8_context_datas_.end())
- return nullptr;
- return it->get();
- }
- void V8ContextTrackerDataStore::MarkDestroyed(ExecutionContextData* ec_data) {
- DCHECK(ec_data);
- if (ec_data->process_data()->MarkDestroyed(PassKey(), ec_data)) {
- DCHECK_LT(destroyed_execution_context_count_,
- global_execution_context_datas_.size());
- ++destroyed_execution_context_count_;
- }
- }
- bool V8ContextTrackerDataStore::MarkDetached(V8ContextData* v8_data) {
- DCHECK(v8_data);
- if (v8_data->process_data()->MarkDetached(PassKey(), v8_data)) {
- DCHECK_LT(detached_v8_context_count_, global_v8_context_datas_.size());
- ++detached_v8_context_count_;
- return true;
- }
- return false;
- }
- void V8ContextTrackerDataStore::Destroy(
- const blink::ExecutionContextToken& token) {
- auto it = global_execution_context_datas_.find(token);
- DCHECK(it != global_execution_context_datas_.end());
- auto* ec_data = it->get();
- if (ec_data->destroyed) {
- DCHECK_LT(0u, destroyed_execution_context_count_);
- --destroyed_execution_context_count_;
- } else {
- DCHECK_LT(destroyed_execution_context_count_,
- global_execution_context_datas_.size());
- }
- ec_data->process_data()->Remove(PassKey(), ec_data);
- global_execution_context_datas_.erase(it);
- }
- void V8ContextTrackerDataStore::Destroy(const blink::RemoteFrameToken& token) {
- auto it = global_remote_frame_datas_.find(token);
- DCHECK(it != global_remote_frame_datas_.end());
- auto* rf_data = it->get();
- rf_data->process_data()->Remove(PassKey(), rf_data);
- global_remote_frame_datas_.erase(it);
- }
- void V8ContextTrackerDataStore::Destroy(const blink::V8ContextToken& token) {
- auto it = global_v8_context_datas_.find(token);
- DCHECK(it != global_v8_context_datas_.end());
- auto* v8_data = it->get();
- if (v8_data->detached) {
- DCHECK_LT(0u, detached_v8_context_count_);
- --detached_v8_context_count_;
- } else {
- DCHECK_LT(detached_v8_context_count_, global_v8_context_datas_.size());
- }
- v8_data->process_data()->Remove(PassKey(), v8_data);
- global_v8_context_datas_.erase(it);
- }
- } // namespace internal
- } // namespace v8_memory
- } // namespace performance_manager
|