blob: ded4d843ad669c022b0cb7ac244542fd1a0f5244 [file] [log] [blame]
// 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.
// This file defines the names used by GC infrastructure.
// TODO: Restructure the name determination to use fully qualified names (ala,
// blink::Foo) so that the plugin can be enabled for all of chromium. Doing so
// would allow us to catch errors with structures outside of blink that might
// have unsafe pointers to GC allocated blink structures.
#ifndef TOOLS_BLINK_GC_PLUGIN_CONFIG_H_
#define TOOLS_BLINK_GC_PLUGIN_CONFIG_H_
#include <cassert>
#include "clang/AST/AST.h"
#include "clang/AST/Attr.h"
extern const char kNewOperatorName[];
extern const char kCreateName[];
extern const char kTraceName[];
extern const char kFinalizeName[];
extern const char kTraceAfterDispatchName[];
extern const char kRegisterWeakMembersName[];
extern const char kHeapAllocatorName[];
extern const char kTraceIfNeededName[];
extern const char kVisitorDispatcherName[];
extern const char kVisitorVarName[];
extern const char kAdjustAndMarkName[];
extern const char kIsHeapObjectAliveName[];
extern const char kIsEagerlyFinalizedName[];
extern const char kConstIteratorName[];
extern const char kIteratorName[];
extern const char kConstReverseIteratorName[];
extern const char kReverseIteratorName[];
class Config {
public:
static bool IsMember(const std::string& name) {
return name == "Member";
}
static bool IsWeakMember(const std::string& name) {
return name == "WeakMember";
}
static bool IsMemberHandle(const std::string& name) {
return IsMember(name) ||
IsWeakMember(name);
}
static bool IsPersistent(const std::string& name) {
return name == "Persistent" ||
name == "WeakPersistent" ;
}
static bool IsCrossThreadPersistent(const std::string& name) {
return name == "CrossThreadPersistent" ||
name == "CrossThreadWeakPersistent" ;
}
static bool IsRefPtr(const std::string& name) {
return name == "RefPtr";
}
static bool IsUniquePtr(const std::string& name) {
return name == "unique_ptr";
}
static bool IsTraceWrapperMember(const std::string& name) {
return name == "TraceWrapperMember";
}
static bool IsTraceWrapperV8Reference(const std::string& name) {
return name == "TraceWrapperV8Reference";
}
static bool IsWTFCollection(const std::string& name) {
return name == "Vector" ||
name == "Deque" ||
name == "HashSet" ||
name == "ListHashSet" ||
name == "LinkedHashSet" ||
name == "HashCountedSet" ||
name == "HashMap";
}
static bool IsGCCollection(const std::string& name) {
return name == "HeapVector" || name == "HeapDeque" ||
name == "HeapHashSet" || name == "HeapListHashSet" ||
name == "HeapLinkedHashSet" || name == "HeapHashCountedSet" ||
name == "HeapHashMap";
}
static bool IsGCCollectionWithUnsafeIterator(const std::string& name) {
if (!IsGCCollection(name))
return false;
// The list hash set iterators refer to the set, not the
// backing store and are consequently safe.
if (name == "HeapListHashSet" || name == "PersistentHeapListHashSet")
return false;
return true;
}
static bool IsHashMap(const std::string& name) {
return name == "HashMap" ||
name == "HeapHashMap" ||
name == "PersistentHeapHashMap";
}
// Assumes name is a valid collection name.
static size_t CollectionDimension(const std::string& name) {
return (IsHashMap(name) || name == "pair") ? 2 : 1;
}
static bool IsRefCountedBase(const std::string& name) {
return name == "RefCounted" ||
name == "ThreadSafeRefCounted";
}
static bool IsGCMixinBase(const std::string& name) {
return name == "GarbageCollectedMixin";
}
static bool IsGCFinalizedBase(const std::string& name) {
return name == "GarbageCollectedFinalized";
}
static bool IsGCBase(const std::string& name) {
return name == "GarbageCollected" ||
IsGCFinalizedBase(name) ||
IsGCMixinBase(name);
}
static bool IsIterator(const std::string& name) {
return name == kIteratorName || name == kConstIteratorName ||
name == kReverseIteratorName || name == kConstReverseIteratorName;
}
// Returns true of the base classes that do not need a vtable entry for trace
// because they cannot possibly initiate a GC during construction.
static bool IsSafePolymorphicBase(const std::string& name) {
return IsGCBase(name) || IsRefCountedBase(name);
}
static bool IsAnnotated(clang::Decl* decl, const std::string& anno) {
clang::AnnotateAttr* attr = decl->getAttr<clang::AnnotateAttr>();
return attr && (attr->getAnnotation() == anno);
}
static bool IsStackAnnotated(clang::Decl* decl) {
return IsAnnotated(decl, "blink_stack_allocated");
}
static bool IsIgnoreAnnotated(clang::Decl* decl) {
return IsAnnotated(decl, "blink_gc_plugin_ignore");
}
static bool IsIgnoreCycleAnnotated(clang::Decl* decl) {
return IsAnnotated(decl, "blink_gc_plugin_ignore_cycle") ||
IsIgnoreAnnotated(decl);
}
static bool IsVisitor(const std::string& name) {
return name == "Visitor" || name == "VisitorHelper";
}
static bool IsVisitorPtrType(const clang::QualType& formal_type) {
if (!formal_type->isPointerType())
return false;
clang::CXXRecordDecl* pointee_type =
formal_type->getPointeeType()->getAsCXXRecordDecl();
if (!pointee_type)
return false;
if (!IsVisitor(pointee_type->getName()))
return false;
return true;
}
static bool IsVisitorDispatcherType(const clang::QualType& formal_type) {
if (const clang::SubstTemplateTypeParmType* subst_type =
clang::dyn_cast<clang::SubstTemplateTypeParmType>(
formal_type.getTypePtr())) {
if (IsVisitorPtrType(subst_type->getReplacementType())) {
// VisitorDispatcher template parameter substituted to Visitor*.
return true;
}
} else if (const clang::TemplateTypeParmType* parm_type =
clang::dyn_cast<clang::TemplateTypeParmType>(
formal_type.getTypePtr())) {
if (parm_type->getDecl()->getName() == kVisitorDispatcherName) {
// Unresolved, but its parameter name is VisitorDispatcher.
return true;
}
}
return IsVisitorPtrType(formal_type);
}
enum TraceMethodType {
NOT_TRACE_METHOD,
TRACE_METHOD,
TRACE_AFTER_DISPATCH_METHOD,
};
static TraceMethodType GetTraceMethodType(const clang::FunctionDecl* method) {
if (method->getNumParams() != 1)
return NOT_TRACE_METHOD;
const std::string& name = method->getNameAsString();
if (name != kTraceName && name != kTraceAfterDispatchName)
return NOT_TRACE_METHOD;
const clang::QualType& formal_type = method->getParamDecl(0)->getType();
if (!IsVisitorPtrType(formal_type)) {
return NOT_TRACE_METHOD;
}
if (name == kTraceName)
return TRACE_METHOD;
if (name == kTraceAfterDispatchName)
return TRACE_AFTER_DISPATCH_METHOD;
assert(false && "Should not reach here");
return NOT_TRACE_METHOD;
}
static bool IsTraceMethod(const clang::FunctionDecl* method) {
return GetTraceMethodType(method) != NOT_TRACE_METHOD;
}
static bool IsTraceWrappersMethod(const clang::FunctionDecl* method);
static bool StartsWith(const std::string& str, const std::string& prefix) {
if (prefix.size() > str.size())
return false;
return str.compare(0, prefix.size(), prefix) == 0;
}
static bool EndsWith(const std::string& str, const std::string& suffix) {
if (suffix.size() > str.size())
return false;
return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
}
// Test if a template specialization is an instantiation.
static bool IsTemplateInstantiation(clang::CXXRecordDecl* record);
};
#endif // TOOLS_BLINK_GC_PLUGIN_CONFIG_H_