sgraenitz created this revision.
sgraenitz added reviewers: labath, jingham, JDevlieghere, erik.pilkington.

I set up a new review, because not all the code I touched was marked as a 
change in old one anymore.

In preparation for this review, there were two earlier ones:

- https://reviews.llvm.org/D49612 introduced the ItaniumPartialDemangler to 
LLDB demangling without conceptual changes
- https://reviews.llvm.org/D49909 added a unit test that covers all relevant 
code paths in the InitNameIndexes() function

Primary goals for this patch are:
(1) Use ItaniumPartialDemangler's rich mangling info for building LLDB's name 
index.
(2) Provide a uniform interface.
(3) Improve indexing performance.

The central implementation in this patch is our new function for explicit 
demangling:

  const RichManglingInfo *
  Mangled::DemangleWithRichManglingInfo(RichManglingContext &, 
SkipMangledNameFn *)

It takes a context object and a filter function and provides read-only access 
to the rich mangling info on success, or otherwise returns null. The two new 
classes are:

- `RichManglingInfo` offers a uniform interface to query symbol properties like 
`getFunctionDeclContextName()` or `isCtorOrDtor()` that are forwarded to the 
respective provider internally (`llvm::ItaniumPartialDemangler` or 
`lldb_private::CPlusPlusLanguage::MethodName`).
- `RichManglingContext` works a bit like `LLVMContext`, it the actual 
`RichManglingInfo` returned from `DemangleWithRichManglingInfo()` and handles 
lifetime and configuration. It is likely stack-allocated and can be reused for 
multiple queries during batch processing.

The idea here is that `DemangleWithRichManglingInfo()` acts like a gate keeper. 
It only provides access to `RichManglingInfo` on success, which in turn avoids 
the need to handle a `NoInfo` state in every single one of its getters. Having 
it stored within the context, avoids extra heap allocations and aids (3). As 
instantiations of the IPD the are considered expensive, the context is the 
ideal place to store it too. An efficient filtering function 
`SkipMangledNameFn` is another piece in the performance puzzle and it helps to 
mimic the original behavior of `InitNameIndexes`.

Future potential:

- `DemangleWithRichManglingInfo()` is thread-safe, IFF using different contexts 
in different threads. This may be exploited in the future. (It's another thing 
that it has in common with `LLVMContext`.)
- The old implementation only parsed and indexed Itanium mangled names. The new 
`RichManglingInfo` can be extended for various mangling schemes and languages.

One problem with the implementation of RichManglingInfo is the inaccessibility 
of class `CPlusPlusLanguage::MethodName` (defined in 
source/Plugins/Language/..), from within any header in the Core components of 
LLDB. The rather hacky solution is to store a type erased reference and cast it 
to the correct type on access in the cpp - see 
`RichManglingInfo::get<ParserT>()`. At the moment there seems to be no better 
way to do it. IMHO `CPlusPlusLanguage::MethodName` should be a top-level class 
in order to enable forward delcarations (but that is a rather big change I 
guess).

First simple profiling shows a good speedup. `target create clang` now takes 
0.64s on average. Before the change I observed runtimes between 0.76s an 1.01s. 
This is still no bulletproof data (I only ran it on one machine!), but it's a 
promising indicator I think.


https://reviews.llvm.org/D50071

Files:
  include/lldb/Core/Mangled.h
  include/lldb/Core/RichManglingInfo.h
  include/lldb/Symbol/Symtab.h
  include/lldb/Utility/ConstString.h
  include/lldb/lldb-forward.h
  source/Core/CMakeLists.txt
  source/Core/Mangled.cpp
  source/Core/RichManglingInfo.cpp
  source/Symbol/Symtab.cpp

Index: source/Symbol/Symtab.cpp
===================================================================
--- source/Symbol/Symtab.cpp
+++ source/Symbol/Symtab.cpp
@@ -10,9 +10,10 @@
 #include <map>
 #include <set>
 
-#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
 #include "Plugins/Language/ObjC/ObjCLanguage.h"
+
 #include "lldb/Core/Module.h"
+#include "lldb/Core/RichManglingInfo.h"
 #include "lldb/Core/STLUtils.h"
 #include "lldb/Core/Section.h"
 #include "lldb/Symbol/ObjectFile.h"
