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 20 class RecordCache; 21 22 // A potentially tracable and/or lifetime affecting point in the object graph. 23 class GraphPoint { 24 public: 25 GraphPoint() : traced_(false) {} 26 void MarkTraced() { traced_ = true; } 27 bool IsProperlyTraced() { return traced_ || !NeedsTracing().IsNeeded(); } 28 virtual const TracingStatus NeedsTracing() = 0; 29 30 private: 31 bool traced_; 32 }; 33 34 class BasePoint : public GraphPoint { 35 public: 36 BasePoint(const clang::CXXBaseSpecifier& spec, 37 RecordInfo* info, 38 const TracingStatus& status) 39 : spec_(spec), info_(info), status_(status) {} 40 const TracingStatus NeedsTracing() { return status_; } 41 const clang::CXXBaseSpecifier& spec() { return spec_; } 42 RecordInfo* info() { return info_; } 43 44 private: 45 const clang::CXXBaseSpecifier& spec_; 46 RecordInfo* info_; 47 TracingStatus status_; 48 }; 49 50 class FieldPoint : public GraphPoint { 51 public: 52 FieldPoint(clang::FieldDecl* field, Edge* edge) 53 : field_(field), edge_(edge) {} 54 const TracingStatus NeedsTracing() { 55 return edge_->NeedsTracing(Edge::kRecursive); 56 } 57 clang::FieldDecl* field() { return field_; } 58 Edge* edge() { return edge_; } 59 60 private: 61 clang::FieldDecl* field_; 62 Edge* edge_; 63 64 friend class RecordCache; 65 void deleteEdge() { delete edge_; } 66 }; 67 68 // Wrapper class to lazily collect information about a C++ record. 69 class RecordInfo { 70 public: 71 typedef std::map<clang::CXXRecordDecl*, BasePoint> Bases; 72 typedef std::map<clang::FieldDecl*, FieldPoint> Fields; 73 typedef std::vector<const clang::Type*> TemplateArgs; 74 75 ~RecordInfo(); 76 77 clang::CXXRecordDecl* record() const { return record_; } 78 const std::string& name() const { return name_; } 79 Fields& GetFields(); 80 Bases& GetBases(); 81 clang::CXXMethodDecl* GetTraceMethod(); 82 clang::CXXMethodDecl* GetTraceDispatchMethod(); 83 clang::CXXMethodDecl* GetFinalizeDispatchMethod(); 84 85 bool GetTemplateArgs(size_t count, TemplateArgs* output_args); 86 87 bool IsHeapAllocatedCollection(); 88 bool IsGCDerived(); 89 bool IsGCAllocated(); 90 bool IsGCFinalized(); 91 bool IsGCMixin(); 92 bool IsStackAllocated(); 93 bool IsNonNewable(); 94 bool IsOnlyPlacementNewable(); 95 clang::CXXMethodDecl* DeclaresNewOperator(); 96 97 bool RequiresTraceMethod(); 98 bool NeedsFinalization(); 99 TracingStatus NeedsTracing(Edge::NeedsTracingOption); 100 clang::CXXMethodDecl* InheritsNonVirtualTrace(); 101 bool IsConsideredAbstract(); 102 103 private: 104 RecordInfo(clang::CXXRecordDecl* record, RecordCache* cache); 105 106 Fields* CollectFields(); 107 Bases* CollectBases(); 108 void DetermineTracingMethods(); 109 bool InheritsTrace(); 110 111 Edge* CreateEdge(const clang::Type* type); 112 113 RecordCache* cache_; 114 clang::CXXRecordDecl* record_; 115 const std::string name_; 116 TracingStatus fields_need_tracing_; 117 Bases* bases_; 118 Fields* fields_; 119 120 enum CachedBool { kFalse = 0, kTrue = 1, kNotComputed = 2 }; 121 CachedBool is_stack_allocated_; 122 CachedBool is_non_newable_; 123 CachedBool is_only_placement_newable_; 124 125 bool determined_trace_methods_; 126 clang::CXXMethodDecl* trace_method_; 127 clang::CXXMethodDecl* trace_dispatch_method_; 128 clang::CXXMethodDecl* finalize_dispatch_method_; 129 130 bool is_gc_derived_; 131 clang::CXXBasePaths* base_paths_; 132 133 friend class RecordCache; 134 }; 135 136 class RecordCache { 137 public: 138 RecordInfo* Lookup(clang::CXXRecordDecl* record); 139 140 RecordInfo* Lookup(const clang::CXXRecordDecl* record) { 141 return Lookup(const_cast<clang::CXXRecordDecl*>(record)); 142 } 143 144 RecordInfo* Lookup(clang::DeclContext* decl) { 145 return Lookup(clang::dyn_cast<clang::CXXRecordDecl>(decl)); 146 } 147 148 RecordInfo* Lookup(const clang::Type* type) { 149 return Lookup(type->getAsCXXRecordDecl()); 150 } 151 152 RecordInfo* Lookup(const clang::QualType& type) { 153 return Lookup(type.getTypePtr()); 154 } 155 156 ~RecordCache() { 157 for (Cache::iterator it = cache_.begin(); it != cache_.end(); ++it) { 158 if (!it->second.fields_) 159 continue; 160 for (RecordInfo::Fields::iterator fit = it->second.fields_->begin(); 161 fit != it->second.fields_->end(); 162 ++fit) { 163 fit->second.deleteEdge(); 164 } 165 } 166 } 167 168 private: 169 typedef std::map<clang::CXXRecordDecl*, RecordInfo> Cache; 170 Cache cache_; 171 }; 172 173 #endif // TOOLS_BLINK_GC_PLUGIN_RECORD_INFO_H_ 174