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