RecordInfo.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // Copyright 2014 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. // This file provides a wrapper for CXXRecordDecl that accumulates GC related
  5. // information about a class. Accumulated information is memoized and the info
  6. // objects are stored in a RecordCache.
  7. #ifndef TOOLS_BLINK_GC_PLUGIN_RECORD_INFO_H_
  8. #define TOOLS_BLINK_GC_PLUGIN_RECORD_INFO_H_
  9. #include <map>
  10. #include <vector>
  11. #include "Edge.h"
  12. #include "clang/AST/AST.h"
  13. #include "clang/AST/CXXInheritance.h"
  14. #include "clang/Frontend/CompilerInstance.h"
  15. class RecordCache;
  16. // A potentially tracable and/or lifetime affecting point in the object graph.
  17. class GraphPoint {
  18. public:
  19. GraphPoint() : traced_(false) {}
  20. virtual ~GraphPoint() {}
  21. void MarkTraced() { traced_ = true; }
  22. bool IsProperlyTraced() { return traced_ || !NeedsTracing().IsNeeded(); }
  23. bool IsInproperlyTraced() { return traced_ && NeedsTracing().IsIllegal(); }
  24. virtual const TracingStatus NeedsTracing() = 0;
  25. private:
  26. bool traced_;
  27. };
  28. class BasePoint : public GraphPoint {
  29. public:
  30. BasePoint(const clang::CXXBaseSpecifier& spec,
  31. RecordInfo* info,
  32. const TracingStatus& status)
  33. : spec_(spec), info_(info), status_(status) {}
  34. const TracingStatus NeedsTracing() override { return status_; }
  35. const clang::CXXBaseSpecifier& spec() { return spec_; }
  36. RecordInfo* info() { return info_; }
  37. private:
  38. const clang::CXXBaseSpecifier& spec_;
  39. RecordInfo* info_;
  40. TracingStatus status_;
  41. };
  42. class FieldPoint : public GraphPoint {
  43. public:
  44. FieldPoint(clang::FieldDecl* field, Edge* edge)
  45. : field_(field), edge_(edge) {}
  46. const TracingStatus NeedsTracing() override {
  47. return edge_->NeedsTracing(Edge::kRecursive);
  48. }
  49. clang::FieldDecl* field() { return field_; }
  50. Edge* edge() { return edge_; }
  51. private:
  52. clang::FieldDecl* field_;
  53. Edge* edge_;
  54. friend class RecordCache;
  55. void deleteEdge() { delete edge_; }
  56. };
  57. // Wrapper class to lazily collect information about a C++ record.
  58. class RecordInfo {
  59. public:
  60. typedef std::vector<std::pair<clang::CXXRecordDecl*, BasePoint>> Bases;
  61. struct FieldDeclCmp {
  62. bool operator()(clang::FieldDecl* a, clang::FieldDecl *b) const {
  63. return a->getBeginLoc() < b->getBeginLoc();
  64. }
  65. };
  66. typedef std::map<clang::FieldDecl*, FieldPoint, FieldDeclCmp> Fields;
  67. typedef std::vector<const clang::Type*> TemplateArgs;
  68. ~RecordInfo();
  69. clang::CXXRecordDecl* record() const { return record_; }
  70. const std::string& name() const { return name_; }
  71. Fields& GetFields();
  72. Bases& GetBases();
  73. const clang::CXXBaseSpecifier* GetDirectGCBase();
  74. clang::CXXMethodDecl* GetTraceMethod();
  75. clang::CXXMethodDecl* GetTraceWrappersMethod();
  76. clang::CXXMethodDecl* GetTraceDispatchMethod();
  77. clang::CXXMethodDecl* GetFinalizeDispatchMethod();
  78. bool GetTemplateArgs(size_t count, TemplateArgs* output_args);
  79. bool IsHeapAllocatedCollection();
  80. bool IsGCDerived();
  81. bool IsGCDirectlyDerived();
  82. bool IsGCAllocated();
  83. bool IsGCMixin();
  84. bool IsStackAllocated();
  85. bool IsNonNewable();
  86. bool IsOnlyPlacementNewable();
  87. bool HasDefinition();
  88. clang::CXXMethodDecl* DeclaresNewOperator();
  89. bool RequiresTraceMethod();
  90. bool NeedsFinalization();
  91. bool DeclaresGCMixinMethods();
  92. bool DeclaresLocalTraceMethod();
  93. TracingStatus NeedsTracing(Edge::NeedsTracingOption);
  94. clang::CXXMethodDecl* InheritsNonVirtualTrace();
  95. bool IsConsideredAbstract();
  96. static clang::CXXRecordDecl* GetDependentTemplatedDecl(const clang::Type&);
  97. private:
  98. RecordInfo(clang::CXXRecordDecl* record, RecordCache* cache);
  99. void walkBases();
  100. Fields* CollectFields();
  101. Bases* CollectBases();
  102. void DetermineTracingMethods();
  103. bool InheritsTrace();
  104. Edge* CreateEdge(const clang::Type* type);
  105. Edge* CreateEdgeFromOriginalType(const clang::Type* type);
  106. bool HasOptionalFinalizer();
  107. bool HasTypeAlias(std::string marker_name) const;
  108. RecordCache* cache_;
  109. clang::CXXRecordDecl* record_;
  110. const std::string name_;
  111. TracingStatus fields_need_tracing_;
  112. Bases* bases_;
  113. Fields* fields_;
  114. enum CachedBool { kFalse = 0, kTrue = 1, kNotComputed = 2 };
  115. CachedBool is_stack_allocated_;
  116. CachedBool is_non_newable_;
  117. CachedBool is_only_placement_newable_;
  118. CachedBool does_need_finalization_;
  119. CachedBool has_gc_mixin_methods_;
  120. CachedBool is_declaring_local_trace_;
  121. bool determined_trace_methods_;
  122. clang::CXXMethodDecl* trace_method_;
  123. clang::CXXMethodDecl* trace_dispatch_method_;
  124. clang::CXXMethodDecl* finalize_dispatch_method_;
  125. bool is_gc_derived_;
  126. std::vector<std::string> gc_base_names_;
  127. const clang::CXXBaseSpecifier* directly_derived_gc_base_;
  128. friend class RecordCache;
  129. };
  130. class RecordCache {
  131. public:
  132. RecordCache(clang::CompilerInstance& instance)
  133. : instance_(instance)
  134. {
  135. }
  136. RecordInfo* Lookup(clang::CXXRecordDecl* record);
  137. RecordInfo* Lookup(const clang::CXXRecordDecl* record) {
  138. return Lookup(const_cast<clang::CXXRecordDecl*>(record));
  139. }
  140. RecordInfo* Lookup(clang::DeclContext* decl) {
  141. return Lookup(clang::dyn_cast<clang::CXXRecordDecl>(decl));
  142. }
  143. RecordInfo* Lookup(const clang::Type* type) {
  144. return Lookup(type->getAsCXXRecordDecl());
  145. }
  146. RecordInfo* Lookup(const clang::QualType& type) {
  147. return Lookup(type.getTypePtr());
  148. }
  149. ~RecordCache() {
  150. for (Cache::iterator it = cache_.begin(); it != cache_.end(); ++it) {
  151. if (!it->second.fields_)
  152. continue;
  153. for (RecordInfo::Fields::iterator fit = it->second.fields_->begin();
  154. fit != it->second.fields_->end();
  155. ++fit) {
  156. fit->second.deleteEdge();
  157. }
  158. }
  159. }
  160. clang::CompilerInstance& instance() const { return instance_; }
  161. private:
  162. clang::CompilerInstance& instance_;
  163. typedef std::map<clang::CXXRecordDecl*, RecordInfo> Cache;
  164. Cache cache_;
  165. };
  166. #endif // TOOLS_BLINK_GC_PLUGIN_RECORD_INFO_H_