• 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 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