v8_context_tracker_internal.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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. // Internal data structures used by V8ContextTracker. These are only exposed in
  5. // a header for testing. Everything in this header lives in an "internal"
  6. // namespace so as not to pollute the "v8_memory", which houses the actual
  7. // consumer API.
  8. #ifndef COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_V8_CONTEXT_TRACKER_INTERNAL_H_
  9. #define COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_V8_CONTEXT_TRACKER_INTERNAL_H_
  10. #include <memory>
  11. #include <set>
  12. #include "base/containers/linked_list.h"
  13. #include "base/memory/raw_ptr.h"
  14. #include "base/types/pass_key.h"
  15. #include "components/performance_manager/graph/node_attached_data_impl.h"
  16. #include "components/performance_manager/graph/process_node_impl.h"
  17. #include "components/performance_manager/public/mojom/v8_contexts.mojom.h"
  18. #include "components/performance_manager/v8_memory/v8_context_tracker.h"
  19. #include "components/performance_manager/v8_memory/v8_context_tracker_helpers.h"
  20. #include "third_party/blink/public/common/tokens/tokens.h"
  21. namespace performance_manager {
  22. namespace v8_memory {
  23. namespace internal {
  24. using ExecutionContextState = V8ContextTracker::ExecutionContextState;
  25. using V8ContextState = V8ContextTracker::V8ContextState;
  26. // Forward declarations.
  27. class ExecutionContextData;
  28. class ProcessData;
  29. class RemoteFrameData;
  30. class V8ContextData;
  31. class V8ContextTrackerDataStore;
  32. // A comparator for "Data" objects that compares by token.
  33. template <typename DataType, typename TokenType>
  34. struct TokenComparator {
  35. using is_transparent = int;
  36. static const TokenType& GetToken(const TokenType& token) { return token; }
  37. static const TokenType& GetToken(const std::unique_ptr<DataType>& data) {
  38. return data->GetToken();
  39. }
  40. template <typename Type1, typename Type2>
  41. bool operator()(const Type1& obj1, const Type2& obj2) const {
  42. return GetToken(obj1) < GetToken(obj2);
  43. }
  44. };
  45. ////////////////////////////////////////////////////////////////////////////////
  46. // ExecutionContextData declaration:
  47. // Internal wrapper of ExecutionContextState. Augments with additional data
  48. // needed for the implementation. Since these objects also need to be tracked
  49. // per-process, they are kept in a process-associated doubly-linked list.
  50. class ExecutionContextData : public base::LinkNode<ExecutionContextData>,
  51. public ExecutionContextState {
  52. public:
  53. using Comparator =
  54. TokenComparator<ExecutionContextData, blink::ExecutionContextToken>;
  55. ExecutionContextData() = delete;
  56. ExecutionContextData(const ExecutionContextData&) = delete;
  57. ExecutionContextData(ProcessData* process_data,
  58. const blink::ExecutionContextToken& token,
  59. mojom::IframeAttributionDataPtr iframe_attribution_data);
  60. ExecutionContextData& operator=(const ExecutionContextData&) = delete;
  61. ~ExecutionContextData() override;
  62. // Simple accessors.
  63. ProcessData* process_data() const { return process_data_; }
  64. RemoteFrameData* remote_frame_data() { return remote_frame_data_; }
  65. size_t v8_context_count() const { return v8_context_count_; }
  66. size_t main_nondetached_v8_context_count() const {
  67. return main_nondetached_v8_context_count_;
  68. }
  69. // For consistency, all Data objects have a GetToken() function.
  70. const blink::ExecutionContextToken& GetToken() const { return token; }
  71. // Returns true if this object is currently being tracked (it is in
  72. // ProcessData::execution_context_datas_, and
  73. // V8ContextTrackerDataStore::global_execution_context_datas_).
  74. [[nodiscard]] bool IsTracked() const;
  75. // Returns true if this object *should* be destroyed (there are no references
  76. // to it keeping it alive).
  77. [[nodiscard]] bool ShouldDestroy() const;
  78. // Manages remote frame data associated with this ExecutionContextData.
  79. void SetRemoteFrameData(base::PassKey<RemoteFrameData>,
  80. RemoteFrameData* remote_frame_data);
  81. [[nodiscard]] bool ClearRemoteFrameData(base::PassKey<RemoteFrameData>);
  82. // Increments |v8_context_count_|.
  83. void IncrementV8ContextCount(base::PassKey<V8ContextData>);
  84. // Decrements |v8_context_count_|, and returns true if the object has
  85. // transitioned to "ShouldDestroy".
  86. [[nodiscard]] bool DecrementV8ContextCount(base::PassKey<V8ContextData>);
  87. // Marks this context as destroyed. Returns true if the state changed, false
  88. // if it was already destroyed.
  89. [[nodiscard]] bool MarkDestroyed(base::PassKey<ProcessData>);
  90. // Used for tracking the total number of non-detached "main" V8Contexts
  91. // associated with this ExecutionContext. This should always be no more than
  92. // 1. A new context may become the main context during a same-document
  93. // navigation of a frame.
  94. [[nodiscard]] bool MarkMainV8ContextCreated(
  95. base::PassKey<V8ContextTrackerDataStore>);
  96. void MarkMainV8ContextDetached(base::PassKey<V8ContextData>);
  97. private:
  98. const raw_ptr<ProcessData> process_data_;
  99. raw_ptr<RemoteFrameData> remote_frame_data_ = nullptr;
  100. // The count of V8ContextDatas keeping this object alive.
  101. size_t v8_context_count_ = 0;
  102. // The number of non-detached main worlds that are currently associated with
  103. // this ExecutionContext. There can be no more than 1 of these. Once
  104. // document and frame lifetime semantics have been cleaned up, there will only
  105. // be a single main context per ExecutionContext over its lifetime; right now
  106. // there can be multiple due to same-document navigations.
  107. size_t main_nondetached_v8_context_count_ = 0;
  108. };
  109. ////////////////////////////////////////////////////////////////////////////////
  110. // RemoteFrameData declaration:
  111. // Represents data about an ExecutionCOntext from the point of view of the
  112. // parent frame that owns it.
  113. class RemoteFrameData : public base::LinkNode<RemoteFrameData> {
  114. public:
  115. using Comparator = TokenComparator<RemoteFrameData, blink::RemoteFrameToken>;
  116. using PassKey = base::PassKey<RemoteFrameData>;
  117. RemoteFrameData() = delete;
  118. RemoteFrameData(ProcessData* process_data,
  119. const blink::RemoteFrameToken& token,
  120. ExecutionContextData* execution_context_data);
  121. RemoteFrameData(const RemoteFrameData&) = delete;
  122. RemoteFrameData& operator=(const RemoteFrameData&) = delete;
  123. ~RemoteFrameData();
  124. // Simple accessors.
  125. ProcessData* process_data() const { return process_data_; }
  126. ExecutionContextData* execution_context_data() const {
  127. return execution_context_data_;
  128. }
  129. // For consistency, all Data objects have a GetToken() function.
  130. const blink::RemoteFrameToken& GetToken() const { return token_; }
  131. // Returns true if this object is currently being tracked (it is in
  132. // ProcessData::remote_frame_datas_, and
  133. // V8ContextTrackerDataStore::global_remote_frame_datas_).
  134. [[nodiscard]] bool IsTracked() const;
  135. private:
  136. const raw_ptr<ProcessData> process_data_;
  137. const blink::RemoteFrameToken token_;
  138. raw_ptr<ExecutionContextData> execution_context_data_;
  139. };
  140. ////////////////////////////////////////////////////////////////////////////////
  141. // V8ContextData declaration:
  142. // Internal wrapper of V8ContextState. Augments with additional data needed for
  143. // the implementation.
  144. class V8ContextData : public base::LinkNode<V8ContextData>,
  145. public V8ContextState {
  146. public:
  147. using Comparator = TokenComparator<V8ContextData, blink::V8ContextToken>;
  148. using PassKey = base::PassKey<V8ContextData>;
  149. V8ContextData() = delete;
  150. V8ContextData(ProcessData* process_data,
  151. const mojom::V8ContextDescription& description,
  152. ExecutionContextData* execution_context_data);
  153. V8ContextData(const V8ContextData&) = delete;
  154. V8ContextData& operator=(const V8ContextData&) = delete;
  155. ~V8ContextData() override;
  156. // Simple accessors.
  157. ProcessData* process_data() const { return process_data_; }
  158. // For consistency, all Data objects have a GetToken() function.
  159. const blink::V8ContextToken& GetToken() const { return description.token; }
  160. // Returns true if this object is currently being tracked (its in
  161. // ProcessData::v8_context_datas_, and
  162. // V8ContextTrackerDataStore::global_v8_context_datas_).
  163. [[nodiscard]] bool IsTracked() const;
  164. // Returns the ExecutionContextData associated with this V8ContextData.
  165. ExecutionContextData* GetExecutionContextData() const;
  166. // Marks this context as having been successfully passed into the data store.
  167. void SetWasTracked(base::PassKey<V8ContextTrackerDataStore>);
  168. // Marks this context as detached. Returns true if the state changed, false
  169. // if it was already detached.
  170. [[nodiscard]] bool MarkDetached(base::PassKey<ProcessData>);
  171. // Returns true if this is the "main" V8Context for an ExecutionContext.
  172. // This will return true if |GetExecutionContextData()| is a frame and
  173. // |description.world_type| is kMain, or if |GetExecutionContextData()| is a
  174. // worker and |description.world_type| is a kWorkerOrWorklet.
  175. bool IsMainV8Context() const;
  176. private:
  177. bool MarkDetachedImpl();
  178. const raw_ptr<ProcessData> process_data_;
  179. bool was_tracked_ = false;
  180. };
  181. ////////////////////////////////////////////////////////////////////////////////
  182. // ProcessData declaration:
  183. class ProcessData : public NodeAttachedDataImpl<ProcessData> {
  184. public:
  185. struct Traits : public NodeAttachedDataInMap<ProcessNodeImpl> {};
  186. using PassKey = base::PassKey<ProcessData>;
  187. explicit ProcessData(const ProcessNodeImpl* process_node);
  188. ~ProcessData() override;
  189. // Simple accessors.
  190. V8ContextTrackerDataStore* data_store() const { return data_store_; }
  191. // Tears down this ProcessData by ensuring that all associated
  192. // ExecutionContextDatas and V8ContextDatas are cleaned up. This must be
  193. // called *prior* to the destructor being invoked.
  194. void TearDown();
  195. // Adds the provided object to the list of process-associated objects. The
  196. // object must not be part of a list, its process data must match this one,
  197. // and it must return false for "ShouldDestroy" (if applicable). For removal,
  198. // the object must be part of a list, the process data must match this one and
  199. // "ShouldDestroy" must return false.
  200. void Add(base::PassKey<V8ContextTrackerDataStore>,
  201. ExecutionContextData* ec_data);
  202. void Add(base::PassKey<V8ContextTrackerDataStore>, RemoteFrameData* rf_data);
  203. void Add(base::PassKey<V8ContextTrackerDataStore>, V8ContextData* v8_data);
  204. void Remove(base::PassKey<V8ContextTrackerDataStore>,
  205. ExecutionContextData* ec_data);
  206. void Remove(base::PassKey<V8ContextTrackerDataStore>,
  207. RemoteFrameData* rf_data);
  208. void Remove(base::PassKey<V8ContextTrackerDataStore>, V8ContextData* v8_data);
  209. // For marking objects detached/destroyed. Returns true if the state
  210. // actually changed, false otherwise.
  211. [[nodiscard]] bool MarkDestroyed(base::PassKey<V8ContextTrackerDataStore>,
  212. ExecutionContextData* ec_data);
  213. [[nodiscard]] bool MarkDetached(base::PassKey<V8ContextTrackerDataStore>,
  214. V8ContextData* v8_data);
  215. size_t GetExecutionContextDataCount() const {
  216. return counts_.GetExecutionContextDataCount();
  217. }
  218. size_t GetDestroyedExecutionContextDataCount() const {
  219. return counts_.GetDestroyedExecutionContextDataCount();
  220. }
  221. size_t GetV8ContextDataCount() const {
  222. return counts_.GetV8ContextDataCount();
  223. }
  224. size_t GetDetachedV8ContextDataCount() const {
  225. return counts_.GetDetachedV8ContextDataCount();
  226. }
  227. private:
  228. // Used to initialize |data_store_| at construction.
  229. static V8ContextTrackerDataStore* GetDataStore(
  230. const ProcessNodeImpl* process_node) {
  231. return V8ContextTracker::GetFromGraph(process_node->graph())->data_store();
  232. }
  233. // Pointer to the DataStore that implicitly owns us.
  234. const raw_ptr<V8ContextTrackerDataStore> data_store_;
  235. // Counts the number of ExecutionContexts and V8Contexts.
  236. ContextCounts counts_;
  237. // List of ExecutionContextDatas associated with this process.
  238. base::LinkedList<ExecutionContextData> execution_context_datas_;
  239. // List of RemoteFrameDatas associated with this process.
  240. base::LinkedList<RemoteFrameData> remote_frame_datas_;
  241. // List of V8ContextDatas associated with this process.
  242. base::LinkedList<V8ContextData> v8_context_datas_;
  243. };
  244. ////////////////////////////////////////////////////////////////////////////////
  245. // V8ContextTrackerDataStore declaration:
  246. // This class acts as the owner of all tracked objects. Objects are created
  247. // in isolation, and ownership passed to this object. Management of all
  248. // per-process lists is centralized through this object.
  249. class V8ContextTrackerDataStore {
  250. public:
  251. using PassKey = base::PassKey<V8ContextTrackerDataStore>;
  252. V8ContextTrackerDataStore();
  253. ~V8ContextTrackerDataStore();
  254. // Passes ownership of an object. An object with the same token must not
  255. // already exist ("Get" should return nullptr). Note that when passing an
  256. // |ec_data| to the impl that "ShouldDestroy" should return false.
  257. void Pass(std::unique_ptr<ExecutionContextData> ec_data);
  258. void Pass(std::unique_ptr<RemoteFrameData> rf_data);
  259. [[nodiscard]] bool Pass(std::unique_ptr<V8ContextData> v8_data);
  260. // Looks up owned objects by token.
  261. ExecutionContextData* Get(const blink::ExecutionContextToken& token);
  262. RemoteFrameData* Get(const blink::RemoteFrameToken& token);
  263. V8ContextData* Get(const blink::V8ContextToken& token);
  264. // For marking objects as detached/destroyed. "MarkDetached" returns true if
  265. // the object was not previously detached, false otherwise.
  266. void MarkDestroyed(ExecutionContextData* ec_data);
  267. [[nodiscard]] bool MarkDetached(V8ContextData* v8_data);
  268. // Destroys objects by token. They must exist ("Get" should return non
  269. // nullptr).
  270. void Destroy(const blink::ExecutionContextToken& token);
  271. void Destroy(const blink::RemoteFrameToken& token);
  272. void Destroy(const blink::V8ContextToken& token);
  273. size_t GetDestroyedExecutionContextDataCount() const {
  274. return destroyed_execution_context_count_;
  275. }
  276. size_t GetDetachedV8ContextDataCount() const {
  277. return detached_v8_context_count_;
  278. }
  279. size_t GetExecutionContextDataCount() const {
  280. return global_execution_context_datas_.size();
  281. }
  282. size_t GetRemoteFrameDataCount() const {
  283. return global_remote_frame_datas_.size();
  284. }
  285. size_t GetV8ContextDataCount() const {
  286. return global_v8_context_datas_.size();
  287. }
  288. private:
  289. size_t destroyed_execution_context_count_ = 0;
  290. size_t detached_v8_context_count_ = 0;
  291. // Browser wide registry of ExecutionContextData objects.
  292. std::set<std::unique_ptr<ExecutionContextData>,
  293. ExecutionContextData::Comparator>
  294. global_execution_context_datas_;
  295. // Browser-wide registry of RemoteFrameData objects.
  296. std::set<std::unique_ptr<RemoteFrameData>, RemoteFrameData::Comparator>
  297. global_remote_frame_datas_;
  298. // Browser wide registry of V8ContextData objects.
  299. std::set<std::unique_ptr<V8ContextData>, V8ContextData::Comparator>
  300. global_v8_context_datas_;
  301. };
  302. } // namespace internal
  303. } // namespace v8_memory
  304. } // namespace performance_manager
  305. #endif // COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_V8_CONTEXT_TRACKER_INTERNAL_H_