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