sgraenitz updated this revision to Diff 159065.
sgraenitz added a comment.

Polishing


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"
@@ -23,6 +24,8 @@
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/Timer.h"
 
+#include "llvm/ADT/StringRef.h"
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -215,6 +218,39 @@
 //----------------------------------------------------------------------
 // InitNameIndexes
 //----------------------------------------------------------------------
+static 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;
+  }
+}
+
 void Symtab::InitNameIndexes() {
   // Protected function, no need to lock mutex...
   if (!m_name_indexes_computed) {
@@ -243,25 +279,30 @@
     m_name_to_index.Reserve(actual_count);
 #endif
 
-    NameToIndexMap::Entry entry;
-
-    // The "const char *" in "class_contexts" must come from a
-    // ConstString::GetCString()
+    // The "const char *" in "class_contexts" and backlog::value_type::second
+    // 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);
+    std::vector<std::pair<NameToIndexMap::Entry, const char *>> backlog;
+    backlog.reserve(num_symbols / 2);
+
+    // 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 +315,15 @@
           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 (mangled.DemangleWithRichManglingInfo(MC, lldb_skip_name))
+            RegisterMangledNameEntry(entry, class_contexts, backlog, MC);
         }
       }
 
+      // 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);
@@ -367,25 +353,10 @@
       }
     }
 
-    size_t count;
-    if (!mangled_name_to_index.IsEmpty()) {
-      count = mangled_name_to_index.GetSize();
-      for (size_t i = 0; i < count; ++i) {
-        if (mangled_name_to_index.GetValueAtIndex(i, entry.value)) {
-          entry.cstring = mangled_name_to_index.GetCStringAtIndex(i);
-          if (symbol_contexts[entry.value] &&
-              class_contexts.find(symbol_contexts[entry.value]) !=
-                  class_contexts.end()) {
-            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
-            m_method_to_index.Append(entry);
-            m_basename_to_index.Append(entry);
-          }
-        }
-      }
+    for (const auto &record : backlog) {
+      RegisterBacklogEntry(record.first, record.second, class_contexts);
     }
+
     m_name_to_index.Sort();
     m_name_to_index.SizeToFit();
     m_selector_to_index.Sort();
@@ -397,6 +368,70 @@
   }
 }
 
