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#ifndef TOOLS_BLINK_GC_PLUGIN_EDGE_H_
6#define TOOLS_BLINK_GC_PLUGIN_EDGE_H_
7
8#include <deque>
9
10#include "TracingStatus.h"
11
12class RecordInfo;
13
14class Edge;
15class Value;
16class RawPtr;
17class RefPtr;
18class OwnPtr;
19class Member;
20class WeakMember;
21class Persistent;
22class Collection;
23
24// Bare-bones visitor.
25class EdgeVisitor {
26 public:
27  virtual void VisitValue(Value*) {}
28  virtual void VisitRawPtr(RawPtr*) {}
29  virtual void VisitRefPtr(RefPtr*) {}
30  virtual void VisitOwnPtr(OwnPtr*) {}
31  virtual void VisitMember(Member*) {}
32  virtual void VisitWeakMember(WeakMember*) {}
33  virtual void VisitPersistent(Persistent*) {}
34  virtual void VisitCollection(Collection*) {}
35};
36
37// Recursive edge visitor. The traversed path is accessible in context.
38class RecursiveEdgeVisitor : public EdgeVisitor {
39 public:
40  // Overrides that recursively walk the edges and record the path.
41  virtual void VisitValue(Value*) override;
42  virtual void VisitRawPtr(RawPtr*) override;
43  virtual void VisitRefPtr(RefPtr*) override;
44  virtual void VisitOwnPtr(OwnPtr*) override;
45  virtual void VisitMember(Member*) override;
46  virtual void VisitWeakMember(WeakMember*) override;
47  virtual void VisitPersistent(Persistent*) override;
48  virtual void VisitCollection(Collection*) override;
49
50 protected:
51  typedef std::deque<Edge*> Context;
52  Context& context() { return context_; }
53  Edge* Parent() { return context_.empty() ? 0 : context_.front(); }
54  void Enter(Edge* e) { return context_.push_front(e); }
55  void Leave() { context_.pop_front(); }
56
57  // Default callback to overwrite in visitor subclass.
58  virtual void AtValue(Value*);
59  virtual void AtRawPtr(RawPtr*);
60  virtual void AtRefPtr(RefPtr*);
61  virtual void AtOwnPtr(OwnPtr*);
62  virtual void AtMember(Member*);
63  virtual void AtWeakMember(WeakMember*);
64  virtual void AtPersistent(Persistent*);
65  virtual void AtCollection(Collection*);
66
67 private:
68  Context context_;
69};
70
71// Base class for all edges.
72class Edge {
73 public:
74  enum NeedsTracingOption { kRecursive, kNonRecursive };
75  enum LivenessKind { kWeak, kStrong, kRoot };
76
77  virtual ~Edge() {}
78  virtual LivenessKind Kind() = 0;
79  virtual void Accept(EdgeVisitor*) = 0;
80  virtual bool NeedsFinalization() = 0;
81  virtual TracingStatus NeedsTracing(NeedsTracingOption) {
82    return TracingStatus::Unknown();
83  }
84
85  virtual bool IsValue() { return false; }
86  virtual bool IsRawPtr() { return false; }
87  virtual bool IsRawPtrClass() { return false; }
88  virtual bool IsRefPtr() { return false; }
89  virtual bool IsOwnPtr() { return false; }
90  virtual bool IsMember() { return false; }
91  virtual bool IsWeakMember() { return false; }
92  virtual bool IsPersistent() { return false; }
93  virtual bool IsCollection() { return false; }
94};
95
96// A value edge is a direct edge to some type, eg, part-object edges.
97class Value : public Edge {
98 public:
99  explicit Value(RecordInfo* value) : value_(value) {};
100  bool IsValue() override { return true; }
101  LivenessKind Kind() override { return kStrong; }
102  bool NeedsFinalization() override;
103  TracingStatus NeedsTracing(NeedsTracingOption) override;
104  void Accept(EdgeVisitor* visitor) override { visitor->VisitValue(this); }
105  RecordInfo* value() { return value_; }
106
107 private:
108  RecordInfo* value_;
109};
110
111// Shared base for smart-pointer edges.
112class PtrEdge : public Edge {
113 public:
114  ~PtrEdge() { delete ptr_; }
115  Edge* ptr() { return ptr_; }
116 protected:
117  PtrEdge(Edge* ptr) : ptr_(ptr) {
118    assert(ptr && "EdgePtr pointer must be non-null");
119  }
120 private:
121  Edge* ptr_;
122};
123
124class RawPtr : public PtrEdge {
125 public:
126  explicit RawPtr(Edge* ptr, bool is_ptr_class)
127      : PtrEdge(ptr), is_ptr_class_(is_ptr_class) { }
128  bool IsRawPtr() { return true; }
129  bool IsRawPtrClass() { return is_ptr_class_; }
130  LivenessKind Kind() { return kWeak; }
131  bool NeedsFinalization() { return false; }
132  TracingStatus NeedsTracing(NeedsTracingOption) {
133    return TracingStatus::Unneeded();
134  }
135  void Accept(EdgeVisitor* visitor) { visitor->VisitRawPtr(this); }
136 private:
137  bool is_ptr_class_;
138};
139
140class RefPtr : public PtrEdge {
141 public:
142  explicit RefPtr(Edge* ptr) : PtrEdge(ptr) { }
143  bool IsRefPtr() { return true; }
144  LivenessKind Kind() { return kStrong; }
145  bool NeedsFinalization() { return true; }
146  TracingStatus NeedsTracing(NeedsTracingOption) {
147    return TracingStatus::Unneeded();
148  }
149  void Accept(EdgeVisitor* visitor) { visitor->VisitRefPtr(this); }
150};
151
152class OwnPtr : public PtrEdge {
153 public:
154  explicit OwnPtr(Edge* ptr) : PtrEdge(ptr) { }
155  bool IsOwnPtr() { return true; }
156  LivenessKind Kind() { return kStrong; }
157  bool NeedsFinalization() { return true; }
158  TracingStatus NeedsTracing(NeedsTracingOption) {
159    return TracingStatus::Unneeded();
160  }
161  void Accept(EdgeVisitor* visitor) { visitor->VisitOwnPtr(this); }
162};
163
164class Member : public PtrEdge {
165 public:
166  explicit Member(Edge* ptr) : PtrEdge(ptr) { }
167  bool IsMember() { return true; }
168  LivenessKind Kind() { return kStrong; }
169  bool NeedsFinalization() { return false; }
170  TracingStatus NeedsTracing(NeedsTracingOption) {
171    return TracingStatus::Needed();
172  }
173  void Accept(EdgeVisitor* visitor) { visitor->VisitMember(this); }
174};
175
176class WeakMember : public PtrEdge {
177 public:
178  explicit WeakMember(Edge* ptr) : PtrEdge(ptr) { }
179  bool IsWeakMember() { return true; }
180  LivenessKind Kind() { return kWeak; }
181  bool NeedsFinalization() { return false; }
182  TracingStatus NeedsTracing(NeedsTracingOption) {
183    return TracingStatus::Needed();
184  }
185  void Accept(EdgeVisitor* visitor) { visitor->VisitWeakMember(this); }
186};
187
188class Persistent : public PtrEdge {
189 public:
190  explicit Persistent(Edge* ptr) : PtrEdge(ptr) { }
191  bool IsPersistent() { return true; }
192  LivenessKind Kind() { return kRoot; }
193  bool NeedsFinalization() { return true; }
194  TracingStatus NeedsTracing(NeedsTracingOption) {
195    return TracingStatus::Unneeded();
196  }
197  void Accept(EdgeVisitor* visitor) { visitor->VisitPersistent(this); }
198};
199
200class Collection : public Edge {
201 public:
202  typedef std::vector<Edge*> Members;
203  Collection(RecordInfo* info, bool on_heap, bool is_root)
204      : info_(info),
205        on_heap_(on_heap),
206        is_root_(is_root) {}
207  ~Collection() {
208    for (Members::iterator it = members_.begin(); it != members_.end(); ++it) {
209      assert(*it && "Collection-edge members must be non-null");
210      delete *it;
211    }
212  }
213  bool IsCollection() { return true; }
214  LivenessKind Kind() { return is_root_ ? kRoot : kStrong; }
215  bool on_heap() { return on_heap_; }
216  bool is_root() { return is_root_; }
217  Members& members() { return members_; }
218  void Accept(EdgeVisitor* visitor) { visitor->VisitCollection(this); }
219  void AcceptMembers(EdgeVisitor* visitor) {
220    for (Members::iterator it = members_.begin(); it != members_.end(); ++it)
221      (*it)->Accept(visitor);
222  }
223  bool NeedsFinalization();
224  TracingStatus NeedsTracing(NeedsTracingOption) {
225    if (is_root_)
226      return TracingStatus::Unneeded();
227    if (on_heap_)
228      return TracingStatus::Needed();
229    // For off-heap collections, determine tracing status of members.
230    TracingStatus status = TracingStatus::Unneeded();
231    for (Members::iterator it = members_.begin(); it != members_.end(); ++it) {
232      // Do a non-recursive test here since members could equal the holder.
233      status = status.LUB((*it)->NeedsTracing(kNonRecursive));
234    }
235    return status;
236  }
237
238 private:
239  RecordInfo* info_;
240  Members members_;
241  bool on_heap_;
242  bool is_root_;
243};
244
245#endif  // TOOLS_BLINK_GC_PLUGIN_EDGE_H_
246