RecordInfo.h revision effb81e5f8246d0db0270817048dc992db66e9fb
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  // Needed to change the status of bases with a pure-virtual trace.
42  void MarkUnneeded() { status_ = TracingStatus::Unneeded(); }
43  const clang::CXXBaseSpecifier& spec() { return spec_; }
44  RecordInfo* info() { return info_; }
45
46 private:
47  const clang::CXXBaseSpecifier& spec_;
48  RecordInfo* info_;
49  TracingStatus status_;
50};
51
52class FieldPoint : public GraphPoint {
53 public:
54  FieldPoint(clang::FieldDecl* field, Edge* edge)
55      : field_(field), edge_(edge) {}
56  const TracingStatus NeedsTracing() {
57    return edge_->NeedsTracing(Edge::kRecursive);
58  }
59  clang::FieldDecl* field() { return field_; }
60  Edge* edge() { return edge_; }
61
62 private:
63  clang::FieldDecl* field_;
64  Edge* edge_;
65
66  friend class RecordCache;
67  void deleteEdge() { delete edge_; }
68};
69
70// Wrapper class to lazily collect information about a C++ record.
71class RecordInfo {
72 public:
73  typedef std::map<clang::CXXRecordDecl*, BasePoint> Bases;
74  typedef std::map<clang::FieldDecl*, FieldPoint> Fields;
75  typedef std::vector<const clang::Type*> TemplateArgs;
76
77  ~RecordInfo();
78
79  clang::CXXRecordDecl* record() const { return record_; }
80  const std::string& name() const { return name_; }
81  Fields& GetFields();
82  Bases& GetBases();
83  clang::CXXMethodDecl* GetTraceMethod();
84  clang::CXXMethodDecl* GetTraceDispatchMethod();
85  clang::CXXMethodDecl* GetFinalizeDispatchMethod();
86
87  bool GetTemplateArgs(size_t count, TemplateArgs* output_args);
88
89  bool IsHeapAllocatedCollection();
90  bool IsGCDerived();
91  bool IsGCAllocated();
92  bool IsGCFinalized();
93  bool IsGCMixin();
94  bool IsStackAllocated();
95  bool IsNonNewable();
96  bool IsOnlyPlacementNewable();
97
98  bool RequiresTraceMethod();
99  bool NeedsFinalization();
100  TracingStatus NeedsTracing(Edge::NeedsTracingOption);
101  clang::CXXMethodDecl* InheritsNonVirtualTrace();
102  bool IsConsideredAbstract();
103
104 private:
105  RecordInfo(clang::CXXRecordDecl* record, RecordCache* cache);
106
107  Fields* CollectFields();
108  Bases* CollectBases();
109  void DetermineTracingMethods();
110  bool InheritsNonPureTrace();
111
112  Edge* CreateEdge(const clang::Type* type);
113
114  RecordCache* cache_;
115  clang::CXXRecordDecl* record_;
116  const std::string name_;
117  TracingStatus fields_need_tracing_;
118  Bases* bases_;
119  Fields* fields_;
120
121  enum CachedBool { kFalse = 0, kTrue = 1, kNotComputed = 2 };
122  CachedBool is_stack_allocated_;
123  CachedBool is_non_newable_;
124  CachedBool is_only_placement_newable_;
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