v8_context_tracker_internal.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/performance_manager/v8_memory/v8_context_tracker_internal.h"
  5. #include <utility>
  6. #include "base/check.h"
  7. #include "components/performance_manager/v8_memory/v8_context_tracker_helpers.h"
  8. namespace performance_manager {
  9. namespace v8_memory {
  10. namespace internal {
  11. ////////////////////////////////////////////////////////////////////////////////
  12. // ExecutionContextData implementation:
  13. ExecutionContextData::ExecutionContextData(
  14. ProcessData* process_data,
  15. const blink::ExecutionContextToken& token,
  16. mojom::IframeAttributionDataPtr iframe_attribution_data)
  17. : ExecutionContextState(token, std::move(iframe_attribution_data)),
  18. process_data_(process_data) {}
  19. ExecutionContextData::~ExecutionContextData() {
  20. DCHECK(!IsTracked());
  21. DCHECK(ShouldDestroy());
  22. DCHECK_EQ(0u, main_nondetached_v8_context_count_);
  23. }
  24. bool ExecutionContextData::IsTracked() const {
  25. return previous() || next();
  26. }
  27. bool ExecutionContextData::ShouldDestroy() const {
  28. return v8_context_count_ == 0 && !remote_frame_data_;
  29. }
  30. void ExecutionContextData::SetRemoteFrameData(
  31. base::PassKey<RemoteFrameData>,
  32. RemoteFrameData* remote_frame_data) {
  33. DCHECK(!remote_frame_data_);
  34. DCHECK(remote_frame_data);
  35. remote_frame_data_ = remote_frame_data;
  36. }
  37. bool ExecutionContextData::ClearRemoteFrameData(
  38. base::PassKey<RemoteFrameData>) {
  39. DCHECK(remote_frame_data_);
  40. remote_frame_data_ = nullptr;
  41. return ShouldDestroy();
  42. }
  43. void ExecutionContextData::IncrementV8ContextCount(
  44. base::PassKey<V8ContextData>) {
  45. ++v8_context_count_;
  46. }
  47. bool ExecutionContextData::DecrementV8ContextCount(
  48. base::PassKey<V8ContextData>) {
  49. DCHECK_LT(0u, v8_context_count_);
  50. DCHECK_LT(main_nondetached_v8_context_count_, v8_context_count_);
  51. --v8_context_count_;
  52. return ShouldDestroy();
  53. }
  54. bool ExecutionContextData::MarkDestroyed(base::PassKey<ProcessData>) {
  55. if (destroyed)
  56. return false;
  57. destroyed = true;
  58. return true;
  59. }
  60. bool ExecutionContextData::MarkMainV8ContextCreated(
  61. base::PassKey<V8ContextTrackerDataStore>) {
  62. if (main_nondetached_v8_context_count_ >= v8_context_count_)
  63. return false;
  64. if (main_nondetached_v8_context_count_ >= 1)
  65. return false;
  66. ++main_nondetached_v8_context_count_;
  67. return true;
  68. }
  69. void ExecutionContextData::MarkMainV8ContextDetached(
  70. base::PassKey<V8ContextData>) {
  71. DCHECK_LT(0u, main_nondetached_v8_context_count_);
  72. --main_nondetached_v8_context_count_;
  73. }
  74. ////////////////////////////////////////////////////////////////////////////////
  75. // RemoteFrameData implementation:
  76. RemoteFrameData::RemoteFrameData(ProcessData* process_data,
  77. const blink::RemoteFrameToken& token,
  78. ExecutionContextData* execution_context_data)
  79. : process_data_(process_data),
  80. token_(token),
  81. execution_context_data_(execution_context_data) {
  82. DCHECK(process_data);
  83. DCHECK(execution_context_data);
  84. execution_context_data->SetRemoteFrameData(PassKey(), this);
  85. }
  86. RemoteFrameData::~RemoteFrameData() {
  87. DCHECK(!IsTracked());
  88. // If this is the last reference keeping alive a tracked ExecutionContextData,
  89. // then clean it up as well. Untracked ExecutionContextDatas will go out of
  90. // scope on their own.
  91. if (execution_context_data_->ClearRemoteFrameData(PassKey()) &&
  92. execution_context_data_->IsTracked()) {
  93. // Reset `execution_context_data_` to nullptr because it will be destroyed
  94. // using the token below.
  95. blink::ExecutionContextToken token = execution_context_data_->GetToken();
  96. execution_context_data_ = nullptr;
  97. process_data_->data_store()->Destroy(token);
  98. }
  99. }
  100. bool RemoteFrameData::IsTracked() const {
  101. return previous() || next();
  102. }
  103. ////////////////////////////////////////////////////////////////////////////////
  104. // V8ContextData implementation:
  105. V8ContextData::V8ContextData(ProcessData* process_data,
  106. const mojom::V8ContextDescription& description,
  107. ExecutionContextData* execution_context_data)
  108. : V8ContextState(description, execution_context_data),
  109. process_data_(process_data) {
  110. DCHECK(process_data);
  111. DCHECK_EQ(static_cast<bool>(execution_context_data),
  112. static_cast<bool>(description.execution_context_token));
  113. if (execution_context_data) {
  114. DCHECK_EQ(execution_context_data->GetToken(),
  115. description.execution_context_token.value());
  116. // These must be same process.
  117. DCHECK_EQ(process_data, execution_context_data->process_data());
  118. execution_context_data->IncrementV8ContextCount(PassKey());
  119. }
  120. }
  121. V8ContextData::~V8ContextData() {
  122. DCHECK(!IsTracked());
  123. // Mark as detached if necessary so that main world counts are appropriately
  124. // updated even during tear down code paths.
  125. MarkDetachedImpl();
  126. // If this is the last reference keeping alive a tracked ExecutionContextData,
  127. // then clean it up as well. Untracked ExecutionContextDatas will go out of
  128. // scope on their own.
  129. auto* execution_context_data = GetExecutionContextData();
  130. if (execution_context_data &&
  131. execution_context_data->DecrementV8ContextCount(PassKey()) &&
  132. execution_context_data->IsTracked()) {
  133. // Reset the execution_context_state to nullptr because it will be
  134. // destroyed using the token below.
  135. blink::ExecutionContextToken token = execution_context_data->GetToken();
  136. execution_context_state = nullptr;
  137. process_data_->data_store()->Destroy(token);
  138. }
  139. }
  140. bool V8ContextData::IsTracked() const {
  141. return previous() || next();
  142. }
  143. ExecutionContextData* V8ContextData::GetExecutionContextData() const {
  144. return static_cast<ExecutionContextData*>(execution_context_state);
  145. }
  146. void V8ContextData::SetWasTracked(base::PassKey<V8ContextTrackerDataStore>) {
  147. DCHECK(!was_tracked_);
  148. was_tracked_ = true;
  149. }
  150. bool V8ContextData::MarkDetached(base::PassKey<ProcessData>) {
  151. return MarkDetachedImpl();
  152. }
  153. bool V8ContextData::IsMainV8Context() const {
  154. auto* ec_data = GetExecutionContextData();
  155. if (!ec_data)
  156. return false;
  157. // ExecutionContexts hosting worklets have no main world (there can be many
  158. // worklets sharing an ExecutionContext).
  159. if (IsWorkletToken(ec_data->GetToken()))
  160. return false;
  161. // We've already checked sane combinations of ExecutionContextToken types and
  162. // world types in ValidateV8ContextDescription, so don't need to be overly
  163. // thorough here.
  164. // Only main frames and workers can be "main" contexts.
  165. auto world_type = description.world_type;
  166. return world_type == mojom::V8ContextWorldType::kMain ||
  167. world_type == mojom::V8ContextWorldType::kWorkerOrWorklet;
  168. }
  169. bool V8ContextData::MarkDetachedImpl() {
  170. if (detached)
  171. return false;
  172. detached = true;
  173. // The EC is notified of the main V8 context only when it is passed to the
  174. // data store (at which point |was_tracked_| is set to true). Only do the
  175. // symmetric operation if the first occurred.
  176. if (IsMainV8Context() && was_tracked_) {
  177. if (auto* ec_data = GetExecutionContextData())
  178. ec_data->MarkMainV8ContextDetached(PassKey());
  179. }
  180. return true;
  181. }
  182. ////////////////////////////////////////////////////////////////////////////////
  183. // ProcessData implementation:
  184. ProcessData::ProcessData(const ProcessNodeImpl* process_node)
  185. : data_store_(GetDataStore(process_node)) {}
  186. ProcessData::~ProcessData() {
  187. DCHECK(execution_context_datas_.empty());
  188. DCHECK(remote_frame_datas_.empty());
  189. DCHECK(v8_context_datas_.empty());
  190. }
  191. void ProcessData::TearDown() {
  192. // First, remove any RemoteFrameData references owned by this ProcessData
  193. // that are keeping alive ExecutionContextDatas in other ProcessDatas. This
  194. // can cause ExecutionContextDatas to be torn down.
  195. while (!remote_frame_datas_.empty()) {
  196. auto* node = remote_frame_datas_.head();
  197. data_store_->Destroy(node->value()->GetToken());
  198. }
  199. // Drain the list of V8ContextTokens. This will also indirectly clean up and
  200. // ExecutionContextDatas that are only being kept alive by V8ContextData
  201. // references.
  202. while (!v8_context_datas_.empty()) {
  203. auto* node = v8_context_datas_.head();
  204. data_store_->Destroy(node->value()->GetToken());
  205. }
  206. // Any ExecutionContextDatas still alive are only being kept alive because of
  207. // RemoteFrameData references from another ProcessData. Clean those up.
  208. while (!execution_context_datas_.empty()) {
  209. auto* node = execution_context_datas_.head();
  210. auto* ec_data = node->value();
  211. auto* rfd = ec_data->remote_frame_data();
  212. DCHECK(rfd);
  213. DCHECK_EQ(0u, ec_data->v8_context_count());
  214. data_store_->Destroy(rfd->GetToken());
  215. }
  216. // We now expect everything to have been cleaned up.
  217. DCHECK(execution_context_datas_.empty());
  218. DCHECK(remote_frame_datas_.empty());
  219. DCHECK(v8_context_datas_.empty());
  220. }
  221. void ProcessData::Add(base::PassKey<V8ContextTrackerDataStore>,
  222. ExecutionContextData* ec_data) {
  223. DCHECK(ec_data);
  224. DCHECK_EQ(this, ec_data->process_data());
  225. DCHECK(!ec_data->ShouldDestroy());
  226. DCHECK(!ec_data->IsTracked());
  227. execution_context_datas_.Append(ec_data);
  228. counts_.IncrementExecutionContextDataCount();
  229. }
  230. void ProcessData::Add(base::PassKey<V8ContextTrackerDataStore>,
  231. RemoteFrameData* rf_data) {
  232. DCHECK(rf_data);
  233. DCHECK_EQ(this, rf_data->process_data());
  234. DCHECK(!rf_data->IsTracked());
  235. remote_frame_datas_.Append(rf_data);
  236. }
  237. void ProcessData::Add(base::PassKey<V8ContextTrackerDataStore>,
  238. V8ContextData* v8_data) {
  239. DCHECK(v8_data);
  240. DCHECK_EQ(this, v8_data->process_data());
  241. DCHECK(!v8_data->IsTracked());
  242. v8_context_datas_.Append(v8_data);
  243. counts_.IncrementV8ContextDataCount();
  244. }
  245. void ProcessData::Remove(base::PassKey<V8ContextTrackerDataStore>,
  246. ExecutionContextData* ec_data) {
  247. DCHECK(ec_data);
  248. DCHECK_EQ(this, ec_data->process_data());
  249. DCHECK(ec_data->IsTracked());
  250. DCHECK(ec_data->ShouldDestroy());
  251. counts_.DecrementExecutionContextDataCount(ec_data->destroyed);
  252. ec_data->RemoveFromList();
  253. }
  254. void ProcessData::Remove(base::PassKey<V8ContextTrackerDataStore>,
  255. RemoteFrameData* rf_data) {
  256. DCHECK(rf_data);
  257. DCHECK_EQ(this, rf_data->process_data());
  258. DCHECK(rf_data->IsTracked());
  259. rf_data->RemoveFromList();
  260. }
  261. void ProcessData::Remove(base::PassKey<V8ContextTrackerDataStore>,
  262. V8ContextData* v8_data) {
  263. DCHECK(v8_data);
  264. DCHECK_EQ(this, v8_data->process_data());
  265. DCHECK(v8_data->IsTracked());
  266. counts_.DecrementV8ContextDataCount(v8_data->detached);
  267. v8_data->RemoveFromList();
  268. }
  269. bool ProcessData::MarkDestroyed(base::PassKey<V8ContextTrackerDataStore>,
  270. ExecutionContextData* ec_data) {
  271. bool result = ec_data->MarkDestroyed(PassKey());
  272. if (result)
  273. counts_.MarkExecutionContextDataDestroyed();
  274. return result;
  275. }
  276. bool ProcessData::MarkDetached(base::PassKey<V8ContextTrackerDataStore>,
  277. V8ContextData* v8_data) {
  278. bool result = v8_data->MarkDetached(PassKey());
  279. if (result)
  280. counts_.MarkV8ContextDataDetached();
  281. return result;
  282. }
  283. ////////////////////////////////////////////////////////////////////////////////
  284. // V8ContextTrackerDataStore implementation:
  285. V8ContextTrackerDataStore::V8ContextTrackerDataStore() = default;
  286. V8ContextTrackerDataStore::~V8ContextTrackerDataStore() {
  287. DCHECK(global_execution_context_datas_.empty());
  288. DCHECK(global_remote_frame_datas_.empty());
  289. DCHECK(global_v8_context_datas_.empty());
  290. }
  291. void V8ContextTrackerDataStore::Pass(
  292. std::unique_ptr<ExecutionContextData> ec_data) {
  293. DCHECK(ec_data.get());
  294. ec_data->process_data()->Add(PassKey(), ec_data.get());
  295. auto result = global_execution_context_datas_.insert(std::move(ec_data));
  296. DCHECK(result.second);
  297. }
  298. void V8ContextTrackerDataStore::Pass(std::unique_ptr<RemoteFrameData> rf_data) {
  299. DCHECK(rf_data.get());
  300. rf_data->process_data()->Add(PassKey(), rf_data.get());
  301. auto result = global_remote_frame_datas_.insert(std::move(rf_data));
  302. DCHECK(result.second);
  303. }
  304. bool V8ContextTrackerDataStore::Pass(std::unique_ptr<V8ContextData> v8_data) {
  305. DCHECK(v8_data.get());
  306. auto* ec_data = v8_data->GetExecutionContextData();
  307. if (ec_data && v8_data->IsMainV8Context()) {
  308. if (!ec_data->MarkMainV8ContextCreated(PassKey()))
  309. return false;
  310. }
  311. v8_data->process_data()->Add(PassKey(), v8_data.get());
  312. v8_data->SetWasTracked(PassKey());
  313. auto result = global_v8_context_datas_.insert(std::move(v8_data));
  314. DCHECK(result.second);
  315. return true;
  316. }
  317. ExecutionContextData* V8ContextTrackerDataStore::Get(
  318. const blink::ExecutionContextToken& token) {
  319. auto it = global_execution_context_datas_.find(token);
  320. if (it == global_execution_context_datas_.end())
  321. return nullptr;
  322. return it->get();
  323. }
  324. RemoteFrameData* V8ContextTrackerDataStore::Get(
  325. const blink::RemoteFrameToken& token) {
  326. auto it = global_remote_frame_datas_.find(token);
  327. if (it == global_remote_frame_datas_.end())
  328. return nullptr;
  329. return it->get();
  330. }
  331. V8ContextData* V8ContextTrackerDataStore::Get(
  332. const blink::V8ContextToken& token) {
  333. auto it = global_v8_context_datas_.find(token);
  334. if (it == global_v8_context_datas_.end())
  335. return nullptr;
  336. return it->get();
  337. }
  338. void V8ContextTrackerDataStore::MarkDestroyed(ExecutionContextData* ec_data) {
  339. DCHECK(ec_data);
  340. if (ec_data->process_data()->MarkDestroyed(PassKey(), ec_data)) {
  341. DCHECK_LT(destroyed_execution_context_count_,
  342. global_execution_context_datas_.size());
  343. ++destroyed_execution_context_count_;
  344. }
  345. }
  346. bool V8ContextTrackerDataStore::MarkDetached(V8ContextData* v8_data) {
  347. DCHECK(v8_data);
  348. if (v8_data->process_data()->MarkDetached(PassKey(), v8_data)) {
  349. DCHECK_LT(detached_v8_context_count_, global_v8_context_datas_.size());
  350. ++detached_v8_context_count_;
  351. return true;
  352. }
  353. return false;
  354. }
  355. void V8ContextTrackerDataStore::Destroy(
  356. const blink::ExecutionContextToken& token) {
  357. auto it = global_execution_context_datas_.find(token);
  358. DCHECK(it != global_execution_context_datas_.end());
  359. auto* ec_data = it->get();
  360. if (ec_data->destroyed) {
  361. DCHECK_LT(0u, destroyed_execution_context_count_);
  362. --destroyed_execution_context_count_;
  363. } else {
  364. DCHECK_LT(destroyed_execution_context_count_,
  365. global_execution_context_datas_.size());
  366. }
  367. ec_data->process_data()->Remove(PassKey(), ec_data);
  368. global_execution_context_datas_.erase(it);
  369. }
  370. void V8ContextTrackerDataStore::Destroy(const blink::RemoteFrameToken& token) {
  371. auto it = global_remote_frame_datas_.find(token);
  372. DCHECK(it != global_remote_frame_datas_.end());
  373. auto* rf_data = it->get();
  374. rf_data->process_data()->Remove(PassKey(), rf_data);
  375. global_remote_frame_datas_.erase(it);
  376. }
  377. void V8ContextTrackerDataStore::Destroy(const blink::V8ContextToken& token) {
  378. auto it = global_v8_context_datas_.find(token);
  379. DCHECK(it != global_v8_context_datas_.end());
  380. auto* v8_data = it->get();
  381. if (v8_data->detached) {
  382. DCHECK_LT(0u, detached_v8_context_count_);
  383. --detached_v8_context_count_;
  384. } else {
  385. DCHECK_LT(detached_v8_context_count_, global_v8_context_datas_.size());
  386. }
  387. v8_data->process_data()->Remove(PassKey(), v8_data);
  388. global_v8_context_datas_.erase(it);
  389. }
  390. } // namespace internal
  391. } // namespace v8_memory
  392. } // namespace performance_manager