@@ -215,6 +216,40 @@
 //----------------------------------------------------------------------
 // InitNameIndexes
 //----------------------------------------------------------------------
+namespace {
+bool lldb_skip_name(llvm::StringRef mangled, Mangled::ManglingScheme scheme) {
+  switch (scheme) {
+  case Mangled::eManglingSchemeItanium: {
+    if (mangled.size() < 3 || !mangled.startswith("_Z"))
+      return true;
+
+    // Avoid the following types of symbols in the index.
+    switch (mangled[2]) {
+    case 'G': // guard variables
+    case 'T': // virtual tables, VTT structures, typeinfo structures + names
+    case 'Z': // named local entities (if we eventually handle
+              // eSymbolTypeData, we will want this back)
+      return true;
+
+    default:
+      break;
+    }
+
+    // Include this name in the index.
+    return false;
+  }
+
+  // No filters for this scheme yet. Include all names in indexing.
+  case Mangled::eManglingSchemeMSVC:
+    return false;
+
+  // Don't try and demangle things we can't categorize.
+  case Mangled::eManglingSchemeNone:
+    return true;
+  }
+}
+} // namespace
+
 void Symtab::InitNameIndexes() {
   // Protected function, no need to lock mutex...
   if (!m_name_indexes_computed) {
@@ -243,25 +278,30 @@
     m_name_to_index.Reserve(actual_count);
 #endif
 
-    NameToIndexMap::Entry entry;
-
     // The "const char *" in "class_contexts" must come from a
     // ConstString::GetCString()
     std::set<const char *> class_contexts;
     UniqueCStringMap<uint32_t> mangled_name_to_index;
     std::vector<const char *> symbol_contexts(num_symbols, nullptr);
 
+    // Instantiation of the demangler is expensive, so better use a single one
+    // for all entries during batch processing.
+    RichManglingContext MC;
+    NameToIndexMap::Entry entry;
+
     for (entry.value = 0; entry.value < num_symbols; ++entry.value) {
-      const Symbol *symbol = &m_symbols[entry.value];
+      Symbol *symbol = &m_symbols[entry.value];
 
       // Don't let trampolines get into the lookup by name map If we ever need
       // the trampoline symbols to be searchable by name we can remove this and
       // then possibly add a new bool to any of the Symtab functions that
       // lookup symbols by name to indicate if they want trampolines.
       if (symbol->IsTrampoline())
         continue;
 
-      const Mangled &mangled = symbol->GetMangled();
+      // If the symbol's name string matched a Mangled::ManglingScheme, it is
+      // stored in the mangled field.
+      Mangled &mangled = symbol->GetMangled();
       entry.cstring = mangled.GetMangledName();
       if (entry.cstring) {
         m_name_to_index.Append(entry);
@@ -274,70 +314,18 @@
           m_name_to_index.Append(entry);
         }
 
-        const SymbolType symbol_type = symbol->GetType();
-        if (symbol_type == eSymbolTypeCode ||
-            symbol_type == eSymbolTypeResolver) {
-          llvm::StringRef entry_ref(entry.cstring.GetStringRef());
-          if (entry_ref[0] == '_' && entry_ref[1] == 'Z' &&
-              (entry_ref[2] != 'T' && // avoid virtual table, VTT structure,
-                                      // typeinfo structure, and typeinfo
-                                      // name
-               entry_ref[2] != 'G' && // avoid guard variables
-               entry_ref[2] != 'Z'))  // named local entities (if we
-                                          // eventually handle eSymbolTypeData,
-                                          // we will want this back)
-          {
-            CPlusPlusLanguage::MethodName cxx_method(
-                mangled.GetDemangledName(lldb::eLanguageTypeC_plus_plus));
-            entry.cstring = ConstString(cxx_method.GetBasename());
-            if (entry.cstring) {
-              // ConstString objects permanently store the string in the pool
-              // so calling GetCString() on the value gets us a const char *
-              // that will never go away
-              const char *const_context =
-                  ConstString(cxx_method.GetContext()).GetCString();
-
-              if (!const_context || const_context[0] == 0) {
-                // No context for this function so this has to be a basename
-                m_basename_to_index.Append(entry);
-                // If there is no context (no namespaces or class scopes that
-                // come before the function name) then this also could be a
-                // fullname.
-                m_name_to_index.Append(entry);
-              } else {
-                entry_ref = entry.cstring.GetStringRef();
-                if (entry_ref[0] == '~' ||
-                    !cxx_method.GetQualifiers().empty()) {
-                  // The first character of the demangled basename is '~' which
-                  // means we have a class destructor. We can use this
-                  // information to help us know what is a class and what
-                  // isn't.
-                  if (class_contexts.find(const_context) == class_contexts.end())
-                    class_contexts.insert(const_context);
-                  m_method_to_index.Append(entry);
-                } else {
-                  if (class_contexts.find(const_context) !=
-                      class_contexts.end()) {
-                    // The current decl context is in our "class_contexts"
-                    // which means this is a method on a class
-                    m_method_to_index.Append(entry);
-                  } else {
-                    // We don't know if this is a function basename or a
-                    // method, so put it into a temporary collection so once we
-                    // are done we can look in class_contexts to see if each
-                    // entry is a class or just a function and will put any
-                    // remaining items into m_method_to_index or
-                    // m_basename_to_index as needed
-                    mangled_name_to_index.Append(entry);
-                    symbol_contexts[entry.value] = const_context;
-                  }
-                }
-              }
-            }
-          }
+        const SymbolType type = symbol->GetType();
+        if (type == eSymbolTypeCode || type == eSymbolTypeResolver) {
+          if (const RichManglingInfo *info =
+                  mangled.DemangleWithRichManglingInfo(MC, lldb_skip_name))
+            RegisterMangledNameEntry(entry, class_contexts,
+                                     mangled_name_to_index, symbol_contexts,
+                                     *info);
         }
       }
 
+      // Symbol name strings that didn't match a Mangled::ManglingScheme, are
+      // stored in the demangled field.
       entry.cstring = mangled.GetDemangledName(symbol->GetLanguage());
       if (entry.cstring) {
         m_name_to_index.Append(entry);
@@ -379,7 +367,7 @@
             m_method_to_index.Append(entry);
           } else {
             // If we got here, we have something that had a context (was inside
-            // a namespace or class) yet we don't know if the entry
+            // a namespace or class) yet we don't know the entry
             m_method_to_index.Append(entry);
             m_basename_to_index.Append(entry);
           }
@@ -397,6 +385,53 @@
   }
 }
 
+void Symtab::RegisterMangledNameEntry(
+    NameToIndexMap::Entry &entry, std::set<const char *> &class_contexts,
+    UniqueCStringMap<uint32_t> &mangled_name_to_index,
+    std::vector<const char *> &symbol_contexts, const RichManglingInfo &info) {
+  // Only register functions that have a base name.
+  const char *base_name_cstr = info.GetFunctionBaseName();
+  if (base_name_cstr == nullptr)
+    return;
+
+  // The base name will be our entry's name.
+  entry.cstring = ConstString(base_name_cstr);
+
+  // Register functions with no context.
+  ConstString decl_context(info.GetFunctionDeclContextName());
+  if (decl_context.IsEmpty()) {
+    // This has to be a basename
+    m_basename_to_index.Append(entry);
+    // If there is no context (no namespaces or class scopes that come before
+    // the function name) then this also could be a fullname.
+    m_name_to_index.Append(entry);
+    return;
+  }
+
+  // See if we already know this context.
+  auto it = class_contexts.find(decl_context.GetCString());
+
+  // Register constructors and destructors. They are methods and create
+  // declaration contexts.
+  if (info.IsCtorOrDtor()) {
+    m_method_to_index.Append(entry);
+    if (it == class_contexts.end())
+      class_contexts.insert(it, decl_context.GetCString());
+    return;
+  }
+
+  // Register regular methods with a known declaration context.
+  if (it != class_contexts.end()) {
+    m_method_to_index.Append(entry);
+    return;
+  }
+
+  // Regular methods in unknown declaration contexts are put to the backlog. We
+  // will revisit them once we processed all remaining symbols.
+  mangled_name_to_index.Append(entry);
+  symbol_contexts[entry.value] = decl_context.GetCString();
+}
+
 void Symtab::PreloadSymbols() {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
   InitNameIndexes();
Index: source/Core/RichManglingInfo.cpp
===================================================================
--- /dev/null
+++ source/Core/RichManglingInfo.cpp
@@ -0,0 +1,93 @@
+//===-- RichManglingInfo.cpp ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/RichManglingInfo.h"
+#include "lldb/Utility/ConstString.h"
+
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void RichManglingInfo::ResetProvider() {
+  // If we want to support parsers for other languages some day, we need a
+  // switch here to delete the correct parser type.
+  if (m_legacy_parser.hasValue()) {
+    assert(m_provider == RichManglingInfo::PluginCxxLanguage);
+    delete get<CPlusPlusLanguage::MethodName>();
+    m_legacy_parser = nullptr;
+  }
+}
+
+RichManglingInfo *RichManglingContext::SetItaniumInfo() {
+  m_info.ResetProvider();
+  m_info.m_provider = RichManglingInfo::ItaniumPartialDemangler;
+  m_info.m_IPD = &m_IPD;
+  return &m_info;
+}
+
+RichManglingInfo *
+RichManglingContext::SetLegacyCxxParserInfo(const ConstString &mangled) {
+  m_info.ResetProvider();
+  m_info.m_provider = RichManglingInfo::PluginCxxLanguage;
+  m_info.m_legacy_parser = new CPlusPlusLanguage::MethodName(mangled);
+  return &m_info;
+}
+
+RichManglingInfo::~RichManglingInfo() {
+  ResetProvider();
+  delete m_IPD_buf;
+}
+
+bool RichManglingInfo::IsCtorOrDtor() const {
+  switch (m_provider) {
+  case ItaniumPartialDemangler:
+    return m_IPD->isCtorOrDtor();
+  case PluginCxxLanguage: {
+    // We can only check for destructors here.
+    auto base_name = get<CPlusPlusLanguage::MethodName>()->GetBasename();
+    return base_name.front() == '~';
+  }
+  }
+}
+
+bool RichManglingInfo::IsFunction() const {
+  switch (m_provider) {
+  case ItaniumPartialDemangler:
+    return m_IPD->isFunction();
+  case PluginCxxLanguage:
+    return get<CPlusPlusLanguage::MethodName>()->IsValid();
+  }
+}
+
+const char *RichManglingInfo::GetFunctionBaseName() const {
+  switch (m_provider) {
+  case ItaniumPartialDemangler:
+    if (auto buf = m_IPD->getFunctionBaseName(m_IPD_buf, &m_IPD_size)) {
+      m_IPD_buf = buf;
+      return buf;
+    }
+    return nullptr;
+  case PluginCxxLanguage:
+    return get<CPlusPlusLanguage::MethodName>()->GetBasename().data();
+  }
+}
+
+const char *RichManglingInfo::GetFunctionDeclContextName() const {
+  switch (m_provider) {
+  case ItaniumPartialDemangler:
+    if (auto buf = m_IPD->getFunctionDeclContextName(m_IPD_buf, &m_IPD_size)) {
+      m_IPD_buf = buf;
+      return buf;
+    }
+    return nullptr;
+  case PluginCxxLanguage:
+    return get<CPlusPlusLanguage::MethodName>()->GetContext().data();
+  }
+}
Index: source/Core/Mangled.cpp
===================================================================
--- source/Core/Mangled.cpp
+++ source/Core/Mangled.cpp
@@ -16,6 +16,7 @@
 #pragma comment(lib, "dbghelp.lib")
 #endif
 
+#include "lldb/Core/RichManglingInfo.h"
 #include "lldb/Utility/ConstString.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/Logging.h"
@@ -195,7 +196,7 @@
 int Mangled::Compare(const Mangled &a, const Mangled &b) {
   return ConstString::Compare(
       a.GetName(lldb::eLanguageTypeUnknown, ePreferMangled),
-      a.GetName(lldb::eLanguageTypeUnknown, ePreferMangled));
+      b.GetName(lldb::eLanguageTypeUnknown, ePreferMangled));
 }
 
 //----------------------------------------------------------------------
@@ -232,6 +233,127 @@
   }
 }
 
