• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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