// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TOOLS_BLINK_GC_PLUGIN_EDGE_H_
#define TOOLS_BLINK_GC_PLUGIN_EDGE_H_
#include <deque>
#include "TracingStatus.h"
class RecordInfo;
class Edge;
class Value;
class RawPtr;
class RefPtr;
class OwnPtr;
class Member;
class WeakMember;
class Persistent;
class Collection;
// Bare-bones visitor.
class EdgeVisitor {
public:
virtual void VisitValue(Value*) {}
virtual void VisitRawPtr(RawPtr*) {}
virtual void VisitRefPtr(RefPtr*) {}
virtual void VisitOwnPtr(OwnPtr*) {}
virtual void VisitMember(Member*) {}
virtual void VisitWeakMember(WeakMember*) {}
virtual void VisitPersistent(Persistent*) {}
virtual void VisitCollection(Collection*) {}
};
// Recursive edge visitor. The traversed path is accessible in context.
class RecursiveEdgeVisitor : public EdgeVisitor {
public:
// Overrides that recursively walk the edges and record the path.
virtual void VisitValue(Value*) override;
virtual void VisitRawPtr(RawPtr*) override;
virtual void VisitRefPtr(RefPtr*) override;
virtual void VisitOwnPtr(OwnPtr*) override;
virtual void VisitMember(Member*) override;
virtual void VisitWeakMember(WeakMember*) override;
virtual void VisitPersistent(Persistent*) override;
virtual void VisitCollection(Collection*) override;
protected:
typedef std::deque<Edge*> Context;
Context& context() { return context_; }
Edge* Parent() { return context_.empty() ? 0 : context_.front(); }
void Enter(Edge* e) { return context_.push_front(e); }
void Leave() { context_.pop_front(); }
// Default callback to overwrite in visitor subclass.
virtual void AtValue(Value*);
virtual void AtRawPtr(RawPtr*);
virtual void AtRefPtr(RefPtr*);
virtual void AtOwnPtr(OwnPtr*);
virtual void AtMember(Member*);
virtual void AtWeakMember(WeakMember*);
virtual void AtPersistent(Persistent*);
virtual void AtCollection(Collection*);
private:
Context context_;
};
// Base class for all edges.
class Edge {
public:
enum NeedsTracingOption { kRecursive, kNonRecursive };
enum LivenessKind { kWeak, kStrong, kRoot };
virtual ~Edge() {}
virtual LivenessKind Kind() = 0;
virtual void Accept(EdgeVisitor*) = 0;
virtual bool NeedsFinalization() = 0;
virtual TracingStatus NeedsTracing(NeedsTracingOption) {
return TracingStatus::Unknown();
}
virtual bool IsValue() { return false; }
virtual bool IsRawPtr() { return false; }
virtual bool IsRawPtrClass() { return false; }
virtual bool IsRefPtr() { return false; }
virtual bool IsOwnPtr() { return false; }
virtual bool IsMember() { return false; }
virtual bool IsWeakMember() { return false; }
virtual bool IsPersistent() { return false; }
virtual bool IsCollection() { return false; }
};
// A value edge is a direct edge to some type, eg, part-object edges.
class Value : public Edge {
public:
explicit Value(RecordInfo* value) : value_(value) {};
bool IsValue() override { return true; }
LivenessKind Kind() override { return kStrong; }
bool NeedsFinalization() override;
TracingStatus NeedsTracing(NeedsTracingOption) override;
void Accept(EdgeVisitor* visitor) override { visitor->VisitValue(this); }
RecordInfo* value() { return value_; }
private:
RecordInfo* value_;
};
// Shared base for smart-pointer edges.
class PtrEdge : public Edge {
public:
~PtrEdge() { delete ptr_; }
Edge* ptr() { return ptr_; }
protected:
PtrEdge(Edge* ptr) : ptr_(ptr) {
assert(ptr && "EdgePtr pointer must be non-null");
}
private:
Edge* ptr_;
};
class RawPtr : public PtrEdge {
public:
explicit RawPtr(Edge* ptr, bool is_ptr_class)
: PtrEdge(ptr), is_ptr_class_(is_ptr_class) { }
bool IsRawPtr() { return true; }
bool IsRawPtrClass() { return is_ptr_class_; }
LivenessKind Kind() { return kWeak; }
bool NeedsFinalization() { return false; }
TracingStatus NeedsTracing(NeedsTracingOption) {
return TracingStatus::Unneeded();
}
void Accept(EdgeVisitor* visitor) { visitor->VisitRawPtr(this); }
private:
bool is_ptr_class_;
};
class RefPtr : public PtrEdge {
public:
explicit RefPtr(Edge* ptr) : PtrEdge(ptr) { }
bool IsRefPtr() { return true; }
LivenessKind Kind() { return kStrong; }
bool NeedsFinalization() { return true; }
TracingStatus NeedsTracing(NeedsTracingOption) {
return TracingStatus::Unneeded();
}
void Accept(EdgeVisitor* visitor) { visitor->VisitRefPtr(this); }
};
class OwnPtr : public PtrEdge {
public:
explicit OwnPtr(Edge* ptr) : PtrEdge(ptr) { }
bool IsOwnPtr() { return true; }
LivenessKind Kind() { return kStrong; }
bool NeedsFinalization() { return true; }
TracingStatus NeedsTracing(NeedsTracingOption) {
return TracingStatus::Unneeded();
}
void Accept(EdgeVisitor* visitor) { visitor->VisitOwnPtr(this); }
};
class Member : public PtrEdge {
public:
explicit Member(Edge* ptr) : PtrEdge(ptr) { }
bool IsMember() { return true; }
LivenessKind Kind() { return kStrong; }
bool NeedsFinalization() { return false; }
TracingStatus NeedsTracing(NeedsTracingOption) {
return TracingStatus::Needed();
}
void Accept(EdgeVisitor* visitor) { visitor->VisitMember(this); }
};
class WeakMember : public PtrEdge {
public:
explicit WeakMember(Edge* ptr) : PtrEdge(ptr) { }
bool IsWeakMember() { return true; }
LivenessKind Kind() { return kWeak; }
bool NeedsFinalization() { return false; }
TracingStatus NeedsTracing(NeedsTracingOption) {
return TracingStatus::Needed();
}
void Accept(EdgeVisitor* visitor) { visitor->VisitWeakMember(this); }
};
class Persistent : public PtrEdge {
public:
explicit Persistent(Edge* ptr) : PtrEdge(ptr) { }
bool IsPersistent() { return true; }
LivenessKind Kind() { return kRoot; }
bool NeedsFinalization() { return true; }
TracingStatus NeedsTracing(NeedsTracingOption) {
return TracingStatus::Unneeded();
}
void Accept(EdgeVisitor* visitor) { visitor->VisitPersistent(this); }
};
class Collection : public Edge {
public:
typedef std::vector<Edge*> Members;
Collection(RecordInfo* info, bool on_heap, bool is_root)
: info_(info),
on_heap_(on_heap),
is_root_(is_root) {}
~Collection() {
for (Members::iterator it = members_.begin(); it != members_.end(); ++it) {
assert(*it && "Collection-edge members must be non-null");
delete *it;
}
}
bool IsCollection() { return true; }
LivenessKind Kind() { return is_root_ ? kRoot : kStrong; }
bool on_heap() { return on_heap_; }
bool is_root() { return is_root_; }
Members& members() { return members_; }
void Accept(EdgeVisitor* visitor) { visitor->VisitCollection(this); }
void AcceptMembers(EdgeVisitor* visitor) {
for (Members::iterator it = members_.begin(); it != members_.end(); ++it)
(*it)->Accept(visitor);
}
bool NeedsFinalization();
TracingStatus NeedsTracing(NeedsTracingOption) {
if (is_root_)
return TracingStatus::Unneeded();
if (on_heap_)
return TracingStatus::Needed();
// For off-heap collections, determine tracing status of members.
TracingStatus status = TracingStatus::Unneeded();
for (Members::iterator it = members_.begin(); it != members_.end(); ++it) {
// Do a non-recursive test here since members could equal the holder.
status = status.LUB((*it)->NeedsTracing(kNonRecursive));
}
return status;
}
private:
RecordInfo* info_;
Members members_;
bool on_heap_;
bool is_root_;
};
#endif // TOOLS_BLINK_GC_PLUGIN_EDGE_H_