• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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