+void Symtab::RegisterMangledNameEntry(
+    NameToIndexMap::Entry &entry, std::set<const char *> &class_contexts,
+    std::vector<std::pair<NameToIndexMap::Entry, const char *>> backlog,
+    RichManglingContext &MC) {
+  // Only register functions that have a base name.
+  MC.ParseFunctionBaseName();
+  llvm::StringRef base_name = MC.GetBufferRef();
+  if (base_name.empty())
+    return;
+
+  // The base name will be our entry's name.
+  entry.cstring = ConstString(base_name);
+
+  // Register functions with no context.
+  MC.ParseFunctionDeclContextName();
+  const char *decl_context_cstr = MC.GetBufferAsCString();
+  if (decl_context_cstr == nullptr || decl_context_cstr[0] == '\0') {
+    // 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;
+  }
+
+  // Add to the pool and see if we already know the context name. Note that
+  // decl_context_cstr is not identical to decl_context_ccstr.GetCString()!
+  ConstString decl_context_ccstr(decl_context_cstr);
+  auto it = class_contexts.find(decl_context_ccstr.GetCString());
+
+  // Register constructors and destructors. They are methods and create
+  // declaration contexts.
+  if (MC.IsCtorOrDtor()) {
+    m_method_to_index.Append(entry);
+    if (it == class_contexts.end())
+      class_contexts.insert(it, decl_context_ccstr.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.
+  backlog.push_back(std::make_pair(entry, decl_context_ccstr.GetCString()));
+}
+
+void Symtab::RegisterBacklogEntry(
+    const NameToIndexMap::Entry &entry, const char *decl_context, 
+    const std::set<const char *> &class_contexts) {
+  auto it = class_contexts.find(decl_context);
+  if (it != class_contexts.end()) {
+    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 the entry
+    m_method_to_index.Append(entry);
+    m_basename_to_index.Append(entry);
+  }
+}
+
 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,175 @@
+//===-- 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/Log.h"
+#include "lldb/Utility/Logging.h"
+
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RichManglingContext
+//----------------------------------------------------------------------
+void RichManglingContext::ResetProvider(InfoProvider new_provider) {
+  // If we want to support parsers for other languages some day, we need a
+  // switch here to delete the correct parser type.
+  if (m_cxx_method_parser.hasValue()) {
+    assert(m_provider == PluginCxxLanguage);
+    delete get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser);
+    m_cxx_method_parser.reset();
+  }
+
+  assert(new_provider != None && "Only reset to a valid provider");
+  m_provider = new_provider;
+}
+
+bool RichManglingContext::FromItaniumName(const ConstString &mangled) {
+  bool err = m_IPD.partialDemangle(mangled.GetCString());
+  if (!err) {
+    ResetProvider(ItaniumPartialDemangler);
+  }
+
+  if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
+    if (!err) {
+      ParseFullName();
+      log->Printf("demangled itanium: %s -> \"%s\"", mangled.GetCString(),
+                  GetBufferAsCString());
+    } else {
+      log->Printf("demangled itanium: %s -> error: failed to demangle",
+                  mangled.GetCString());
+    }
+  }
+
+  return !err; // true == success
+}
+
+bool RichManglingContext::FromCxxMethodName(const ConstString &demangled) {
+  ResetProvider(PluginCxxLanguage);
+  m_cxx_method_parser = new CPlusPlusLanguage::MethodName(demangled);
+  return true;
+}
+
+bool RichManglingContext::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>(m_cxx_method_parser)->GetBasename();
+    return base_name.front() == '~';
+  }
+  case None:
+    assert(false && "Initialize with a provider");
+    return false;
+  }
+}
+
+bool RichManglingContext::IsFunction() const {
+  switch (m_provider) {
+  case ItaniumPartialDemangler:
+    return m_IPD.isFunction();
+  case PluginCxxLanguage:
+    return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->IsValid();
+  case None:
+    assert(false && "Initialize with a provider");
+    return false;
+  }
+}
+
+void RichManglingContext::processIPDStrResult(char *IPD_res, size_t res_size) {
+  if (LLVM_UNLIKELY(IPD_res == nullptr)) {
+    assert(res_size == m_IPD_size &&
+           "Failed IPD queries keep the original size in the N parameter");
+
+    // Error case: Clear the buffer.
+    m_IPD_str_len = 0;
+    m_IPD_buf[m_IPD_str_len] = '\0';
+  } else {
+    // IPD's res_size includes null terminator.
+    size_t res_len = res_size - 1;
+    assert(IPD_res[res_len] == '\0' &&
+           "IPD returns null-terminated strings and we rely on that");
+
+    if (LLVM_UNLIKELY(IPD_res != m_IPD_buf)) {
+      // Realloc case: Take over the new buffer.
+      m_IPD_buf = IPD_res;   // std::realloc freed or reused the old buffer.
+      m_IPD_size = res_size; // Actual buffer may be bigger, but we can't know.
+      m_IPD_str_len = res_len;
+
+      Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE);
+      if (log)
+        log->Printf("ItaniumPartialDemangler Realloc: new buffer size %ul",
+                    m_IPD_size);
+    } else {
+      // 99% case: Just remember the string length.
+      m_IPD_str_len = res_len;
+    }
+  }
+}
+
+void RichManglingContext::ParseFunctionBaseName() {
+  switch (m_provider) {
+  case ItaniumPartialDemangler: {
+    auto multi_in_out = m_IPD_size;
+    auto buf = m_IPD.getFunctionBaseName(m_IPD_buf, &multi_in_out);
+    processIPDStrResult(buf, multi_in_out);
+    return;
+  }
+  case PluginCxxLanguage:
+    m_cxx_method_ccstr = ConstString(
+        get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename());
+    return;
+  case None:
+    assert(false && "Initialize with a provider");
+    return;
+  }
+}
+
+void RichManglingContext::ParseFunctionDeclContextName() {
+  switch (m_provider) {
+  case ItaniumPartialDemangler: {
+    auto multi_in_out = m_IPD_size;
+    auto buf = m_IPD.getFunctionDeclContextName(m_IPD_buf, &multi_in_out);
+    processIPDStrResult(buf, multi_in_out);
+    return;
+  }
+  case PluginCxxLanguage:
+    m_cxx_method_ccstr = ConstString(
+        get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetContext());
+    return;
+  case None:
+    assert(false && "Initialize with a provider");
+    return;
+  }
+}
+
+void RichManglingContext::ParseFullName() {
+  switch (m_provider) {
+  case ItaniumPartialDemangler: {
+    auto multi_in_out = m_IPD_size;
+    auto buf = m_IPD.finishDemangle(m_IPD_buf, &multi_in_out);
+    processIPDStrResult(buf, multi_in_out);
+    return;
+  }
+  case PluginCxxLanguage:
+    m_cxx_method_ccstr = ConstString(
+        get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetFullName());
+    return;
+  case None:
+    assert(false && "Initialize with a provider");
+    return;
+  }
+}
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,126 @@
   }
 }
 
