node_attached_data_impl.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. // Copyright 2019 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. #ifndef COMPONENTS_PERFORMANCE_MANAGER_GRAPH_NODE_ATTACHED_DATA_IMPL_H_
  5. #define COMPONENTS_PERFORMANCE_MANAGER_GRAPH_NODE_ATTACHED_DATA_IMPL_H_
  6. #include <memory>
  7. #include <type_traits>
  8. #include <utility>
  9. #include "base/check_op.h"
  10. #include "base/memory/ptr_util.h"
  11. #include "components/performance_manager/graph/node_attached_data.h"
  12. namespace performance_manager {
  13. // Helper classes for defining a user data class that is associated with nodes
  14. // in the graph. At most one instance of each type of data may exist per node
  15. // in the graph.
  16. //
  17. // An instance of NodeAttachedData has to be specifically permitted to be
  18. // associated with individual node types, with this being enforced at compile
  19. // time via the type system. For each association, exactly one storage type is
  20. // also specified. Storage may be one of the following:
  21. //
  22. // - In a singleton map owned by the graph (easiest, least efficient). This is
  23. // provided by deriving the traits from NodeAttachedDataInMap<>. If the data
  24. // is needed only for some instances of a node type, use this storage.
  25. // - In a std::unique_ptr<NodeAttachedData> owned by the node itself
  26. // (slightly harder, slightly more efficient). The node type need only be
  27. // aware of the NodeAttachedData base class in this case. This is provided by
  28. // deriving the traits from NodeAttachedDataOwnedByNodeType<>. If the data is
  29. // needed for all instances of a node type, but only for a relatively small
  30. // portion of the nodes lifetime, use this storage type.
  31. // - In a raw buffer owned by the node implementation, initialized by the
  32. // data type using a placement new (most difficult to use, but most memory
  33. // efficient). The node type needs to be aware of NodeAttachedData base class
  34. // and the size of the DataType in this case. This is provided by deriving
  35. // the traits from NodeAttachedDataInternalOnNodeType<>. If the data is needed
  36. // for all instances of a node type and for effectively the entire lifetime of
  37. // the node, use this storage type.
  38. //
  39. // These traits are provided by a "Traits" subclass, which is decorated by
  40. // deriving from the appropriate storage type helpers. Keeping the decorations
  41. // on a subclass keeps the data implementation class hierarchy clean, meaning it
  42. // has a predictable size across all platforms and compilers (a single vtable
  43. // entry).
  44. //
  45. // This is intended to be used as follows:
  46. //
  47. // -- foo.h --
  48. // class Foo : public NodeAttachedDataImpl<Foo> {
  49. // public:
  50. // // This class communicates how the data type is allowed to be used in the
  51. // // graph.
  52. // struct Traits
  53. // // Can be associated with page nodes, storage in the map.
  54. // : public NodeAttachedDataInMap<PageNodeImpl>,
  55. // // Can be associated with frame nodes, storage provided by a
  56. // // std::unique_ptr<> member in the FrameNodeImpl.
  57. // public NodeAttachedDataOwnedByNodeType<FrameNodeImpl>,
  58. // // Can be associated with process nodes, storage provided inline
  59. // // in the ProcessNodeImpl.
  60. // public NodeAttachedDataInternalOnNodeType<ProcessNodeImpl> {};
  61. //
  62. // ~Foo() override;
  63. //
  64. // private:
  65. // // Make the impl our friend so it can access the constructor and any
  66. // // storage providers.
  67. // friend class ::performance_manager::NodeAttachedDataImpl<DataType>;
  68. //
  69. // // For each node type that is supported a matching constructor must be
  70. // // available.
  71. // explicit Foo(const PageNodeImpl* page_node);
  72. // explicit Foo(const FrameNodeImpl* frame_node);
  73. // explicit Foo(const ProcessNodeImpl* process_node);
  74. //
  75. // // Provides access to the std::unique_ptr storage in frame nodes.
  76. // // See NodeAttachedDataOwnedByNodeType<>.
  77. // static std::unique_ptr<NodeAttachedData>* GetUniquePtrStorage(
  78. // FrameNodeImpl* frame_node);
  79. //
  80. // // Provides access to the inline storage in process nodes. The "4" must
  81. // // match sizeof(Foo). See NodeAttachedDataInternalOnNodeType<>.
  82. // static InternalNodeAttachedDataStorage<4>* GetInternalStorage(
  83. // ProcessNodeImpl* process_node);
  84. //
  85. // };
  86. // -- foo.h --
  87. //
  88. // Once defined, the class is used the same way, regardless of where the
  89. // storage is implemented. For each bound node type the following functions are
  90. // exposed:
  91. //
  92. // - static Foo* Foo::GetOrCreate(const NodeType* node)
  93. // Creates a Foo associated with |node| if there isn't already one, and
  94. // returns it.
  95. // - static Foo* Foo::Get(const NodeType* node)
  96. // Returns the Foo associated with |node|, which may be nullptr.
  97. // - static bool Foo::Destroy(const NodeType* node)
  98. // Destroys the Foo associated with |node|, if one exists. Returns true if one
  99. // existed, false otherwise.
  100. //
  101. // For example:
  102. //
  103. // -- user_of_foo.cc --
  104. // Foo* foo = Foo::GetOrCreate(page_node);
  105. // foo->DoSomething();
  106. // DCHECK_EQ(foo, Foo::Get(page_node));
  107. // DCHECK(Foo::Destroy(page_node));
  108. // -- user_of_foo.cc --
  109. // Implementation of NodeAttachedData intended to be used as the base class for
  110. // derived types. Provides the basic plumbing for accessing the node attached
  111. // data in a strongly typed manner, while enforcing node type bindings.
  112. template <typename DataType>
  113. class NodeAttachedDataImpl : public NodeAttachedData {
  114. public:
  115. ///////////////////////////////////
  116. // Storage specification classes //
  117. ///////////////////////////////////
  118. // The pointer to this object acts as a unique key that identifies the type
  119. // at runtime. Note that the address of this should be taken only from a
  120. // single library, as a different address will be returned from each library
  121. // into which a given data type is linked.
  122. static constexpr int kUserDataKey = 0;
  123. // A class whose presence in the inheritance hierarchy of the Traits class
  124. // indicates that a NodeAttachedDataImpl is allowed to be attached to the
  125. // given node type, by type or by enum. Used by the storage impl classes.
  126. template <NodeTypeEnum kNodeType>
  127. class NodeAttachedDataPermittedByNodeTypeEnum {};
  128. template <typename NodeType>
  129. class NodeAttachedDataPermittedOnNodeType
  130. : public NodeAttachedDataPermittedByNodeTypeEnum<NodeType::Type()> {
  131. static_assert(std::is_base_of<NodeBase, NodeType>::value &&
  132. !std::is_same<NodeBase, NodeType>::value,
  133. "NodeType must be descended from NodeBase");
  134. };
  135. // The following 3 "mixin" classes are used to enable NodeAttachedData for a
  136. // given node type, and also to provide the storage type for the data. See
  137. // each class for details.
  138. // A "mixin" class that endows a NodeAttachedData implementation with strongly
  139. // typed data accessors for a given node type. This allows a NodeAttachedData
  140. // to be selectively bound only to certain node types. Use this with NodeBase
  141. // if the data can be attached to any graph node type.
  142. template <typename NodeType>
  143. class NodeAttachedDataInMap
  144. : public NodeAttachedDataPermittedOnNodeType<NodeType> {
  145. public:
  146. static DataType* GetOrCreate(const NodeType* node);
  147. static DataType* Get(const NodeType* node);
  148. static bool Destroy(const NodeType* node);
  149. };
  150. // A "mixin" class that endows a NodeAttachedData implementation with strongly
  151. // typed accessors for a given node type, where the storage for the data is
  152. // provided by a std::unique_ptr<NodeAttachedData> owned by the node.
  153. template <typename NodeType>
  154. class NodeAttachedDataOwnedByNodeType
  155. : public NodeAttachedDataPermittedOnNodeType<NodeType> {
  156. public:
  157. static DataType* GetOrCreate(const NodeType* node);
  158. static DataType* Get(const NodeType* node);
  159. static bool Destroy(const NodeType* node);
  160. };
  161. // A "mixin" class that endows a NodeAttachedData implementation with strongly
  162. // typed accessors for a given node type, where the storage for the data is
  163. // provided by an InternalNodeAttachedDataStorage<> on the node.
  164. template <typename NodeType>
  165. class NodeAttachedDataInternalOnNodeType
  166. : public NodeAttachedDataPermittedOnNodeType<NodeType> {
  167. public:
  168. static DataType* GetOrCreate(const NodeType* node);
  169. static DataType* Get(const NodeType* node);
  170. static bool Destroy(const NodeType* node);
  171. };
  172. NodeAttachedDataImpl() = default;
  173. ~NodeAttachedDataImpl() override = default;
  174. static const void* UserDataKey() { return &DataType::kUserDataKey; }
  175. // NodeAttachedData implementation:
  176. const void* GetKey() const override { return UserDataKey(); }
  177. private:
  178. // Uses implicit conversion of the traits to get the appropriate mixin class
  179. // that implements storage for the node type. This is used to provide dispatch
  180. // of GetOrCreate/Get/Destroy base on the storage type.
  181. template <class NodeType>
  182. static const NodeAttachedDataInMap<NodeType>& GetTraits(
  183. NodeAttachedDataInMap<NodeType>& traits) {
  184. return traits;
  185. }
  186. template <class NodeType>
  187. static const NodeAttachedDataOwnedByNodeType<NodeType>& GetTraits(
  188. NodeAttachedDataOwnedByNodeType<NodeType>& traits) {
  189. return traits;
  190. }
  191. template <class NodeType>
  192. static const NodeAttachedDataInternalOnNodeType<NodeType>& GetTraits(
  193. NodeAttachedDataInternalOnNodeType<NodeType>& traits) {
  194. return traits;
  195. }
  196. public:
  197. // Creates (if necessary) and retrieves the data associated with the provided
  198. // node.
  199. template <typename NodeType>
  200. static DataType* GetOrCreate(const NodeType* node) {
  201. typename DataType::Traits traits;
  202. return GetTraits<NodeType>(traits).GetOrCreate(node);
  203. }
  204. // Retrieves the data associated with the provided node if it exists.
  205. template <typename NodeType>
  206. static DataType* Get(const NodeType* node) {
  207. typename DataType::Traits traits;
  208. return GetTraits<NodeType>(traits).Get(node);
  209. }
  210. // Destroys the data associated with the provided node. Returns true data was
  211. // deleted, false otherwise.
  212. template <typename NodeType>
  213. static bool Destroy(const NodeType* node) {
  214. typename DataType::Traits traits;
  215. return GetTraits<NodeType>(traits).Destroy(node);
  216. }
  217. };
  218. // static
  219. template <typename DataType>
  220. constexpr int NodeAttachedDataImpl<DataType>::kUserDataKey;
  221. ///////////////////////////////////////////////////////////
  222. // Everything below this point is implementation detail! //
  223. ///////////////////////////////////////////////////////////
  224. // Helper class allowing access to internals of
  225. // InternalNodeAttachedDataStorage<>.
  226. class InternalNodeAttachedDataStorageAccess {
  227. public:
  228. // InternalNodeAttachedDataStorage<> forwarding.
  229. template <typename InlineStorageType>
  230. static void Set(InlineStorageType* storage, NodeAttachedData* data) {
  231. storage->Set(data);
  232. }
  233. };
  234. // Implementation of storage type mixins.
  235. // Map storage impl.
  236. // static
  237. template <typename DataType>
  238. template <typename NodeType>
  239. DataType*
  240. NodeAttachedDataImpl<DataType>::NodeAttachedDataInMap<NodeType>::GetOrCreate(
  241. const NodeType* node) {
  242. if (auto* data = Get(node))
  243. return data;
  244. std::unique_ptr<DataType> data = base::WrapUnique(new DataType(node));
  245. DataType* raw_data = data.get();
  246. NodeAttachedDataMapHelper::AttachInMap(node, std::move(data));
  247. return raw_data;
  248. }
  249. // static
  250. template <typename DataType>
  251. template <typename NodeType>
  252. DataType* NodeAttachedDataImpl<DataType>::NodeAttachedDataInMap<NodeType>::Get(
  253. const NodeType* node) {
  254. auto* data =
  255. NodeAttachedDataMapHelper::GetFromMap(node, DataType::UserDataKey());
  256. DCHECK(!data || DataType::UserDataKey() == data->GetKey());
  257. return static_cast<DataType*>(data);
  258. }
  259. // static
  260. template <typename DataType>
  261. template <typename NodeType>
  262. bool NodeAttachedDataImpl<DataType>::NodeAttachedDataInMap<NodeType>::Destroy(
  263. const NodeType* node) {
  264. std::unique_ptr<NodeAttachedData> data =
  265. NodeAttachedDataMapHelper::DetachFromMap(node, DataType::UserDataKey());
  266. return data.get();
  267. }
  268. // Node owned storage impl.
  269. // static
  270. template <typename DataType>
  271. template <typename NodeType>
  272. DataType* NodeAttachedDataImpl<DataType>::NodeAttachedDataOwnedByNodeType<
  273. NodeType>::GetOrCreate(const NodeType* node) {
  274. std::unique_ptr<NodeAttachedData>* storage =
  275. DataType::GetUniquePtrStorage(const_cast<NodeType*>(node));
  276. if (!storage->get())
  277. *storage = base::WrapUnique(new DataType(node));
  278. DCHECK_EQ(DataType::UserDataKey(), storage->get()->GetKey());
  279. return static_cast<DataType*>(storage->get());
  280. }
  281. // static
  282. template <typename DataType>
  283. template <typename NodeType>
  284. DataType*
  285. NodeAttachedDataImpl<DataType>::NodeAttachedDataOwnedByNodeType<NodeType>::Get(
  286. const NodeType* node) {
  287. std::unique_ptr<NodeAttachedData>* storage =
  288. DataType::GetUniquePtrStorage(const_cast<NodeType*>(node));
  289. if (storage->get())
  290. DCHECK_EQ(DataType::UserDataKey(), storage->get()->GetKey());
  291. return static_cast<DataType*>(storage->get());
  292. }
  293. // static
  294. template <typename DataType>
  295. template <typename NodeType>
  296. bool NodeAttachedDataImpl<DataType>::NodeAttachedDataOwnedByNodeType<
  297. NodeType>::Destroy(const NodeType* node) {
  298. std::unique_ptr<NodeAttachedData>* storage =
  299. DataType::GetUniquePtrStorage(const_cast<NodeType*>(node));
  300. bool data_exists = storage->get();
  301. storage->reset();
  302. return data_exists;
  303. }
  304. // Node internal storage impl.
  305. // static
  306. template <typename DataType>
  307. template <typename NodeType>
  308. DataType* NodeAttachedDataImpl<DataType>::NodeAttachedDataInternalOnNodeType<
  309. NodeType>::GetOrCreate(const NodeType* node) {
  310. // TODO(chrisha): Add a compile test that this is enforced. Otherwise, there's
  311. // potential for a OOB reads / security issues. https://www.crbug.com/952864
  312. InternalNodeAttachedDataStorage<sizeof(DataType)>* storage =
  313. DataType::GetInternalStorage(const_cast<NodeType*>(node));
  314. if (!storage->Get()) {
  315. NodeAttachedData* data = new (storage->buffer()) DataType(node);
  316. InternalNodeAttachedDataStorageAccess::Set(storage, data);
  317. }
  318. DCHECK_EQ(DataType::UserDataKey(), storage->Get()->GetKey());
  319. return static_cast<DataType*>(storage->Get());
  320. }
  321. // static
  322. template <typename DataType>
  323. template <typename NodeType>
  324. DataType* NodeAttachedDataImpl<DataType>::NodeAttachedDataInternalOnNodeType<
  325. NodeType>::Get(const NodeType* node) {
  326. InternalNodeAttachedDataStorage<sizeof(DataType)>* storage =
  327. DataType::GetInternalStorage(const_cast<NodeType*>(node));
  328. if (storage->Get())
  329. DCHECK_EQ(DataType::UserDataKey(), storage->Get()->GetKey());
  330. return static_cast<DataType*>(storage->Get());
  331. }
  332. // static
  333. template <typename DataType>
  334. template <typename NodeType>
  335. bool NodeAttachedDataImpl<DataType>::NodeAttachedDataInternalOnNodeType<
  336. NodeType>::Destroy(const NodeType* node) {
  337. InternalNodeAttachedDataStorage<sizeof(DataType)>* storage =
  338. DataType::GetInternalStorage(const_cast<NodeType*>(node));
  339. bool data_exists = storage->Get();
  340. storage->Reset();
  341. return data_exists;
  342. }
  343. } // namespace performance_manager
  344. #endif // COMPONENTS_PERFORMANCE_MANAGER_GRAPH_NODE_ATTACHED_DATA_IMPL_H_