+//----------------------------------------------------------------------
+// Local helpers for different demangling implementations.
+//----------------------------------------------------------------------
+namespace {
+
+char *GetMSVCDemangledCStr(const char *M) {
+#if defined(_MSC_VER)
+  const size_t demangled_length = 2048;
+  char *demangled_cstr = static_cast<char *>(::malloc(demangled_length));
+  ::ZeroMemory(demangled_cstr, demangled_length);
+  DWORD result = safeUndecorateName(M, demangled_cstr, demangled_length);
+
+  if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
+    if (demangled_cstr && demangled_cstr[0])
+      log->Printf("demangled msvc: %s -> \"%s\"", M, demangled_cstr);
+    else
+      log->Printf("demangled msvc: %s -> error: 0x%lu", M, result);
+  }
+
+  if (result != 0) {
+    return demangled_cstr;
+  } else {
+    ::free(demangled_cstr);
+    return nullptr;
+  }
+#else
+  return nullptr;
+#endif
+}
+
+char *GetItaniumRichDemangleInfo(const char *M,
+                                 llvm::ItaniumPartialDemangler &IPD) {
+  char *demangled_cstr = nullptr;
+  bool err = IPD.partialDemangle(M);
+  if (!err) {
+    // Default buffer and size (will realloc in case it's too small).
+    size_t demangled_size = 80;
+    demangled_cstr = static_cast<char *>(std::malloc(demangled_size));
+    demangled_cstr = IPD.finishDemangle(demangled_cstr, &demangled_size);
+  }
+
+  if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
+    if (demangled_cstr)
+      log->Printf("demangled itanium: %s -> \"%s\"", M, demangled_cstr);
+    else
+      log->Printf("demangled itanium: %s -> error: failed to demangle", M);
+  }
+
+  return demangled_cstr;
+}
+} // namespace
+
+//----------------------------------------------------------------------
+// Explicit demangling for scheduled requests during batch processing. This
+// makes use of ItaniumPartialDemangler's rich demangle info
+//----------------------------------------------------------------------
+const RichManglingInfo *
+Mangled::DemangleWithRichManglingInfo(RichManglingContext &context,
+                                      SkipMangledNameFn *skip_mangled_name) {
+  // We need to generate and cache the demangled name.
+  static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+  Timer scoped_timer(func_cat,
+                     "Mangled::DemangleWithRichNameIndexInfo (m_mangled = %s)",
+                     m_mangled.GetCString());
+
+  // Others are not meant to arrive here. ObjC names or C's main() for example
+  // have their names stored in m_demangled, while m_mangled is empty.
+  assert(m_mangled);
+
+  // Check whether or not we are interested in this name at all.
+  llvm::StringRef M = m_mangled.GetStringRef();
+  ManglingScheme S = cstring_mangling_scheme(M.data());
+  if (skip_mangled_name && skip_mangled_name(M, S))
+    return nullptr;
+
+  switch (S) {
+  case eManglingSchemeNone:
+    // The current mangled_name_filter would allow llvm_unreachable here.
+    return nullptr;
+
+  case eManglingSchemeItanium:
+    // We want the rich mangling info here, so we don't care whether or not
+    // there is a demangled string in the pool already.
+    if (char *D = GetItaniumRichDemangleInfo(M.data(), context.GetIPD())) {
+      // Connect the counterparts in the string pool to accelerate subsequent
+      // access in GetDemangledName().
+      m_demangled.SetCStringWithMangledCounterpart(D, m_mangled);
+      std::free(D);
+
+      return context.SetItaniumInfo();
+    } else {
+      m_demangled.SetCString("");
+      return nullptr;
+    }
+
+  case eManglingSchemeMSVC: {
+    // We have no rich mangling for MSVC-mangled names yet, so first try to
+    // demangle it if necessary.
+    if (!m_demangled && !m_mangled.GetMangledCounterpart(m_demangled)) {
+      if (char *D = GetMSVCDemangledCStr(M.data())) {
+        // Connect the counterparts in the string pool to accelerate
+        // subsequent access in GetDemangledName().
+        m_demangled.SetCStringWithMangledCounterpart(D, m_mangled);
+        ::free(D);
+      } else {
+        m_demangled.SetCString("");
+      }
+    }
+
+    if (m_demangled.IsEmpty()) {
+      // Cannot demangle it, so don't try parsing.
+      return nullptr;
+    } else {
+      // Demangled successfully, we can try and parse it with
+      // CPlusPlusLanguage::MethodName.
+      return context.SetLegacyCxxParserInfo(m_mangled);
+    }
+  }
+  }
+}
+
 //----------------------------------------------------------------------
 // Generate the demangled name on demand using this accessor. Code in this
 // class will need to use this accessor if it wishes to decode the demangled
