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 kFinalizeName[];
     24 extern const char kTraceAfterDispatchName[];
     25 extern const char kRegisterWeakMembersName[];
     26 extern const char kHeapAllocatorName[];
     27 extern const char kTraceIfNeededName[];
     28 extern const char kVisitorDispatcherName[];
     29 extern const char kVisitorVarName[];
     30 extern const char kAdjustAndMarkName[];
     31 extern const char kIsHeapObjectAliveName[];
     32 extern const char kIsEagerlyFinalizedName[];
     33 extern const char kConstIteratorName[];
     34 extern const char kIteratorName[];
     35 extern const char kConstReverseIteratorName[];
     36 extern const char kReverseIteratorName[];
     37 
     38 class Config {
     39  public:
     40   static bool IsMember(const std::string& name) {
     41     return name == "Member";
     42   }
     43 
     44   static bool IsWeakMember(const std::string& name) {
     45     return name == "WeakMember";
     46   }
     47 
     48   static bool IsMemberHandle(const std::string& name) {
     49     return IsMember(name) ||
     50            IsWeakMember(name);
     51   }
     52 
     53   static bool IsPersistent(const std::string& name) {
     54     return name == "Persistent" ||
     55            name == "WeakPersistent" ;
     56   }
     57 
     58   static bool IsCrossThreadPersistent(const std::string& name) {
     59     return name == "CrossThreadPersistent" ||
     60            name == "CrossThreadWeakPersistent" ;
     61   }
     62 
     63   static bool IsRefPtr(const std::string& name) {
     64     return name == "RefPtr";
     65   }
     66 
     67   static bool IsUniquePtr(const std::string& name) {
     68     return name == "unique_ptr";
     69   }
     70 
     71   static bool IsWTFCollection(const std::string& name) {
     72     return name == "Vector" ||
     73            name == "Deque" ||
     74            name == "HashSet" ||
     75            name == "ListHashSet" ||
     76            name == "LinkedHashSet" ||
     77            name == "HashCountedSet" ||
     78            name == "HashMap";
     79   }
     80 
     81   static bool IsGCCollection(const std::string& name) {
     82     return name == "HeapVector" ||
     83            name == "HeapDeque" ||
     84            name == "HeapHashSet" ||
     85            name == "HeapListHashSet" ||
     86            name == "HeapLinkedHashSet" ||
     87            name == "HeapHashCountedSet" ||
     88            name == "HeapHashMap" ||
     89            IsPersistentGCCollection(name);
     90   }
     91 
     92   static bool IsPersistentGCCollection(const std::string& name) {
     93     return name == "PersistentHeapVector" ||
     94            name == "PersistentHeapDeque" ||
     95            name == "PersistentHeapHashSet" ||
     96            name == "PersistentHeapListHashSet" ||
     97            name == "PersistentHeapLinkedHashSet" ||
     98            name == "PersistentHeapHashCountedSet" ||
     99            name == "PersistentHeapHashMap";
    100   }
    101 
    102   static bool IsGCCollectionWithUnsafeIterator(const std::string& name) {
    103     if (!IsGCCollection(name))
    104       return false;
    105     // The list hash set iterators refer to the set, not the
    106     // backing store and are consequently safe.
    107     if (name == "HeapListHashSet" || name == "PersistentHeapListHashSet")
    108       return false;
    109     return true;
    110   }
    111 
    112   static bool IsHashMap(const std::string& name) {
    113     return name == "HashMap" ||
    114            name == "HeapHashMap" ||
    115            name == "PersistentHeapHashMap";
    116   }
    117 
    118   // Assumes name is a valid collection name.
    119   static size_t CollectionDimension(const std::string& name) {
    120     return (IsHashMap(name) || name == "pair") ? 2 : 1;
    121   }
    122 
    123   static bool IsRefCountedBase(const std::string& name) {
    124     return name == "RefCounted" ||
    125            name == "ThreadSafeRefCounted";
    126   }
    127 
    128   static bool IsGCMixinBase(const std::string& name) {
    129     return name == "GarbageCollectedMixin";
    130   }
    131 
    132   static bool IsGCFinalizedBase(const std::string& name) {
    133     return name == "GarbageCollectedFinalized";
    134   }
    135 
    136   static bool IsGCBase(const std::string& name) {
    137     return name == "GarbageCollected" ||
    138            IsGCFinalizedBase(name) ||
    139            IsGCMixinBase(name);
    140   }
    141 
    142   static bool IsIterator(const std::string& name) {
    143     return name == kIteratorName || name == kConstIteratorName ||
    144            name == kReverseIteratorName || name == kConstReverseIteratorName;
    145   }
    146 
    147   // Returns true of the base classes that do not need a vtable entry for trace
    148   // because they cannot possibly initiate a GC during construction.
    149   static bool IsSafePolymorphicBase(const std::string& name) {
    150     return IsGCBase(name) || IsRefCountedBase(name);
    151   }
    152 
    153   static bool IsAnnotated(clang::Decl* decl, const std::string& anno) {
    154     clang::AnnotateAttr* attr = decl->getAttr<clang::AnnotateAttr>();
    155     return attr && (attr->getAnnotation() == anno);
    156   }
    157 
    158   static bool IsStackAnnotated(clang::Decl* decl) {
    159     return IsAnnotated(decl, "blink_stack_allocated");
    160   }
    161 
    162   static bool IsIgnoreAnnotated(clang::Decl* decl) {
    163     return IsAnnotated(decl, "blink_gc_plugin_ignore");
    164   }
    165 
    166   static bool IsIgnoreCycleAnnotated(clang::Decl* decl) {
    167     return IsAnnotated(decl, "blink_gc_plugin_ignore_cycle") ||
    168            IsIgnoreAnnotated(decl);
    169   }
    170 
    171   static bool IsVisitor(const std::string& name) {
    172     return name == "Visitor" || name == "VisitorHelper";
    173   }
    174 
    175   static bool IsVisitorPtrType(const clang::QualType& formal_type) {
    176     if (!formal_type->isPointerType())
    177       return false;
    178 
    179     clang::CXXRecordDecl* pointee_type =
    180         formal_type->getPointeeType()->getAsCXXRecordDecl();
    181     if (!pointee_type)
    182       return false;
    183 
    184     if (!IsVisitor(pointee_type->getName()))
    185       return false;
    186 
    187     return true;
    188   }
    189 
    190   static bool IsVisitorDispatcherType(const clang::QualType& formal_type) {
    191     if (const clang::SubstTemplateTypeParmType* subst_type =
    192             clang::dyn_cast<clang::SubstTemplateTypeParmType>(
    193                 formal_type.getTypePtr())) {
    194       if (IsVisitorPtrType(subst_type->getReplacementType())) {
    195         // VisitorDispatcher template parameter substituted to Visitor*.
    196         return true;
    197       }
    198     } else if (const clang::TemplateTypeParmType* parm_type =
    199                    clang::dyn_cast<clang::TemplateTypeParmType>(
    200                        formal_type.getTypePtr())) {
    201       if (parm_type->getDecl()->getName() == kVisitorDispatcherName) {
    202         // Unresolved, but its parameter name is VisitorDispatcher.
    203         return true;
    204       }
    205     }
    206 
    207     return IsVisitorPtrType(formal_type);
    208   }
    209 
    210   enum TraceMethodType {
    211     NOT_TRACE_METHOD,
    212     TRACE_METHOD,
    213     TRACE_AFTER_DISPATCH_METHOD,
    214   };
    215 
    216   static TraceMethodType GetTraceMethodType(const clang::FunctionDecl* method) {
    217     if (method->getNumParams() != 1)
    218       return NOT_TRACE_METHOD;
    219 
    220     const std::string& name = method->getNameAsString();
    221     if (name != kTraceName && name != kTraceAfterDispatchName)
    222       return NOT_TRACE_METHOD;
    223 
    224     const clang::QualType& formal_type = method->getParamDecl(0)->getType();
    225     if (!IsVisitorPtrType(formal_type)) {
    226       return NOT_TRACE_METHOD;
    227     }
    228 
    229     if (name == kTraceName)
    230       return TRACE_METHOD;
    231     if (name == kTraceAfterDispatchName)
    232       return TRACE_AFTER_DISPATCH_METHOD;
    233 
    234     assert(false && "Should not reach here");
    235     return NOT_TRACE_METHOD;
    236   }
    237 
    238   static bool IsTraceMethod(const clang::FunctionDecl* method) {
    239     return GetTraceMethodType(method) != NOT_TRACE_METHOD;
    240   }
    241 
    242   static bool IsTraceWrappersMethod(const clang::FunctionDecl* method);
    243 
    244   static bool StartsWith(const std::string& str, const std::string& prefix) {
    245     if (prefix.size() > str.size())
    246       return false;
    247     return str.compare(0, prefix.size(), prefix) == 0;
    248   }
    249 
    250   static bool EndsWith(const std::string& str, const std::string& suffix) {
    251     if (suffix.size() > str.size())
    252       return false;
    253     return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
    254   }
    255 
    256   // Test if a template specialization is an instantiation.
    257   static bool IsTemplateInstantiation(clang::CXXRecordDecl* record);
    258 };
    259 
    260 #endif  // TOOLS_BLINK_GC_PLUGIN_CONFIG_H_
    261