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 20class RecordCache; 21 22// A potentially tracable and/or lifetime affecting point in the object graph. 23class 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 34class 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 50class 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. 69class 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 CachedBool does_need_finalization_; 125 126 bool determined_trace_methods_; 127 clang::CXXMethodDecl* trace_method_; 128 clang::CXXMethodDecl* trace_dispatch_method_; 129 clang::CXXMethodDecl* finalize_dispatch_method_; 130 131 bool is_gc_derived_; 132 clang::CXXBasePaths* base_paths_; 133 134 friend class RecordCache; 135}; 136 137class RecordCache { 138 public: 139 RecordInfo* Lookup(clang::CXXRecordDecl* record); 140 141 RecordInfo* Lookup(const clang::CXXRecordDecl* record) { 142 return Lookup(const_cast<clang::CXXRecordDecl*>(record)); 143 } 144 145 RecordInfo* Lookup(clang::DeclContext* decl) { 146 return Lookup(clang::dyn_cast<clang::CXXRecordDecl>(decl)); 147 } 148 149 RecordInfo* Lookup(const clang::Type* type) { 150 return Lookup(type->getAsCXXRecordDecl()); 151 } 152 153 RecordInfo* Lookup(const clang::QualType& type) { 154 return Lookup(type.getTypePtr()); 155 } 156 157 ~RecordCache() { 158 for (Cache::iterator it = cache_.begin(); it != cache_.end(); ++it) { 159 if (!it->second.fields_) 160 continue; 161 for (RecordInfo::Fields::iterator fit = it->second.fields_->begin(); 162 fit != it->second.fields_->end(); 163 ++fit) { 164 fit->second.deleteEdge(); 165 } 166 } 167 } 168 169 private: 170 typedef std::map<clang::CXXRecordDecl*, RecordInfo> Cache; 171 Cache cache_; 172}; 173 174#endif // TOOLS_BLINK_GC_PLUGIN_RECORD_INFO_H_ 175