Index: tools/clang/blink_gc_plugin/Config.h |
diff --git a/tools/clang/blink_gc_plugin/Config.h b/tools/clang/blink_gc_plugin/Config.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c62de053306072539003ef93baead1c3dd3a13db |
--- /dev/null |
+++ b/tools/clang/blink_gc_plugin/Config.h |
@@ -0,0 +1,272 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+// This file defines the names used by GC infrastructure. |
+ |
+// TODO: Restructure the name determination to use fully qualified names (ala, |
+// blink::Foo) so that the plugin can be enabled for all of chromium. Doing so |
+// would allow us to catch errors with structures outside of blink that might |
+// have unsafe pointers to GC allocated blink structures. |
+ |
+#ifndef TOOLS_BLINK_GC_PLUGIN_CONFIG_H_ |
+#define TOOLS_BLINK_GC_PLUGIN_CONFIG_H_ |
+ |
+#include <cassert> |
+ |
+#include "clang/AST/AST.h" |
+#include "clang/AST/Attr.h" |
+ |
+const char kNewOperatorName[] = "operator new"; |
+const char kCreateName[] = "create"; |
+const char kTraceName[] = "trace"; |
+const char kTraceImplName[] = "traceImpl"; |
+const char kFinalizeName[] = "finalizeGarbageCollectedObject"; |
+const char kTraceAfterDispatchName[] = "traceAfterDispatch"; |
+const char kTraceAfterDispatchImplName[] = "traceAfterDispatchImpl"; |
+const char kRegisterWeakMembersName[] = "registerWeakMembers"; |
+const char kHeapAllocatorName[] = "HeapAllocator"; |
+const char kTraceIfNeededName[] = "TraceIfNeeded"; |
+const char kVisitorDispatcherName[] = "VisitorDispatcher"; |
+const char kVisitorVarName[] = "visitor"; |
+const char kAdjustAndMarkName[] = "adjustAndMark"; |
+const char kIsHeapObjectAliveName[] = "isHeapObjectAlive"; |
+const char kIsEagerlyFinalizedName[] = "IsEagerlyFinalizedMarker"; |
+ |
+class Config { |
+ public: |
+ static bool IsMember(const std::string& name) { |
+ return name == "Member"; |
+ } |
+ |
+ static bool IsWeakMember(const std::string& name) { |
+ return name == "WeakMember"; |
+ } |
+ |
+ static bool IsMemberHandle(const std::string& name) { |
+ return IsMember(name) || |
+ IsWeakMember(name); |
+ } |
+ |
+ static bool IsPersistent(const std::string& name) { |
+ return name == "Persistent"; |
+ } |
+ |
+ static bool IsPersistentHandle(const std::string& name) { |
+ return IsPersistent(name) || |
+ IsPersistentGCCollection(name); |
+ } |
+ |
+ static bool IsRawPtr(const std::string& name) { |
+ return name == "RawPtr"; |
+ } |
+ |
+ static bool IsRefPtr(const std::string& name) { |
+ return name == "RefPtr"; |
+ } |
+ |
+ static bool IsOwnPtr(const std::string& name) { |
+ return name == "OwnPtr"; |
+ } |
+ |
+ static bool IsWTFCollection(const std::string& name) { |
+ return name == "Vector" || |
+ name == "Deque" || |
+ name == "HashSet" || |
+ name == "ListHashSet" || |
+ name == "LinkedHashSet" || |
+ name == "HashCountedSet" || |
+ name == "HashMap"; |
+ } |
+ |
+ static bool IsGCCollection(const std::string& name) { |
+ return name == "HeapVector" || |
+ name == "HeapDeque" || |
+ name == "HeapHashSet" || |
+ name == "HeapListHashSet" || |
+ name == "HeapLinkedHashSet" || |
+ name == "HeapHashCountedSet" || |
+ name == "HeapHashMap" || |
+ IsPersistentGCCollection(name); |
+ } |
+ |
+ static bool IsPersistentGCCollection(const std::string& name) { |
+ return name == "PersistentHeapVector" || |
+ name == "PersistentHeapDeque" || |
+ name == "PersistentHeapHashSet" || |
+ name == "PersistentHeapListHashSet" || |
+ name == "PersistentHeapLinkedHashSet" || |
+ name == "PersistentHeapHashCountedSet" || |
+ name == "PersistentHeapHashMap"; |
+ } |
+ |
+ static bool IsHashMap(const std::string& name) { |
+ return name == "HashMap" || |
+ name == "HeapHashMap" || |
+ name == "PersistentHeapHashMap"; |
+ } |
+ |
+ // Following http://crrev.com/369633033 (Blink r177436), |
+ // ignore blink::ScriptWrappable's destructor. |
+ // TODO: remove when its non-Oilpan destructor is removed. |
+ static bool HasIgnorableDestructor(const std::string& ns, |
+ const std::string& name) { |
+ return ns == "blink" && name == "ScriptWrappable"; |
+ } |
+ |
+ // Assumes name is a valid collection name. |
+ static size_t CollectionDimension(const std::string& name) { |
+ return (IsHashMap(name) || name == "pair") ? 2 : 1; |
+ } |
+ |
+ static bool IsDummyBase(const std::string& name) { |
+ return name == "DummyBase"; |
+ } |
+ |
+ static bool IsRefCountedBase(const std::string& name) { |
+ return name == "RefCounted" || |
+ name == "ThreadSafeRefCounted"; |
+ } |
+ |
+ static bool IsGCMixinBase(const std::string& name) { |
+ return name == "GarbageCollectedMixin"; |
+ } |
+ |
+ static bool IsGCFinalizedBase(const std::string& name) { |
+ return name == "GarbageCollectedFinalized" || |
+ name == "RefCountedGarbageCollected" || |
+ name == "ThreadSafeRefCountedGarbageCollected"; |
+ } |
+ |
+ static bool IsGCBase(const std::string& name) { |
+ return name == "GarbageCollected" || |
+ IsGCFinalizedBase(name) || |
+ IsGCMixinBase(name); |
+ } |
+ |
+ // Returns true of the base classes that do not need a vtable entry for trace |
+ // because they cannot possibly initiate a GC during construction. |
+ static bool IsSafePolymorphicBase(const std::string& name) { |
+ return IsGCBase(name) || IsDummyBase(name) || IsRefCountedBase(name); |
+ } |
+ |
+ static bool IsAnnotated(clang::Decl* decl, const std::string& anno) { |
+ clang::AnnotateAttr* attr = decl->getAttr<clang::AnnotateAttr>(); |
+ return attr && (attr->getAnnotation() == anno); |
+ } |
+ |
+ static bool IsStackAnnotated(clang::Decl* decl) { |
+ return IsAnnotated(decl, "blink_stack_allocated"); |
+ } |
+ |
+ static bool IsIgnoreAnnotated(clang::Decl* decl) { |
+ return IsAnnotated(decl, "blink_gc_plugin_ignore"); |
+ } |
+ |
+ static bool IsIgnoreCycleAnnotated(clang::Decl* decl) { |
+ return IsAnnotated(decl, "blink_gc_plugin_ignore_cycle") || |
+ IsIgnoreAnnotated(decl); |
+ } |
+ |
+ static bool IsVisitor(const std::string& name) { |
+ return name == "Visitor" || name == "VisitorHelper"; |
+ } |
+ |
+ static bool IsVisitorPtrType(const clang::QualType& formal_type) { |
+ if (!formal_type->isPointerType()) |
+ return false; |
+ |
+ clang::CXXRecordDecl* pointee_type = |
+ formal_type->getPointeeType()->getAsCXXRecordDecl(); |
+ if (!pointee_type) |
+ return false; |
+ |
+ if (!IsVisitor(pointee_type->getName())) |
+ return false; |
+ |
+ return true; |
+ } |
+ |
+ static bool IsVisitorDispatcherType(const clang::QualType& formal_type) { |
+ if (const clang::SubstTemplateTypeParmType* subst_type = |
+ clang::dyn_cast<clang::SubstTemplateTypeParmType>( |
+ formal_type.getTypePtr())) { |
+ if (IsVisitorPtrType(subst_type->getReplacementType())) { |
+ // VisitorDispatcher template parameter substituted to Visitor*. |
+ return true; |
+ } |
+ } else if (const clang::TemplateTypeParmType* parm_type = |
+ clang::dyn_cast<clang::TemplateTypeParmType>( |
+ formal_type.getTypePtr())) { |
+ if (parm_type->getDecl()->getName() == kVisitorDispatcherName) { |
+ // Unresolved, but its parameter name is VisitorDispatcher. |
+ return true; |
+ } |
+ } |
+ |
+ return IsVisitorPtrType(formal_type); |
+ } |
+ |
+ enum TraceMethodType { |
+ NOT_TRACE_METHOD, |
+ TRACE_METHOD, |
+ TRACE_AFTER_DISPATCH_METHOD, |
+ TRACE_IMPL_METHOD, |
+ TRACE_AFTER_DISPATCH_IMPL_METHOD |
+ }; |
+ |
+ static TraceMethodType GetTraceMethodType(const clang::FunctionDecl* method) { |
+ if (method->getNumParams() != 1) |
+ return NOT_TRACE_METHOD; |
+ |
+ const std::string& name = method->getNameAsString(); |
+ if (name != kTraceName && name != kTraceAfterDispatchName && |
+ name != kTraceImplName && name != kTraceAfterDispatchImplName) |
+ return NOT_TRACE_METHOD; |
+ |
+ const clang::QualType& formal_type = method->getParamDecl(0)->getType(); |
+ if (name == kTraceImplName || name == kTraceAfterDispatchImplName) { |
+ if (!IsVisitorDispatcherType(formal_type)) |
+ return NOT_TRACE_METHOD; |
+ } else if (!IsVisitorPtrType(formal_type)) { |
+ return NOT_TRACE_METHOD; |
+ } |
+ |
+ if (name == kTraceName) |
+ return TRACE_METHOD; |
+ if (name == kTraceAfterDispatchName) |
+ return TRACE_AFTER_DISPATCH_METHOD; |
+ if (name == kTraceImplName) |
+ return TRACE_IMPL_METHOD; |
+ if (name == kTraceAfterDispatchImplName) |
+ return TRACE_AFTER_DISPATCH_IMPL_METHOD; |
+ |
+ assert(false && "Should not reach here"); |
+ return NOT_TRACE_METHOD; |
+ } |
+ |
+ static bool IsTraceMethod(const clang::FunctionDecl* method) { |
+ return GetTraceMethodType(method) != NOT_TRACE_METHOD; |
+ } |
+ |
+ static bool IsTraceImplName(const std::string& name) { |
+ return name == kTraceImplName || name == kTraceAfterDispatchImplName; |
+ } |
+ |
+ static bool StartsWith(const std::string& str, const std::string& prefix) { |
+ if (prefix.size() > str.size()) |
+ return false; |
+ return str.compare(0, prefix.size(), prefix) == 0; |
+ } |
+ |
+ static bool EndsWith(const std::string& str, const std::string& suffix) { |
+ if (suffix.size() > str.size()) |
+ return false; |
+ return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; |
+ } |
+ |
+ // Test if a template specialization is an instantiation. |
+ static bool IsTemplateInstantiation(clang::CXXRecordDecl* record); |
+}; |
+ |
+#endif // TOOLS_BLINK_GC_PLUGIN_CONFIG_H_ |