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 IsMember(const std::string & name)44 static bool IsMember(const std::string& name) { 45 return name == "Member"; 46 } 47 IsWeakMember(const std::string & name)48 static bool IsWeakMember(const std::string& name) { 49 return name == "WeakMember"; 50 } 51 IsMemberHandle(const std::string & name)52 static bool IsMemberHandle(const std::string& name) { 53 return IsMember(name) || 54 IsWeakMember(name); 55 } 56 IsPersistent(const std::string & name)57 static bool IsPersistent(const std::string& name) { 58 return name == "Persistent" || 59 name == "WeakPersistent" ; 60 } 61 IsCrossThreadPersistent(const std::string & name)62 static bool IsCrossThreadPersistent(const std::string& name) { 63 return name == "CrossThreadPersistent" || 64 name == "CrossThreadWeakPersistent" ; 65 } 66 IsRefPtr(const std::string & name)67 static bool IsRefPtr(const std::string& name) { 68 return name == "RefPtr"; 69 } 70 IsOwnPtr(const std::string & name)71 static bool IsOwnPtr(const std::string& name) { 72 return name == "OwnPtr"; 73 } 74 IsUniquePtr(const std::string & name)75 static bool IsUniquePtr(const std::string& name) { 76 return name == "unique_ptr"; 77 } 78 IsWTFCollection(const std::string & name)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 IsGCCollection(const std::string & name)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 IsPersistentGCCollection(const std::string & name)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 IsGCCollectionWithUnsafeIterator(const std::string & name)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 IsHashMap(const std::string & name)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. CollectionDimension(const std::string & name)127 static size_t CollectionDimension(const std::string& name) { 128 return (IsHashMap(name) || name == "pair") ? 2 : 1; 129 } 130 IsRefCountedBase(const std::string & name)131 static bool IsRefCountedBase(const std::string& name) { 132 return name == "RefCounted" || 133 name == "ThreadSafeRefCounted"; 134 } 135 IsGCMixinBase(const std::string & name)136 static bool IsGCMixinBase(const std::string& name) { 137 return name == "GarbageCollectedMixin"; 138 } 139 IsGCFinalizedBase(const std::string & name)140 static bool IsGCFinalizedBase(const std::string& name) { 141 return name == "GarbageCollectedFinalized"; 142 } 143 IsGCBase(const std::string & name)144 static bool IsGCBase(const std::string& name) { 145 return name == "GarbageCollected" || 146 IsGCFinalizedBase(name) || 147 IsGCMixinBase(name); 148 } 149 IsIterator(const std::string & name)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. IsSafePolymorphicBase(const std::string & name)157 static bool IsSafePolymorphicBase(const std::string& name) { 158 return IsGCBase(name) || IsRefCountedBase(name); 159 } 160 IsAnnotated(clang::Decl * decl,const std::string & anno)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 IsStackAnnotated(clang::Decl * decl)166 static bool IsStackAnnotated(clang::Decl* decl) { 167 return IsAnnotated(decl, "blink_stack_allocated"); 168 } 169 IsIgnoreAnnotated(clang::Decl * decl)170 static bool IsIgnoreAnnotated(clang::Decl* decl) { 171 return IsAnnotated(decl, "blink_gc_plugin_ignore"); 172 } 173 IsIgnoreCycleAnnotated(clang::Decl * decl)174 static bool IsIgnoreCycleAnnotated(clang::Decl* decl) { 175 return IsAnnotated(decl, "blink_gc_plugin_ignore_cycle") || 176 IsIgnoreAnnotated(decl); 177 } 178 IsVisitor(const std::string & name)179 static bool IsVisitor(const std::string& name) { 180 return name == "Visitor" || name == "VisitorHelper"; 181 } 182 IsVisitorPtrType(const clang::QualType & formal_type)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 IsVisitorDispatcherType(const clang::QualType & formal_type)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 GetTraceMethodType(const clang::FunctionDecl * method)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 IsTraceMethod(const clang::FunctionDecl * method)256 static bool IsTraceMethod(const clang::FunctionDecl* method) { 257 return GetTraceMethodType(method) != NOT_TRACE_METHOD; 258 } 259 IsTraceImplName(const std::string & name)260 static bool IsTraceImplName(const std::string& name) { 261 return name == kTraceImplName || name == kTraceAfterDispatchImplName; 262 } 263 StartsWith(const std::string & str,const std::string & prefix)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 EndsWith(const std::string & str,const std::string & suffix)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