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: GraphPoint()26 GraphPoint() : traced_(false) {} ~GraphPoint()27 virtual ~GraphPoint() {} MarkTraced()28 void MarkTraced() { traced_ = true; } IsProperlyTraced()29 bool IsProperlyTraced() { return traced_ || !NeedsTracing().IsNeeded(); } IsInproperlyTraced()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: BasePoint(const clang::CXXBaseSpecifier & spec,RecordInfo * info,const TracingStatus & status)39 BasePoint(const clang::CXXBaseSpecifier& spec, 40 RecordInfo* info, 41 const TracingStatus& status) 42 : spec_(spec), info_(info), status_(status) {} NeedsTracing()43 const TracingStatus NeedsTracing() { return status_; } spec()44 const clang::CXXBaseSpecifier& spec() { return spec_; } info()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: FieldPoint(clang::FieldDecl * field,Edge * edge)55 FieldPoint(clang::FieldDecl* field, Edge* edge) 56 : field_(field), edge_(edge) {} NeedsTracing()57 const TracingStatus NeedsTracing() { 58 return edge_->NeedsTracing(Edge::kRecursive); 59 } field()60 clang::FieldDecl* field() { return field_; } edge()61 Edge* edge() { return edge_; } 62 63 private: 64 clang::FieldDecl* field_; 65 Edge* edge_; 66 67 friend class RecordCache; deleteEdge()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 { operatorFieldDeclCmp77 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 record()87 clang::CXXRecordDecl* record() const { return record_; } name()88 const std::string& name() const { return name_; } 89 Fields& GetFields(); 90 Bases& GetBases(); 91 clang::CXXMethodDecl* GetTraceMethod(); 92 clang::CXXMethodDecl* GetTraceWrappersMethod(); 93 clang::CXXMethodDecl* GetTraceDispatchMethod(); 94 clang::CXXMethodDecl* GetFinalizeDispatchMethod(); 95 96 bool GetTemplateArgs(size_t count, TemplateArgs* output_args); 97 98 bool IsHeapAllocatedCollection(); 99 bool IsGCDerived(); 100 bool IsGCAllocated(); 101 bool IsGCFinalized(); 102 bool IsGCMixin(); 103 bool IsStackAllocated(); 104 bool IsNonNewable(); 105 bool IsOnlyPlacementNewable(); 106 bool IsEagerlyFinalized(); 107 108 bool HasDefinition(); 109 110 clang::CXXMethodDecl* DeclaresNewOperator(); 111 112 bool RequiresTraceMethod(); 113 bool NeedsFinalization(); 114 bool DeclaresGCMixinMethods(); 115 bool DeclaresLocalTraceMethod(); 116 TracingStatus NeedsTracing(Edge::NeedsTracingOption); 117 clang::CXXMethodDecl* InheritsNonVirtualTrace(); 118 bool IsConsideredAbstract(); 119 120 static clang::CXXRecordDecl* GetDependentTemplatedDecl(const clang::Type&); 121 122 private: 123 RecordInfo(clang::CXXRecordDecl* record, RecordCache* cache); 124 125 void walkBases(); 126 127 Fields* CollectFields(); 128 Bases* CollectBases(); 129 void DetermineTracingMethods(); 130 bool InheritsTrace(); 131 132 Edge* CreateEdge(const clang::Type* type); 133 Edge* CreateEdgeFromOriginalType(const clang::Type* type); 134 135 bool HasOptionalFinalizer(); 136 137 RecordCache* cache_; 138 clang::CXXRecordDecl* record_; 139 const std::string name_; 140 TracingStatus fields_need_tracing_; 141 Bases* bases_; 142 Fields* fields_; 143 144 enum CachedBool { kFalse = 0, kTrue = 1, kNotComputed = 2 }; 145 CachedBool is_stack_allocated_; 146 CachedBool is_non_newable_; 147 CachedBool is_only_placement_newable_; 148 CachedBool does_need_finalization_; 149 CachedBool has_gc_mixin_methods_; 150 CachedBool is_declaring_local_trace_; 151 CachedBool is_eagerly_finalized_; 152 153 bool determined_trace_methods_; 154 clang::CXXMethodDecl* trace_method_; 155 clang::CXXMethodDecl* trace_dispatch_method_; 156 clang::CXXMethodDecl* finalize_dispatch_method_; 157 158 bool is_gc_derived_; 159 160 std::vector<std::string> gc_base_names_; 161 162 friend class RecordCache; 163 }; 164 165 class RecordCache { 166 public: RecordCache(clang::CompilerInstance & instance)167 RecordCache(clang::CompilerInstance& instance) 168 : instance_(instance) 169 { 170 } 171 172 RecordInfo* Lookup(clang::CXXRecordDecl* record); 173 Lookup(const clang::CXXRecordDecl * record)174 RecordInfo* Lookup(const clang::CXXRecordDecl* record) { 175 return Lookup(const_cast<clang::CXXRecordDecl*>(record)); 176 } 177 Lookup(clang::DeclContext * decl)178 RecordInfo* Lookup(clang::DeclContext* decl) { 179 return Lookup(clang::dyn_cast<clang::CXXRecordDecl>(decl)); 180 } 181 Lookup(const clang::Type * type)182 RecordInfo* Lookup(const clang::Type* type) { 183 return Lookup(type->getAsCXXRecordDecl()); 184 } 185 Lookup(const clang::QualType & type)186 RecordInfo* Lookup(const clang::QualType& type) { 187 return Lookup(type.getTypePtr()); 188 } 189 ~RecordCache()190 ~RecordCache() { 191 for (Cache::iterator it = cache_.begin(); it != cache_.end(); ++it) { 192 if (!it->second.fields_) 193 continue; 194 for (RecordInfo::Fields::iterator fit = it->second.fields_->begin(); 195 fit != it->second.fields_->end(); 196 ++fit) { 197 fit->second.deleteEdge(); 198 } 199 } 200 } 201 instance()202 clang::CompilerInstance& instance() const { return instance_; } 203 204 private: 205 clang::CompilerInstance& instance_; 206 207 typedef std::map<clang::CXXRecordDecl*, RecordInfo> Cache; 208 Cache cache_; 209 }; 210 211 #endif // TOOLS_BLINK_GC_PLUGIN_RECORD_INFO_H_ 212