+//----------------------------------------------------------------------
+// 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 *GetItaniumDemangledStr(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
+//----------------------------------------------------------------------
+bool 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 false;
+
+  switch (S) {
+  case eManglingSchemeNone:
+    // The current mangled_name_filter would allow llvm_unreachable here.
+    return false;
+
+  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 (context.FromItaniumName(m_mangled)) {
+      // If we got an info, we have a name. Connect the counterparts in the
+      // string pool to accelerate subsequent access in GetDemangledName().
+      context.ParseFullName();
+      const char *demangled_cstr = context.GetBufferAsCString();
+      m_demangled.SetCStringWithMangledCounterpart(demangled_cstr, m_mangled);
+      return true;
+    } else {
+      m_demangled.SetCString("");
+      return false;
+    }
+
+  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 false;
+    } else {
+      // Demangled successfully, we can try and parse it with
+      // CPlusPlusLanguage::MethodName.
+      return context.FromCxxMethodName(m_demangled);
+    }
+  }
+  }
+}
+
 //----------------------------------------------------------------------
 // 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 +363,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 +378,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 = GetItaniumDemangledStr(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
@@ -35,6 +35,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,15 @@
 
 } // namespace lldb
 
+//----------------------------------------------------------------------
+// llvm forward declarations
+//----------------------------------------------------------------------
+namespace llvm {
+
+struct ItaniumPartialDemangler;
+class StringRef;
+
+} // 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,15 @@
   void SymbolIndicesToSymbolContextList(std::vector<uint32_t> &symbol_indexes,
                                         SymbolContextList &sc_list);
 
+  void RegisterMangledNameEntry(
+      NameToIndexMap::Entry &entry, std::set<const char *> &class_contexts,
+      std::vector<std::pair<NameToIndexMap::Entry, const char *>> backlog,
+      RichManglingContext &MC);
+
+  void RegisterBacklogEntry(
+      const NameToIndexMap::Entry &entry, const char *decl_context, 
+      const std::set<const char *> &class_contexts);
+
   DISALLOW_COPY_AND_ASSIGN(Symtab);
 };
 
