#include <map>
#include <vector>
+#include "Edge.h"
+
#include "clang/AST/AST.h"
#include "clang/AST/CXXInheritance.h"
class RecordCache;
-// Value to track the tracing status of a point in the tracing graph.
-// (Points that might need tracing are fields and base classes.)
-class TracingStatus {
+// A potentially tracable and/or lifetime affecting point in the object graph.
+class GraphPoint {
public:
- static TracingStatus Unknown() { return kUnknown; }
- static TracingStatus Required() { return kRequired; }
- static TracingStatus Unneeded() { return kUnneeded; }
- static TracingStatus RequiredWeak() {
- return TracingStatus(kRequired, true);
- }
+ GraphPoint() : traced_(false) {}
+ void MarkTraced() { traced_ = true; }
+ bool IsProperlyTraced() { return traced_ || !NeedsTracing().IsNeeded(); }
+ virtual const TracingStatus NeedsTracing() = 0;
+
+ private:
+ bool traced_;
+};
- bool IsTracingUnknown() const { return status_ == kUnknown; }
- bool IsTracingRequired() const { return status_ == kRequired; }
- bool IsTracingUnneeded() const { return status_ == kUnneeded; }
+class BasePoint : public GraphPoint {
+ public:
+ BasePoint(const clang::CXXBaseSpecifier& spec,
+ RecordInfo* info,
+ const TracingStatus& status)
+ : spec_(spec), info_(info), status_(status) {}
+ const TracingStatus NeedsTracing() { return status_; }
+ // Needed to change the status of bases with a pure-virtual trace.
+ void MarkUnneeded() { status_ = TracingStatus::Unneeded(); }
+ const clang::CXXBaseSpecifier& spec() { return spec_; }
+ RecordInfo* info() { return info_; }
- // Updating functions so the status can only become more defined.
- void MarkTracingRequired() {
- if (status_ < kRequired) status_ = kRequired;
- }
- void MarkTracingUnneeded() {
- if (status_ < kUnneeded) status_ = kUnneeded;
- }
+ private:
+ const clang::CXXBaseSpecifier& spec_;
+ RecordInfo* info_;
+ TracingStatus status_;
+};
- bool is_weak() { return is_weak_; }
+class FieldPoint : public GraphPoint {
+ public:
+ FieldPoint(clang::FieldDecl* field, Edge* edge)
+ : field_(field), edge_(edge) {}
+ const TracingStatus NeedsTracing() {
+ return edge_->NeedsTracing(Edge::kRecursive);
+ }
+ clang::FieldDecl* field() { return field_; }
+ Edge* edge() { return edge_; }
private:
- enum Status {
- kUnknown, // Point that might need to be traced.
- kRequired, // Point that must be traced.
- kUnneeded // Point that need not be traced.
- };
-
- TracingStatus(Status status)
- : status_(status),
- is_weak_(false) { }
-
- TracingStatus(Status status, bool is_weak)
- : status_(status),
- is_weak_(is_weak) { }
-
- Status status_;
- bool is_weak_;
+ clang::FieldDecl* field_;
+ Edge* edge_;
+
+ friend class RecordCache;
+ void deleteEdge() { delete edge_; }
};
// Wrapper class to lazily collect information about a C++ record.
class RecordInfo {
-public:
- typedef std::map<clang::CXXRecordDecl*, TracingStatus> Bases;
- typedef std::map<clang::FieldDecl*, TracingStatus> Fields;
- typedef std::vector<RecordInfo*> TemplateArgs;
-
- enum NeedsTracingOption {
- kRecursive,
- kNonRecursive
- };
+ public:
+ typedef std::map<clang::CXXRecordDecl*, BasePoint> Bases;
+ typedef std::map<clang::FieldDecl*, FieldPoint> Fields;
+ typedef std::vector<const clang::Type*> TemplateArgs;
~RecordInfo();
Bases& GetBases();
clang::CXXMethodDecl* GetTraceMethod();
clang::CXXMethodDecl* GetTraceDispatchMethod();
+ clang::CXXMethodDecl* GetFinalizeDispatchMethod();
- bool IsTemplate(TemplateArgs* args = 0);
-
- bool IsHeapAllocatedCollection(bool* is_weak = 0);
- bool IsGCDerived(clang::CXXBasePaths* paths = 0);
+ bool GetTemplateArgs(size_t count, TemplateArgs* output_args);
+ bool IsHeapAllocatedCollection();
+ bool IsGCDerived();
+ bool IsGCAllocated();
+ bool IsGCFinalized();
+ bool IsGCMixin();
+ bool IsStackAllocated();
bool IsNonNewable();
+ bool IsOnlyPlacementNewable();
+ bool IsTreeShared();
+ clang::CXXMethodDecl* DeclaresNewOperator();
+
bool RequiresTraceMethod();
- TracingStatus NeedsTracing(NeedsTracingOption option = kRecursive);
+ bool NeedsFinalization();
+ TracingStatus NeedsTracing(Edge::NeedsTracingOption);
+ clang::CXXMethodDecl* InheritsNonVirtualTrace();
+ bool IsConsideredAbstract();
-private:
+ private:
RecordInfo(clang::CXXRecordDecl* record, RecordCache* cache);
Fields* CollectFields();
Bases* CollectBases();
void DetermineTracingMethods();
+ bool InheritsNonPureTrace();
- TracingStatus NeedsTracing(clang::FieldDecl* field);
+ Edge* CreateEdge(const clang::Type* type);
RecordCache* cache_;
clang::CXXRecordDecl* record_;
const std::string name_;
- bool requires_trace_method_;
+ TracingStatus fields_need_tracing_;
Bases* bases_;
Fields* fields_;
+ enum CachedBool { kFalse = 0, kTrue = 1, kNotComputed = 2 };
+ CachedBool is_stack_allocated_;
+ CachedBool is_non_newable_;
+ CachedBool is_only_placement_newable_;
+
bool determined_trace_methods_;
clang::CXXMethodDecl* trace_method_;
clang::CXXMethodDecl* trace_dispatch_method_;
+ clang::CXXMethodDecl* finalize_dispatch_method_;
+
+ bool is_gc_derived_;
+ clang::CXXBasePaths* base_paths_;
friend class RecordCache;
};
class RecordCache {
-public:
- RecordInfo* Lookup(clang::CXXRecordDecl* record) {
- if (!record) return 0;
- Cache::iterator it = cache_.find(record);
- if (it != cache_.end())
- return &it->second;
- return &cache_.insert(std::make_pair(record, RecordInfo(record, this)))
- .first->second;
- }
+ public:
+ RecordInfo* Lookup(clang::CXXRecordDecl* record);
RecordInfo* Lookup(const clang::CXXRecordDecl* record) {
return Lookup(const_cast<clang::CXXRecordDecl*>(record));
}
-private:
+ RecordInfo* Lookup(clang::DeclContext* decl) {
+ return Lookup(clang::dyn_cast<clang::CXXRecordDecl>(decl));
+ }
+
+ RecordInfo* Lookup(const clang::Type* type) {
+ return Lookup(type->getAsCXXRecordDecl());
+ }
+
+ RecordInfo* Lookup(const clang::QualType& type) {
+ return Lookup(type.getTypePtr());
+ }
+
+ ~RecordCache() {
+ for (Cache::iterator it = cache_.begin(); it != cache_.end(); ++it) {
+ if (!it->second.fields_)
+ continue;
+ for (RecordInfo::Fields::iterator fit = it->second.fields_->begin();
+ fit != it->second.fields_->end();
+ ++fit) {
+ fit->second.deleteEdge();
+ }
+ }
+ }
+
+ private:
typedef std::map<clang::CXXRecordDecl*, RecordInfo> Cache;
Cache cache_;
};
-#endif // TOOLS_BLINK_GC_PLUGIN_RECORD_INFO_H_
+#endif // TOOLS_BLINK_GC_PLUGIN_RECORD_INFO_H_