15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file. 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This file defines the names used by GC infrastructure. 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#ifndef TOOLS_BLINK_GC_PLUGIN_CONFIG_H_ 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define TOOLS_BLINK_GC_PLUGIN_CONFIG_H_ 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "clang/AST/AST.h" 11effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "clang/AST/Attr.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kNewOperatorName[] = "operator new"; 1423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)const char kCreateName[] = "create"; 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kTraceName[] = "trace"; 1623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)const char kFinalizeName[] = "finalizeGarbageCollectedObject"; 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kTraceAfterDispatchName[] = "traceAfterDispatch"; 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kRegisterWeakMembersName[] = "registerWeakMembers"; 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kHeapAllocatorName[] = "HeapAllocator"; 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const char kTraceIfNeededName[] = "TraceIfNeeded"; 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class Config { 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public: 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static bool IsMember(const std::string& name) { 25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return name == "Member"; 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static bool IsWeakMember(const std::string& name) { 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return name == "WeakMember"; 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static bool IsMemberHandle(const std::string& name) { 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return IsMember(name) || 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) IsWeakMember(name); 35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static bool IsPersistent(const std::string& name) { 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return name == "Persistent"; 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static bool IsPersistentHandle(const std::string& name) { 42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return IsPersistent(name) || 43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) IsPersistentGCCollection(name); 44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static bool IsRawPtr(const std::string& name) { 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return name == "RawPtr"; 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static bool IsRefPtr(const std::string& name) { 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return name == "RefPtr"; 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static bool IsOwnPtr(const std::string& name) { 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return name == "OwnPtr"; 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static bool IsWTFCollection(const std::string& name) { 59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return name == "Vector" || 60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "Deque" || 61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) name == "HashSet" || 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) name == "ListHashSet" || 63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "LinkedHashSet" || 64010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "HashCountedSet" || 65010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "HashMap"; 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static bool IsGCCollection(const std::string& name) { 69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return name == "HeapVector" || 70010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "HeapDeque" || 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) name == "HeapHashSet" || 72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "HeapListHashSet" || 73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "HeapLinkedHashSet" || 74010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "HeapHashCountedSet" || 75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "HeapHashMap" || 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) IsPersistentGCCollection(name); 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 79010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) static bool IsPersistentGCCollection(const std::string& name) { 80010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return name == "PersistentHeapVector" || 81010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "PersistentHeapDeque" || 82010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "PersistentHeapHashSet" || 83010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "PersistentHeapListHashSet" || 84010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "PersistentHeapLinkedHashSet" || 85010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "PersistentHeapHashCountedSet" || 86010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) name == "PersistentHeapHashMap"; 87010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static bool IsHashMap(const std::string& name) { 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return name == "HashMap" || 91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) name == "HeapHashMap" || 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) name == "PersistentHeapHashMap"; 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Following http://crrev.com/369633033 (Blink r177436), 96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // ignore blink::ScriptWrappable's destructor. 97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // FIXME: remove when its non-Oilpan destructor is removed. 98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch static bool HasIgnorableDestructor(const std::string& ns, 99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& name) { 100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return ns == "blink" && name == "ScriptWrappable"; 101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Assumes name is a valid collection name. 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static size_t CollectionDimension(const std::string& name) { 105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return (IsHashMap(name) || name == "pair") ? 2 : 1; 106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) static bool IsDummyBase(const std::string& name) { 1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return name == "DummyBase"; 1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) static bool IsRefCountedBase(const std::string& name) { 1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return name == "RefCounted" || 1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) name == "ThreadSafeRefCounted"; 1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static bool IsGCMixinBase(const std::string& name) { 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return name == "GarbageCollectedMixin"; 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static bool IsGCFinalizedBase(const std::string& name) { 122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return name == "GarbageCollectedFinalized" || 1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) name == "RefCountedGarbageCollected" || 1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) name == "ThreadSafeRefCountedGarbageCollected"; 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static bool IsGCBase(const std::string& name) { 128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return name == "GarbageCollected" || 129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) IsGCFinalizedBase(name) || 130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) IsGCMixinBase(name); 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Returns true of the base classes that do not need a vtable entry for trace 1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // because they cannot possibly initiate a GC during construction. 1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) static bool IsSafePolymorphicBase(const std::string& name) { 1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return IsGCBase(name) || IsDummyBase(name) || IsRefCountedBase(name); 1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 139effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch static bool IsAnnotated(clang::Decl* decl, const std::string& anno) { 140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch clang::AnnotateAttr* attr = decl->getAttr<clang::AnnotateAttr>(); 141effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return attr && (attr->getAnnotation() == anno); 142effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 144effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch static bool IsStackAnnotated(clang::Decl* decl) { 145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return IsAnnotated(decl, "blink_stack_allocated"); 146effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch static bool IsIgnoreAnnotated(clang::Decl* decl) { 149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return IsAnnotated(decl, "blink_gc_plugin_ignore"); 150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch static bool IsIgnoreCycleAnnotated(clang::Decl* decl) { 153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return IsAnnotated(decl, "blink_gc_plugin_ignore_cycle") || 154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch IsIgnoreAnnotated(decl); 155effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 156effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static bool IsVisitor(const std::string& name) { return name == "Visitor"; } 158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) static bool IsTraceMethod(clang::FunctionDecl* method, 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool* isTraceAfterDispatch = 0) { 161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (method->getNumParams() != 1) 162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& name = method->getNameAsString(); 165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (name != kTraceName && name != kTraceAfterDispatchName) 166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const clang::QualType& formal_type = method->getParamDecl(0)->getType(); 169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!formal_type->isPointerType()) 170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) clang::CXXRecordDecl* pointee_type = 173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) formal_type->getPointeeType()->getAsCXXRecordDecl(); 174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!pointee_type) 175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!IsVisitor(pointee_type->getName())) 178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (isTraceAfterDispatch) 181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) *isTraceAfterDispatch = (name == kTraceAfterDispatchName); 182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return true; 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static bool StartsWith(const std::string& str, const std::string& prefix) { 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (prefix.size() > str.size()) 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return str.compare(0, prefix.size(), prefix) == 0; 1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static bool EndsWith(const std::string& str, const std::string& suffix) { 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (suffix.size() > str.size()) 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}; 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif // TOOLS_BLINK_GC_PLUGIN_CONFIG_H_ 199