Index: include/lldb/Core/RichManglingInfo.h
===================================================================
--- /dev/null
+++ include/lldb/Core/RichManglingInfo.h
@@ -0,0 +1,118 @@
+//===-- 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-forward.h"
+#include "lldb/lldb-private.h"
+
+#include "lldb/Utility/ConstString.h"
+
+#include "llvm/ADT/Any.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Demangle/Demangle.h"
+
+namespace lldb_private {
+
+/// Uniform wrapper for access to rich mangling information from different
+/// providers. See Mangled::DemangleWithRichManglingInfo()
+class RichManglingContext {
+public:
+  RichManglingContext() : m_provider(None), m_IPD_size(2048), m_IPD_str_len(0) {
+    m_IPD_buf = static_cast<char *>(std::malloc(m_IPD_size));
+    m_IPD_buf[m_IPD_str_len] = '\0';
+  }
+
+  ~RichManglingContext() { std::free(m_IPD_buf); }
+
+  bool FromItaniumName(const ConstString &mangled);
+  bool FromCxxMethodName(const ConstString &demangled);
+
+  /// 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".
+  void ParseFunctionBaseName();
+
+  /// Get the context name for a function. For "a::b::c", this function returns
+  /// "a::b".
+  void ParseFunctionDeclContextName();
+
+  /// Get the entire demangled name.
+  void ParseFullName();
+
+  llvm::StringRef GetBufferRef() const {
+    switch (m_provider) {
+    case ItaniumPartialDemangler:
+      assert(m_IPD_buf && "Parse before accessing buffer");
+      return llvm::StringRef(m_IPD_buf, m_IPD_str_len);
+    case PluginCxxLanguage:
+      assert(!m_cxx_method_ccstr.IsNull() && "Parse before accessing buffer");
+      return m_cxx_method_ccstr.GetStringRef();
+    case None:
+      assert(false && "Initialize with a provider before accessing buffer");
+      return llvm::StringRef();
+    }
+  }
+
+  const char *GetBufferAsCString() const {
+    switch (m_provider) {
+    case ItaniumPartialDemangler:
+      assert(m_IPD_buf && "Parse before accessing buffer");
+      return m_IPD_buf;
+    case PluginCxxLanguage:
+      assert(!m_cxx_method_ccstr.IsNull() && "Parse before accessing buffer");
+      return m_cxx_method_ccstr.GetCString();
+    case None:
+      assert(false && "Initialize with a provider before accessing buffer");
+      return nullptr;
+    }
+  }
+
+private:
+  enum InfoProvider { None, ItaniumPartialDemangler, PluginCxxLanguage };
+
+  /// Selects the rich mangling info provider.
+  InfoProvider m_provider;
+
+  /// Members for ItaniumPartialDemangler
+  llvm::ItaniumPartialDemangler m_IPD;
+  char *m_IPD_buf;
+  size_t m_IPD_size;
+  size_t m_IPD_str_len;
+
+  /// 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.
+  llvm::Any m_cxx_method_parser;
+  ConstString m_cxx_method_ccstr;
+
+  void ResetProvider(InfoProvider new_provider);
+
+  void processIPDStrResult(char *IPD_res, size_t res_len);
+
+  /// Cast the given parser 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> static ParserT *get(llvm::Any parser) {
+    assert(parser.hasValue());
+    assert(llvm::any_isa<ParserT *>(parser));
+    return llvm::any_cast<ParserT *>(parser);
+  }
+};
+
+} // namespace lldb_private
+
+#endif
Index: include/lldb/Core/Mangled.h
===================================================================
--- include/lldb/Core/Mangled.h
+++ include/lldb/Core/Mangled.h
@@ -11,18 +11,15 @@
 #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 <stddef.h> // for size_t
+#include "llvm/ADT/StringRef.h"
 
-namespace lldb_private {
-class RegularExpression;
-}
-namespace lldb_private {
-class Stream;
-}
+#include <memory>
+#include <stddef.h>
 
 namespace lldb_private {
 
@@ -238,7 +235,6 @@
       return true;
     return GetDemangledName(language) == name;
   }
-
   bool NameMatches(const RegularExpression &regex,
                    lldb::LanguageType language) const;
 
@@ -300,6 +296,37 @@
   //----------------------------------------------------------------------
   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.
+  //----------------------------------------------------------------------
+  bool 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