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* 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 Edge* CreateEdgeFromOriginalType(const clang::Type* type); 133 134 RecordCache* cache_; 135 clang::CXXRecordDecl* record_; 136 const std::string name_; 137 TracingStatus fields_need_tracing_; 138 Bases* bases_; 139 Fields* fields_; 140 141 enum CachedBool { kFalse = 0, kTrue = 1, kNotComputed = 2 }; 142 CachedBool is_stack_allocated_; 143 CachedBool is_non_newable_; 144 CachedBool is_only_placement_newable_; 145 CachedBool does_need_finalization_; 146 CachedBool has_gc_mixin_methods_; 147 CachedBool is_declaring_local_trace_; 148 CachedBool is_eagerly_finalized_; 149 150 bool determined_trace_methods_; 151 clang::CXXMethodDecl* trace_method_; 152 clang::CXXMethodDecl* trace_dispatch_method_; 153 clang::CXXMethodDecl* finalize_dispatch_method_; 154 155 bool is_gc_derived_; 156 157 std::vector<std::string> gc_base_names_; 158 159 friend class RecordCache; 160 }; 161 162 class RecordCache { 163 public: RecordCache(clang::CompilerInstance & instance)164 RecordCache(clang::CompilerInstance& instance) 165 : instance_(instance) 166 { 167 } 168 169 RecordInfo* Lookup(clang::CXXRecordDecl* record); 170 Lookup(const clang::CXXRecordDecl * record)171 RecordInfo* Lookup(const clang::CXXRecordDecl* record) { 172 return Lookup(const_cast<clang::CXXRecordDecl*>(record)); 173 } 174 Lookup(clang::DeclContext * decl)175 RecordInfo* Lookup(clang::DeclContext* decl) { 176 return Lookup(clang::dyn_cast<clang::CXXRecordDecl>(decl)); 177 } 178 Lookup(const clang::Type * type)179 RecordInfo* Lookup(const clang::Type* type) { 180 return Lookup(type->getAsCXXRecordDecl()); 181 } 182 Lookup(const clang::QualType & type)183 RecordInfo* Lookup(const clang::QualType& type) { 184 return Lookup(type.getTypePtr()); 185 } 186 ~RecordCache()187 ~RecordCache() { 188 for (Cache::iterator it = cache_.begin(); it != cache_.end(); ++it) { 189 if (!it->second.fields_) 190 continue; 191 for (RecordInfo::Fields::iterator fit = it->second.fields_->begin(); 192 fit != it->second.fields_->end(); 193 ++fit) { 194 fit->second.deleteEdge(); 195 } 196 } 197 } 198 instance()199 clang::CompilerInstance& instance() const { return instance_; } 200 201 private: 202 clang::CompilerInstance& instance_; 203 204 typedef std::map<clang::CXXRecordDecl*, RecordInfo> Cache; 205 Cache cache_; 206 }; 207 208 #endif // TOOLS_BLINK_GC_PLUGIN_RECORD_INFO_H_ 209