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: IsMember(const std::string & name)40 static bool IsMember(const std::string& name) { 41 return name == "Member"; 42 } 43 IsWeakMember(const std::string & name)44 static bool IsWeakMember(const std::string& name) { 45 return name == "WeakMember"; 46 } 47 IsMemberHandle(const std::string & name)48 static bool IsMemberHandle(const std::string& name) { 49 return IsMember(name) || 50 IsWeakMember(name); 51 } 52 IsPersistent(const std::string & name)53 static bool IsPersistent(const std::string& name) { 54 return name == "Persistent" || 55 name == "WeakPersistent" ; 56 } 57 IsCrossThreadPersistent(const std::string & name)58 static bool IsCrossThreadPersistent(const std::string& name) { 59 return name == "CrossThreadPersistent" || 60 name == "CrossThreadWeakPersistent" ; 61 } 62 IsRefPtr(const std::string & name)63 static bool IsRefPtr(const std::string& name) { 64 return name == "RefPtr"; 65 } 66 IsUniquePtr(const std::string & name)67 static bool IsUniquePtr(const std::string& name) { 68 return name == "unique_ptr"; 69 } 70 IsWTFCollection(const std::string & name)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 IsGCCollection(const std::string & name)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 IsPersistentGCCollection(const std::string & name)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 IsGCCollectionWithUnsafeIterator(const std::string & name)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 IsHashMap(const std::string & name)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. CollectionDimension(const std::string & name)119 static size_t CollectionDimension(const std::string& name) { 120 return (IsHashMap(name) || name == "pair") ? 2 : 1; 121 } 122 IsRefCountedBase(const std::string & name)123 static bool IsRefCountedBase(const std::string& name) { 124 return name == "RefCounted" || 125 name == "ThreadSafeRefCounted"; 126 } 127 IsGCMixinBase(const std::string & name)128 static bool IsGCMixinBase(const std::string& name) { 129 return name == "GarbageCollectedMixin"; 130 } 131 IsGCFinalizedBase(const std::string & name)132 static bool IsGCFinalizedBase(const std::string& name) { 133 return name == "GarbageCollectedFinalized"; 134 } 135 IsGCBase(const std::string & name)136 static bool IsGCBase(const std::string& name) { 137 return name == "GarbageCollected" || 138 IsGCFinalizedBase(name) || 139 IsGCMixinBase(name); 140 } 141 IsIterator(const std::string & name)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. IsSafePolymorphicBase(const std::string & name)149 static bool IsSafePolymorphicBase(const std::string& name) { 150 return IsGCBase(name) || IsRefCountedBase(name); 151 } 152 IsAnnotated(clang::Decl * decl,const std::string & anno)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 IsStackAnnotated(clang::Decl * decl)158 static bool IsStackAnnotated(clang::Decl* decl) { 159 return IsAnnotated(decl, "blink_stack_allocated"); 160 } 161 IsIgnoreAnnotated(clang::Decl * decl)162 static bool IsIgnoreAnnotated(clang::Decl* decl) { 163 return IsAnnotated(decl, "blink_gc_plugin_ignore"); 164 } 165 IsIgnoreCycleAnnotated(clang::Decl * decl)166 static bool IsIgnoreCycleAnnotated(clang::Decl* decl) { 167 return IsAnnotated(decl, "blink_gc_plugin_ignore_cycle") || 168 IsIgnoreAnnotated(decl); 169 } 170 IsVisitor(const std::string & name)171 static bool IsVisitor(const std::string& name) { 172 return name == "Visitor" || name == "VisitorHelper"; 173 } 174 IsVisitorPtrType(const clang::QualType & formal_type)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 IsVisitorDispatcherType(const clang::QualType & formal_type)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 GetTraceMethodType(const clang::FunctionDecl * method)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 IsTraceMethod(const clang::FunctionDecl * method)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 StartsWith(const std::string & str,const std::string & prefix)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 EndsWith(const std::string & str,const std::string & suffix)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