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