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:
IsMember(const std::string & name)38   static bool IsMember(const std::string& name) {
39     return name == "Member";
40   }
41 
IsWeakMember(const std::string & name)42   static bool IsWeakMember(const std::string& name) {
43     return name == "WeakMember";
44   }
45 
IsMemberHandle(const std::string & name)46   static bool IsMemberHandle(const std::string& name) {
47     return IsMember(name) ||
48            IsWeakMember(name);
49   }
50 
IsPersistent(const std::string & name)51   static bool IsPersistent(const std::string& name) {
52     return name == "Persistent" ||
53            name == "WeakPersistent" ;
54   }
55 
IsCrossThreadPersistent(const std::string & name)56   static bool IsCrossThreadPersistent(const std::string& name) {
57     return name == "CrossThreadPersistent" ||
58            name == "CrossThreadWeakPersistent" ;
59   }
60 
IsRefPtr(const std::string & name)61   static bool IsRefPtr(const std::string& name) {
62     return name == "RefPtr";
63   }
64 
IsOwnPtr(const std::string & name)65   static bool IsOwnPtr(const std::string& name) {
66     return name == "OwnPtr";
67   }
68 
IsUniquePtr(const std::string & name)69   static bool IsUniquePtr(const std::string& name) {
70     return name == "unique_ptr";
71   }
72 
IsWTFCollection(const std::string & name)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 
IsGCCollection(const std::string & name)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 
IsPersistentGCCollection(const std::string & name)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 
IsHashMap(const std::string & name)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.
CollectionDimension(const std::string & name)111   static size_t CollectionDimension(const std::string& name) {
112     return (IsHashMap(name) || name == "pair") ? 2 : 1;
113   }
114 
IsRefCountedBase(const std::string & name)115   static bool IsRefCountedBase(const std::string& name) {
116     return name == "RefCounted" ||
117            name == "ThreadSafeRefCounted";
118   }
119 
IsGCMixinBase(const std::string & name)120   static bool IsGCMixinBase(const std::string& name) {
121     return name == "GarbageCollectedMixin";
122   }
123 
IsGCFinalizedBase(const std::string & name)124   static bool IsGCFinalizedBase(const std::string& name) {
125     return name == "GarbageCollectedFinalized";
126   }
127 
IsGCBase(const std::string & name)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.
IsSafePolymorphicBase(const std::string & name)136   static bool IsSafePolymorphicBase(const std::string& name) {
137     return IsGCBase(name) || IsRefCountedBase(name);
138   }
139 
IsAnnotated(clang::Decl * decl,const std::string & anno)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 
IsStackAnnotated(clang::Decl * decl)145   static bool IsStackAnnotated(clang::Decl* decl) {
146     return IsAnnotated(decl, "blink_stack_allocated");
147   }
148 
IsIgnoreAnnotated(clang::Decl * decl)149   static bool IsIgnoreAnnotated(clang::Decl* decl) {
150     return IsAnnotated(decl, "blink_gc_plugin_ignore");
151   }
152 
IsIgnoreCycleAnnotated(clang::Decl * decl)153   static bool IsIgnoreCycleAnnotated(clang::Decl* decl) {
154     return IsAnnotated(decl, "blink_gc_plugin_ignore_cycle") ||
155            IsIgnoreAnnotated(decl);
156   }
157 
IsVisitor(const std::string & name)158   static bool IsVisitor(const std::string& name) {
159     return name == "Visitor" || name == "VisitorHelper";
160   }
161 
IsVisitorPtrType(const clang::QualType & formal_type)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 
IsVisitorDispatcherType(const clang::QualType & formal_type)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 
GetTraceMethodType(const clang::FunctionDecl * method)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 
IsTraceMethod(const clang::FunctionDecl * method)235   static bool IsTraceMethod(const clang::FunctionDecl* method) {
236     return GetTraceMethodType(method) != NOT_TRACE_METHOD;
237   }
238 
IsTraceImplName(const std::string & name)239   static bool IsTraceImplName(const std::string& name) {
240     return name == kTraceImplName || name == kTraceAfterDispatchImplName;
241   }
242 
StartsWith(const std::string & str,const std::string & prefix)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 
EndsWith(const std::string & str,const std::string & suffix)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