| Index: tools/clang/blink_gc_plugin/Config.h
|
| diff --git a/tools/clang/blink_gc_plugin/Config.h b/tools/clang/blink_gc_plugin/Config.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c62de053306072539003ef93baead1c3dd3a13db
|
| --- /dev/null
|
| +++ b/tools/clang/blink_gc_plugin/Config.h
|
| @@ -0,0 +1,272 @@
|
| +// 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"
|
| +
|
| +const char kNewOperatorName[] = "operator new";
|
| +const char kCreateName[] = "create";
|
| +const char kTraceName[] = "trace";
|
| +const char kTraceImplName[] = "traceImpl";
|
| +const char kFinalizeName[] = "finalizeGarbageCollectedObject";
|
| +const char kTraceAfterDispatchName[] = "traceAfterDispatch";
|
| +const char kTraceAfterDispatchImplName[] = "traceAfterDispatchImpl";
|
| +const char kRegisterWeakMembersName[] = "registerWeakMembers";
|
| +const char kHeapAllocatorName[] = "HeapAllocator";
|
| +const char kTraceIfNeededName[] = "TraceIfNeeded";
|
| +const char kVisitorDispatcherName[] = "VisitorDispatcher";
|
| +const char kVisitorVarName[] = "visitor";
|
| +const char kAdjustAndMarkName[] = "adjustAndMark";
|
| +const char kIsHeapObjectAliveName[] = "isHeapObjectAlive";
|
| +const char kIsEagerlyFinalizedName[] = "IsEagerlyFinalizedMarker";
|
| +
|
| +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";
|
| + }
|
| +
|
| + static bool IsPersistentHandle(const std::string& name) {
|
| + return IsPersistent(name) ||
|
| + IsPersistentGCCollection(name);
|
| + }
|
| +
|
| + static bool IsRawPtr(const std::string& name) {
|
| + return name == "RawPtr";
|
| + }
|
| +
|
| + static bool IsRefPtr(const std::string& name) {
|
| + return name == "RefPtr";
|
| + }
|
| +
|
| + static bool IsOwnPtr(const std::string& name) {
|
| + return name == "OwnPtr";
|
| + }
|
| +
|
| + 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" ||
|
| + IsPersistentGCCollection(name);
|
| + }
|
| +
|
| + static bool IsPersistentGCCollection(const std::string& name) {
|
| + return name == "PersistentHeapVector" ||
|
| + name == "PersistentHeapDeque" ||
|
| + name == "PersistentHeapHashSet" ||
|
| + name == "PersistentHeapListHashSet" ||
|
| + name == "PersistentHeapLinkedHashSet" ||
|
| + name == "PersistentHeapHashCountedSet" ||
|
| + name == "PersistentHeapHashMap";
|
| + }
|
| +
|
| + static bool IsHashMap(const std::string& name) {
|
| + return name == "HashMap" ||
|
| + name == "HeapHashMap" ||
|
| + name == "PersistentHeapHashMap";
|
| + }
|
| +
|
| + // Following http://crrev.com/369633033 (Blink r177436),
|
| + // ignore blink::ScriptWrappable's destructor.
|
| + // TODO: remove when its non-Oilpan destructor is removed.
|
| + static bool HasIgnorableDestructor(const std::string& ns,
|
| + const std::string& name) {
|
| + return ns == "blink" && name == "ScriptWrappable";
|
| + }
|
| +
|
| + // Assumes name is a valid collection name.
|
| + static size_t CollectionDimension(const std::string& name) {
|
| + return (IsHashMap(name) || name == "pair") ? 2 : 1;
|
| + }
|
| +
|
| + static bool IsDummyBase(const std::string& name) {
|
| + return name == "DummyBase";
|
| + }
|
| +
|
| + 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" ||
|
| + name == "RefCountedGarbageCollected" ||
|
| + name == "ThreadSafeRefCountedGarbageCollected";
|
| + }
|
| +
|
| + static bool IsGCBase(const std::string& name) {
|
| + return name == "GarbageCollected" ||
|
| + IsGCFinalizedBase(name) ||
|
| + IsGCMixinBase(name);
|
| + }
|
| +
|
| + // 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) || IsDummyBase(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,
|
| + TRACE_IMPL_METHOD,
|
| + TRACE_AFTER_DISPATCH_IMPL_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 &&
|
| + name != kTraceImplName && name != kTraceAfterDispatchImplName)
|
| + return NOT_TRACE_METHOD;
|
| +
|
| + const clang::QualType& formal_type = method->getParamDecl(0)->getType();
|
| + if (name == kTraceImplName || name == kTraceAfterDispatchImplName) {
|
| + if (!IsVisitorDispatcherType(formal_type))
|
| + return NOT_TRACE_METHOD;
|
| + } else if (!IsVisitorPtrType(formal_type)) {
|
| + return NOT_TRACE_METHOD;
|
| + }
|
| +
|
| + if (name == kTraceName)
|
| + return TRACE_METHOD;
|
| + if (name == kTraceAfterDispatchName)
|
| + return TRACE_AFTER_DISPATCH_METHOD;
|
| + if (name == kTraceImplName)
|
| + return TRACE_IMPL_METHOD;
|
| + if (name == kTraceAfterDispatchImplName)
|
| + return TRACE_AFTER_DISPATCH_IMPL_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 IsTraceImplName(const std::string& name) {
|
| + return name == kTraceImplName || name == kTraceAfterDispatchImplName;
|
| + }
|
| +
|
| + 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_
|
|
|