]> granicus.if.org Git - clang/commitdiff
Eliminate the static map of overridden C++ methods, which was going to
authorDouglas Gregor <dgregor@apple.com>
Tue, 2 Mar 2010 23:58:15 +0000 (23:58 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 2 Mar 2010 23:58:15 +0000 (23:58 +0000)
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

include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/AST/DeclCXX.cpp

index d4d03299f9f2d71c448ff8dd26b8328af9e9a81a..c023ec0cdee6be4a6768838732f21d1a39066833 100644 (file)
@@ -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<const CXXMethodDecl *> *.
+  mutable uintptr_t Storage;
+
+  typedef std::vector<const CXXMethodDecl *> 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<FieldDecl *, FieldDecl *> 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<const CXXMethodDecl *, CXXMethodVector> 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; }
 
 
index 5cd52396a80b643dc31f55fd05b27f0d42a75e68..e091bf10b62977265f3189fdc4cbfd6c6ffb5427 100644 (file)
@@ -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<const CXXMethodDecl *, CXXMethodVector>::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<iterator>(&Storage);
+
+  vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
+  return &Vec->front();
+}
+
+CXXMethodVector::iterator CXXMethodVector::end() const {
+  if ((Storage & 0x01) == 0) {
+    if (Storage == 0)
+      return reinterpret_cast<iterator>(&Storage);
+
+    return reinterpret_cast<iterator>(&Storage) + 1;
+  }
+
+  vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
+  return &Vec->front() + Vec->size();
+}
+
+void CXXMethodVector::push_back(const CXXMethodDecl *Method) {
+  if (Storage == 0) {
+    // 0 -> 1 element.
+    Storage = reinterpret_cast<uintptr_t>(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<const CXXMethodDecl *>(Storage));
+    Storage = reinterpret_cast<uintptr_t>(Vec) | 0x01;
+  } else
+    Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
+
+  // Add the new method to the vector.
+  Vec->push_back(Method);
+}
+
+void CXXMethodVector::Destroy() {
+  if (Storage & 0x01)
+    delete reinterpret_cast<vector_type *>(Storage & ~0x01);
+
+  Storage = 0;
+}
+
+
+ASTContext::overridden_cxx_method_iterator
+ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
+  llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::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 CXXMethodDecl *, CXXMethodVector>::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<SourceRange, SourceRange, bool> {
index aa4b2dd1d0813515762fd36a2d89a022bf86b5a4..9b693af5bc92f1c2164078431f71a155cd41c296 100644 (file)
@@ -611,51 +611,20 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
   return true;
 }
 
-typedef llvm::DenseMap<const CXXMethodDecl*,
-                       std::vector<const CXXMethodDecl *> *>
-                       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<const CXXMethodDecl *> *&Methods = (*OverriddenMethods)[this];
-  if (!Methods)
-    Methods = new std::vector<const CXXMethodDecl *>;
-
-  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 {