From: Douglas Gregor Date: Tue, 2 Mar 2010 23:58:15 +0000 (+0000) Subject: Eliminate the static map of overridden C++ methods, which was going to X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7d10b7eb670b821741b4c96f6cf7afbc3bb39abe;p=clang Eliminate the static map of overridden C++ methods, which was going to come back to bite us at some point. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97607 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index d4d03299f9..c023ec0cde 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -67,6 +67,26 @@ namespace clang { namespace Builtin { class Context; } +/// \brief A vector of C++ member functions that is optimized for +/// storing a single method. +class CXXMethodVector { + /// \brief Storage for the vector. + /// + /// When the low bit is zero, this is a const CXXMethodDecl *. When the + /// low bit is one, this is a std::vector *. + mutable uintptr_t Storage; + + typedef std::vector vector_type; + +public: + typedef const CXXMethodDecl **iterator; + iterator begin() const; + iterator end() const; + + void push_back(const CXXMethodDecl *Method); + void Destroy(); +}; + /// ASTContext - This class holds long-lived AST nodes (such as types and /// decls) that can be referred to throughout the semantic analysis of a file. class ASTContext { @@ -219,6 +239,14 @@ class ASTContext { llvm::DenseMap InstantiatedFromUnnamedFieldDecl; + /// \brief Mapping that stores the methods overridden by a given C++ + /// member function. + /// + /// Since most C++ member functions aren't virtual and therefore + /// don't override anything, we store the overridden functions in + /// this map on the side rather than within the CXXMethodDecl structure. + llvm::DenseMap OverriddenMethods; + TranslationUnitDecl *TUDecl; /// SourceMgr - The associated SourceManager object. @@ -310,6 +338,19 @@ public: void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl); + // Access to the set of methods overridden by the given C++ method. + typedef CXXMethodVector::iterator overridden_cxx_method_iterator; + overridden_cxx_method_iterator + overridden_methods_begin(const CXXMethodDecl *Method) const; + + overridden_cxx_method_iterator + overridden_methods_end(const CXXMethodDecl *Method) const; + + /// \brief Note that the given C++ \p Method overrides the given \p + /// Overridden method. + void addOverriddenMethod(const CXXMethodDecl *Method, + const CXXMethodDecl *Overridden); + TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 5cd52396a8..e091bf10b6 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -59,6 +59,12 @@ ASTContext::~ASTContext() { // Release the DenseMaps associated with DeclContext objects. // FIXME: Is this the ideal solution? ReleaseDeclContextMaps(); + + // Release all of the memory associated with overridden C++ methods. + for (llvm::DenseMap::iterator + OM = OverriddenMethods.begin(), OMEnd = OverriddenMethods.end(); + OM != OMEnd; ++OM) + OM->second.Destroy(); if (FreeMemory) { // Deallocate all the types. @@ -319,6 +325,80 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl; } +CXXMethodVector::iterator CXXMethodVector::begin() const { + if ((Storage & 0x01) == 0) + return reinterpret_cast(&Storage); + + vector_type *Vec = reinterpret_cast(Storage & ~0x01); + return &Vec->front(); +} + +CXXMethodVector::iterator CXXMethodVector::end() const { + if ((Storage & 0x01) == 0) { + if (Storage == 0) + return reinterpret_cast(&Storage); + + return reinterpret_cast(&Storage) + 1; + } + + vector_type *Vec = reinterpret_cast(Storage & ~0x01); + return &Vec->front() + Vec->size(); +} + +void CXXMethodVector::push_back(const CXXMethodDecl *Method) { + if (Storage == 0) { + // 0 -> 1 element. + Storage = reinterpret_cast(Method); + return; + } + + vector_type *Vec; + if ((Storage & 0x01) == 0) { + // 1 -> 2 elements. Allocate a new vector and push the element into that + // vector. + Vec = new vector_type; + Vec->push_back(reinterpret_cast(Storage)); + Storage = reinterpret_cast(Vec) | 0x01; + } else + Vec = reinterpret_cast(Storage & ~0x01); + + // Add the new method to the vector. + Vec->push_back(Method); +} + +void CXXMethodVector::Destroy() { + if (Storage & 0x01) + delete reinterpret_cast(Storage & ~0x01); + + Storage = 0; +} + + +ASTContext::overridden_cxx_method_iterator +ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { + llvm::DenseMap::const_iterator Pos + = OverriddenMethods.find(Method); + if (Pos == OverriddenMethods.end()) + return 0; + + return Pos->second.begin(); +} + +ASTContext::overridden_cxx_method_iterator +ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const { + llvm::DenseMap::const_iterator Pos + = OverriddenMethods.find(Method); + if (Pos == OverriddenMethods.end()) + return 0; + + return Pos->second.end(); +} + +void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method, + const CXXMethodDecl *Overridden) { + OverriddenMethods[Method].push_back(Overridden); +} + namespace { class BeforeInTranslationUnit : std::binary_function { diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index aa4b2dd1d0..9b693af5bc 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -611,51 +611,20 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const { return true; } -typedef llvm::DenseMap *> - OverriddenMethodsMapTy; - -// FIXME: We hate static data. This doesn't survive PCH saving/loading, and -// the vtable building code uses it at CG time. -static OverriddenMethodsMapTy *OverriddenMethods = 0; - void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { assert(MD->isCanonicalDecl() && "Method is not canonical!"); assert(!MD->getParent()->isDependentContext() && "Can't add an overridden method to a class template!"); - // FIXME: The CXXMethodDecl dtor needs to remove and free the entry. - - if (!OverriddenMethods) - OverriddenMethods = new OverriddenMethodsMapTy(); - - std::vector *&Methods = (*OverriddenMethods)[this]; - if (!Methods) - Methods = new std::vector; - - Methods->push_back(MD); + getASTContext().addOverriddenMethod(this, MD); } CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const { - if (!OverriddenMethods) - return 0; - - OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this); - if (it == OverriddenMethods->end() || it->second->empty()) - return 0; - - return &(*it->second)[0]; + return getASTContext().overridden_methods_begin(this); } CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const { - if (!OverriddenMethods) - return 0; - - OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this); - if (it == OverriddenMethods->end() || it->second->empty()) - return 0; - - return &(*it->second)[0] + it->second->size(); + return getASTContext().overridden_methods_end(this); } QualType CXXMethodDecl::getThisType(ASTContext &C) const {