@@ -242,14 +364,12 @@
 Mangled::GetDemangledName(lldb::LanguageType language) const {
   // Check to make sure we have a valid mangled name and that we haven't
   // already decoded our mangled name.
-  if (m_mangled && !m_demangled) {
+  if (m_mangled && m_demangled.IsNull()) {
     // We need to generate and cache the demangled name.
     static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
     Timer scoped_timer(func_cat, "Mangled::GetDemangledName (m_mangled = %s)",
                        m_mangled.GetCString());
 
-    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE);
-
     // Don't bother running anything that isn't mangled
     const char *mangled_name = m_mangled.GetCString();
     ManglingScheme mangling_scheme{cstring_mangling_scheme(mangled_name)};
@@ -259,60 +379,23 @@
       // add it to our map.
       char *demangled_name = nullptr;
       switch (mangling_scheme) {
-      case eManglingSchemeMSVC: {
-#if defined(_MSC_VER)
-        if (log)
-          log->Printf("demangle msvc: %s", mangled_name);
-        const size_t demangled_length = 2048;
-        demangled_name = static_cast<char *>(::malloc(demangled_length));
-        ::ZeroMemory(demangled_name, demangled_length);
-        DWORD result =
-            safeUndecorateName(mangled_name, demangled_name, demangled_length);
-        if (log) {
-          if (demangled_name && demangled_name[0])
-            log->Printf("demangled msvc: %s -> \"%s\"", mangled_name,
-                        demangled_name);
-          else
-            log->Printf("demangled msvc: %s -> error: 0x%lu", mangled_name,
-                        result);
-        }
-
-        if (result == 0) {
-          free(demangled_name);
-          demangled_name = nullptr;
-        }
-#endif
+      case eManglingSchemeMSVC:
+        demangled_name = GetMSVCDemangledCStr(mangled_name);
         break;
-      }
       case eManglingSchemeItanium: {
         llvm::ItaniumPartialDemangler IPD;
-        bool demangle_err = IPD.partialDemangle(mangled_name);
-        if (!demangle_err) {
-          // Default buffer and size (realloc is used in case it's too small).
-          size_t demangled_size = 80;
-          demangled_name = static_cast<char *>(::malloc(demangled_size));
-          demangled_name = IPD.finishDemangle(demangled_name, &demangled_size);
-        }
-
-        if (log) {
-          if (demangled_name)
-            log->Printf("demangled itanium: %s -> \"%s\"", mangled_name,
-                        demangled_name);
-          else
-            log->Printf("demangled itanium: %s -> error: failed to demangle",
-                        mangled_name);
-        }
+        demangled_name = GetItaniumRichDemangleInfo(mangled_name, IPD);
         break;
       }
       case eManglingSchemeNone:
-        break;
+        llvm_unreachable("eManglingSchemeNone was handled already");
       }
       if (demangled_name) {
         m_demangled.SetCStringWithMangledCounterpart(demangled_name, m_mangled);
         free(demangled_name);
       }
     }
-    if (!m_demangled) {
+    if (m_demangled.IsNull()) {
       // Set the demangled string to the empty string to indicate we tried to
       // parse it once and failed.
       m_demangled.SetCString("");
Index: source/Core/CMakeLists.txt
===================================================================
--- source/Core/CMakeLists.txt
+++ source/Core/CMakeLists.txt
@@ -34,6 +34,7 @@
   Opcode.cpp
   PluginManager.cpp
   RegisterValue.cpp
+  RichManglingInfo.cpp
   Scalar.cpp
   SearchFilter.cpp
   Section.cpp
Index: include/lldb/lldb-forward.h
===================================================================
--- include/lldb/lldb-forward.h
+++ include/lldb/lldb-forward.h
@@ -191,6 +191,8 @@
 class RegisterValue;
 class RegularExpression;
 class REPL;
+class RichManglingInfo;
+class RichManglingContext;
 class Scalar;
 class ScriptInterpreter;
 class ScriptInterpreterLocker;
@@ -492,5 +494,14 @@
 
 } // namespace lldb
 
+//----------------------------------------------------------------------
+// llvm forward declarations
+//----------------------------------------------------------------------
+namespace llvm {
+
+struct ItaniumPartialDemangler;
+
+} // namespace llvm
+
 #endif // #if defined(__cplusplus)
 #endif // LLDB_lldb_forward_h_
Index: include/lldb/Utility/ConstString.h
===================================================================
--- include/lldb/Utility/ConstString.h
+++ include/lldb/Utility/ConstString.h
@@ -345,6 +345,15 @@
   //------------------------------------------------------------------
   bool IsEmpty() const { return m_string == nullptr || m_string[0] == '\0'; }
 
+  //------------------------------------------------------------------
+  /// Test for null string.
+  ///
+  /// @return
+  ///     @li \b true if there is no string associated with this instance.
+  ///     @li \b false if there is a string associated with this instance.
+  //------------------------------------------------------------------
+  bool IsNull() const { return m_string == nullptr; }
+
   //------------------------------------------------------------------
   /// Set the C string value.
   ///
Index: include/lldb/Symbol/Symtab.h
===================================================================
--- include/lldb/Symbol/Symtab.h
+++ include/lldb/Symbol/Symtab.h
@@ -197,6 +197,11 @@
   void SymbolIndicesToSymbolContextList(std::vector<uint32_t> &symbol_indexes,
                                         SymbolContextList &sc_list);
 
+  void RegisterMangledNameEntry(
+      NameToIndexMap::Entry &entry, std::set<const char *> &class_contexts,
+      UniqueCStringMap<uint32_t> &mangled_name_to_index,
+      std::vector<const char *> &symbol_contexts, const RichManglingInfo &info);
+
   DISALLOW_COPY_AND_ASSIGN(Symtab);
 };
 
Index: include/lldb/Core/RichManglingInfo.h
===================================================================
--- /dev/null
+++ include/lldb/Core/RichManglingInfo.h
@@ -0,0 +1,95 @@
+//===-- RichManglingInfo.h --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RichManglingInfo_h_
+#define liblldb_RichManglingInfo_h_
+
+#include "lldb/lldb-private.h"
+#include "llvm/ADT/Any.h"
+#include "llvm/Demangle/Demangle.h"
+
+namespace lldb_private {
+
+/// Uniform wrapper for access to rich mangling information from different
+/// providers. See Mangled::DemangleWithRichManglingInfo()
+class RichManglingInfo {
+public:
+  /// If this symbol describes a constructor or destructor.
+  bool IsCtorOrDtor() const;
+
+  /// If this symbol describes a function.
+  bool IsFunction() const;
+
+  /// Get the base name of a function. This doesn't include trailing template
+  /// arguments, ie for "a::b<int>" this function returns "b".
+  const char *GetFunctionBaseName() const;
+
+  /// Get the context name for a function. For "a::b::c", this function returns
+  /// "a::b".
+  const char *GetFunctionDeclContextName() const;
+
+private:
+  enum InfoProvider { ItaniumPartialDemangler, PluginCxxLanguage };
+
+  /// Selects the rich mangling info provider. Initially undefined. Configured
+  /// from RichManglingContext::SetX (instance not accessible before).
+  InfoProvider m_provider;
+
+  /// Members for ItaniumPartialDemangler
+  llvm::ItaniumPartialDemangler *m_IPD = nullptr;
+  mutable size_t m_IPD_size = 0;
+  mutable char *m_IPD_buf = nullptr;
+
+  /// Members for PluginCxxLanguage
+  /// Cannot forward declare inner class CPlusPlusLanguage::MethodName. The
+  /// respective header is in Plugins and including it from here causes cyclic
+  /// dependency. Instead keep a llvm::Any and cast it on-access in the cpp.
+  mutable llvm::Any m_legacy_parser;
+
+  /// Obtain the legacy parser casted to the given type. Ideally we had a type
+  /// trait to deduce \a ParserT from a given InfoProvider, but unfortunately we
+  /// can't access CPlusPlusLanguage::MethodName from within the header.
+  template <class ParserT> ParserT *get() const {
+    assert(m_legacy_parser.hasValue());
+    assert(llvm::any_isa<ParserT>(m_legacy_parser));
+    return llvm::any_cast<ParserT *>(m_legacy_parser);
+  }
+
+  /// Reset the provider and clean up memory before reassigning/destroying.
+  void ResetProvider();
+
+  // Default construction in undefined state from RichManglingContext.
+  RichManglingInfo() = default;
+
+  // Destruction from RichManglingContext.
+  ~RichManglingInfo();
+
+  // Declare RichManglingContext as friend so it can access the default ctor and
+  // assign to members in its SetX methods.
+  friend class RichManglingContext;
+};
+
+//----------------------------------------------------------------------
+
+/// Unique owner of RichManglingInfo. Handles configuration and lifetime.
+class RichManglingContext {
+public:
+  RichManglingInfo *SetItaniumInfo();
+  RichManglingInfo *SetLegacyCxxParserInfo(const ConstString &mangled);
+
+  llvm::ItaniumPartialDemangler &GetIPD() { return m_IPD; }
+
+private:
+  RichManglingInfo m_info;
+  llvm::ItaniumPartialDemangler m_IPD;
+};
+
+} // namespace lldb_private
+
+#endif
Index: include/lldb/Core/Mangled.h
===================================================================
--- include/lldb/Core/Mangled.h
+++ include/lldb/Core/Mangled.h
@@ -11,18 +11,13 @@
 #define liblldb_Mangled_h_
 #if defined(__cplusplus)
 
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
 #include "lldb/Utility/ConstString.h"
-#include "lldb/lldb-enumerations.h" // for LanguageType
-#include "llvm/ADT/StringRef.h"     // for StringRef
+#include "llvm/ADT/StringRef.h"
 
-#include <stddef.h> // for size_t
-
-namespace lldb_private {
-class RegularExpression;
-}
-namespace lldb_private {
-class Stream;
-}
+#include <memory>
+#include <stddef.h>
 
 namespace lldb_private {
 
@@ -238,7 +233,6 @@
       return true;
     return GetDemangledName(language) == name;
   }
-
   bool NameMatches(const RegularExpression &regex,
                    lldb::LanguageType language) const;
 
@@ -300,6 +294,38 @@
   //----------------------------------------------------------------------
   lldb::LanguageType GuessLanguage() const;
 
+  /// Function signature for filtering mangled names.
+  using SkipMangledNameFn = bool(llvm::StringRef, ManglingScheme);
+
+  //----------------------------------------------------------------------
+  /// Trigger explicit demangling to obtain rich mangling information. This is
+  /// optimized for batch processing while populating a name index. To get the
+  /// pure demangled name string for a single entity, use GetDemangledName()
+  /// instead.
+  ///
+  /// For names that match the Itanium mangling scheme, this uses LLVM's
+  /// ItaniumPartialDemangler. All other names fall back to LLDB's builtin
+  /// parser currently.
+  ///
+  /// This function is thread-safe when used with different \a context
+  /// instances in different threads.
+  ///
+  /// @param[in] context
+  ///     The context for this function. A single instance can be stack-
+  ///     allocated in the caller's frame and used for multiple calls.
+  ///
+  /// @param[in] skip_mangled_name
+  ///     A filtering function for skipping entities based on name and mangling
+  ///     scheme. This can be null if unused.
+  ///
+  /// @return
+  ///     The rich mangling info on success, null otherwise. Expect the pointer
+  ///     to be valid only until the next call to this funtion.
+  //----------------------------------------------------------------------
+  const RichManglingInfo *
+  DemangleWithRichManglingInfo(RichManglingContext &context,
+                               SkipMangledNameFn *skip_mangled_name);
+
 private:
   //----------------------------------------------------------------------
   /// Mangled member variables.
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to