// 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" || 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 IsOwnPtr(const std::string& name) { return name == "OwnPtr"; } static bool IsUniquePtr(const std::string& name) { return name == "unique_ptr"; } 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"; } // 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); } // 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, 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_