Home | History | Annotate | Download | only in blink_gc_plugin
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // This file defines the names used by GC infrastructure.
      6 
      7 // TODO: Restructure the name determination to use fully qualified names (ala,
      8 // blink::Foo) so that the plugin can be enabled for all of chromium. Doing so
      9 // would allow us to catch errors with structures outside of blink that might
     10 // have unsafe pointers to GC allocated blink structures.
     11 
     12 #ifndef TOOLS_BLINK_GC_PLUGIN_CONFIG_H_
     13 #define TOOLS_BLINK_GC_PLUGIN_CONFIG_H_
     14 
     15 #include <cassert>
     16 
     17 #include "clang/AST/AST.h"
     18 #include "clang/AST/Attr.h"
     19 
     20 extern const char kNewOperatorName[];
     21 extern const char* kCreateName;
     22 extern const char* kTraceName;
     23 extern const char* kTraceImplName;
     24 extern const char* kFinalizeName;
     25 extern const char* kTraceAfterDispatchName;
     26 extern const char* kTraceAfterDispatchImplName;
     27 extern const char* kRegisterWeakMembersName;
     28 extern const char kHeapAllocatorName[];
     29 extern const char kTraceIfNeededName[];
     30 extern const char kVisitorDispatcherName[];
     31 extern const char kVisitorVarName[];
     32 extern const char* kAdjustAndMarkName;
     33 extern const char* kIsHeapObjectAliveName;
     34 extern const char kIsEagerlyFinalizedName[];
     35 extern const char kConstIteratorName[];
     36 extern const char kIteratorName[];
     37 extern const char kConstReverseIteratorName[];
     38 extern const char kReverseIteratorName[];
     39 
     40 class Config {
     41  public:
     42   static void UseLegacyNames();
     43 
     44   static bool IsMember(const std::string& name) {
     45     return name == "Member";
     46   }
     47 
     48   static bool IsWeakMember(const std::string& name) {
     49     return name == "WeakMember";
     50   }
     51 
     52   static bool IsMemberHandle(const std::string& name) {
     53     return IsMember(name) ||
     54            IsWeakMember(name);
     55   }
     56 
     57   static bool IsPersistent(const std::string& name) {
     58     return name == "Persistent" ||
     59            name == "WeakPersistent" ;
     60   }
     61 
     62   static bool IsCrossThreadPersistent(const std::string& name) {
     63     return name == "CrossThreadPersistent" ||
     64            name == "CrossThreadWeakPersistent" ;
     65   }
     66 
     67   static bool IsRefPtr(const std::string& name) {
     68     return name == "RefPtr";
     69   }
     70 
     71   static bool IsOwnPtr(const std::string& name) {
     72     return name == "OwnPtr";
     73   }
     74 
     75   static bool IsUniquePtr(const std::string& name) {
     76     return name == "unique_ptr";
     77   }
     78 
     79   static bool IsWTFCollection(const std::string& name) {
     80     return name == "Vector" ||
     81            name == "Deque" ||
     82            name == "HashSet" ||
     83            name == "ListHashSet" ||
     84            name == "LinkedHashSet" ||
     85            name == "HashCountedSet" ||
     86            name == "HashMap";
     87   }
     88 
     89   static bool IsGCCollection(const std::string& name) {
     90     return name == "HeapVector" ||
     91            name == "HeapDeque" ||
     92            name == "HeapHashSet" ||
     93            name == "HeapListHashSet" ||
     94            name == "HeapLinkedHashSet" ||
     95            name == "HeapHashCountedSet" ||
     96            name == "HeapHashMap" ||
     97            IsPersistentGCCollection(name);
     98   }
     99 
    100   static bool IsPersistentGCCollection(const std::string& name) {
    101     return name == "PersistentHeapVector" ||
    102            name == "PersistentHeapDeque" ||
    103            name == "PersistentHeapHashSet" ||
    104            name == "PersistentHeapListHashSet" ||
    105            name == "PersistentHeapLinkedHashSet" ||
    106            name == "PersistentHeapHashCountedSet" ||
    107            name == "PersistentHeapHashMap";
    108   }
    109 
    110   static bool IsGCCollectionWithUnsafeIterator(const std::string& name) {
    111     if (!IsGCCollection(name))
    112       return false;
    113     // The list hash set iterators refer to the set, not the
    114     // backing store and are consequently safe.
    115     if (name == "HeapListHashSet" || name == "PersistentHeapListHashSet")
    116       return false;
    117     return true;
    118   }
    119 
    120   static bool IsHashMap(const std::string& name) {
    121     return name == "HashMap" ||
    122            name == "HeapHashMap" ||
    123            name == "PersistentHeapHashMap";
    124   }
    125 
    126   // Assumes name is a valid collection name.
    127   static size_t CollectionDimension(const std::string& name) {
    128     return (IsHashMap(name) || name == "pair") ? 2 : 1;
    129   }
    130 
    131   static bool IsRefCountedBase(const std::string& name) {
    132     return name == "RefCounted" ||
    133            name == "ThreadSafeRefCounted";
    134   }
    135 
    136   static bool IsGCMixinBase(const std::string& name) {
    137     return name == "GarbageCollectedMixin";
    138   }
    139 
    140   static bool IsGCFinalizedBase(const std::string& name) {
    141     return name == "GarbageCollectedFinalized";
    142   }
    143 
    144   static bool IsGCBase(const std::string& name) {
    145     return name == "GarbageCollected" ||
    146            IsGCFinalizedBase(name) ||
    147            IsGCMixinBase(name);
    148   }
    149 
    150   static bool IsIterator(const std::string& name) {
    151     return name == kIteratorName || name == kConstIteratorName ||
    152            name == kReverseIteratorName || name == kConstReverseIteratorName;
    153   }
    154 
    155   // Returns true of the base classes that do not need a vtable entry for trace
    156   // because they cannot possibly initiate a GC during construction.
    157   static bool IsSafePolymorphicBase(const std::string& name) {
    158     return IsGCBase(name) || IsRefCountedBase(name);
    159   }
    160 
    161   static bool IsAnnotated(clang::Decl* decl, const std::string& anno) {
    162     clang::AnnotateAttr* attr = decl->getAttr<clang::AnnotateAttr>();
    163     return attr && (attr->getAnnotation() == anno);
    164   }
    165 
    166   static bool IsStackAnnotated(clang::Decl* decl) {
    167     return IsAnnotated(decl, "blink_stack_allocated");
    168   }
    169 
    170   static bool IsIgnoreAnnotated(clang::Decl* decl) {
    171     return IsAnnotated(decl, "blink_gc_plugin_ignore");
    172   }
    173 
    174   static bool IsIgnoreCycleAnnotated(clang::Decl* decl) {
    175     return IsAnnotated(decl, "blink_gc_plugin_ignore_cycle") ||
    176            IsIgnoreAnnotated(decl);
    177   }
    178 
    179   static bool IsVisitor(const std::string& name) {
    180     return name == "Visitor" || name == "VisitorHelper";
    181   }
    182 
    183   static bool IsVisitorPtrType(const clang::QualType& formal_type) {
    184     if (!formal_type->isPointerType())
    185       return false;
    186 
    187     clang::CXXRecordDecl* pointee_type =
    188         formal_type->getPointeeType()->getAsCXXRecordDecl();
    189     if (!pointee_type)
    190       return false;
    191 
    192     if (!IsVisitor(pointee_type->getName()))
    193       return false;
    194 
    195     return true;
    196   }
    197 
    198   static bool IsVisitorDispatcherType(const clang::QualType& formal_type) {
    199     if (const clang::SubstTemplateTypeParmType* subst_type =
    200             clang::dyn_cast<clang::SubstTemplateTypeParmType>(
    201                 formal_type.getTypePtr())) {
    202       if (IsVisitorPtrType(subst_type->getReplacementType())) {
    203         // VisitorDispatcher template parameter substituted to Visitor*.
    204         return true;
    205       }
    206     } else if (const clang::TemplateTypeParmType* parm_type =
    207                    clang::dyn_cast<clang::TemplateTypeParmType>(
    208                        formal_type.getTypePtr())) {
    209       if (parm_type->getDecl()->getName() == kVisitorDispatcherName) {
    210         // Unresolved, but its parameter name is VisitorDispatcher.
    211         return true;
    212       }
    213     }
    214 
    215     return IsVisitorPtrType(formal_type);
    216   }
    217 
    218   enum TraceMethodType {
    219     NOT_TRACE_METHOD,
    220     TRACE_METHOD,
    221     TRACE_AFTER_DISPATCH_METHOD,
    222     TRACE_IMPL_METHOD,
    223     TRACE_AFTER_DISPATCH_IMPL_METHOD
    224   };
    225 
    226   static TraceMethodType GetTraceMethodType(const clang::FunctionDecl* method) {
    227     if (method->getNumParams() != 1)
    228       return NOT_TRACE_METHOD;
    229 
    230     const std::string& name = method->getNameAsString();
    231     if (name != kTraceName && name != kTraceAfterDispatchName &&
    232         name != kTraceImplName && name != kTraceAfterDispatchImplName)
    233       return NOT_TRACE_METHOD;
    234 
    235     const clang::QualType& formal_type = method->getParamDecl(0)->getType();
    236     if (name == kTraceImplName || name == kTraceAfterDispatchImplName) {
    237       if (!IsVisitorDispatcherType(formal_type))
    238         return NOT_TRACE_METHOD;
    239     } else if (!IsVisitorPtrType(formal_type)) {
    240       return NOT_TRACE_METHOD;
    241     }
    242 
    243     if (name == kTraceName)
    244       return TRACE_METHOD;
    245     if (name == kTraceAfterDispatchName)
    246       return TRACE_AFTER_DISPATCH_METHOD;
    247     if (name == kTraceImplName)
    248       return TRACE_IMPL_METHOD;
    249     if (name == kTraceAfterDispatchImplName)
    250       return TRACE_AFTER_DISPATCH_IMPL_METHOD;
    251 
    252     assert(false && "Should not reach here");
    253     return NOT_TRACE_METHOD;
    254   }
    255 
    256   static bool IsTraceMethod(const clang::FunctionDecl* method) {
    257     return GetTraceMethodType(method) != NOT_TRACE_METHOD;
    258   }
    259 
    260   static bool IsTraceImplName(const std::string& name) {
    261     return name == kTraceImplName || name == kTraceAfterDispatchImplName;
    262   }
    263 
    264   static bool StartsWith(const std::string& str, const std::string& prefix) {
    265     if (prefix.size() > str.size())
    266       return false;
    267     return str.compare(0, prefix.size(), prefix) == 0;
    268   }
    269 
    270   static bool EndsWith(const std::string& str, const std::string& suffix) {
    271     if (suffix.size() > str.size())
    272       return false;
    273     return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
    274   }
    275 
    276   // Test if a template specialization is an instantiation.
    277   static bool IsTemplateInstantiation(clang::CXXRecordDecl* record);
    278 };
    279 
    280 #endif  // TOOLS_BLINK_GC_PLUGIN_CONFIG_H_
    281