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