[Lldb-commits] [lldb] r339291 - Use rich mangling information in Symtab::InitNameIndexes()

Stefan Granitz via lldb-commits lldb-commits at lists.llvm.org
Wed Aug 8 14:57:38 PDT 2018


Author: stefan.graenitz
Date: Wed Aug  8 14:57:37 2018
New Revision: 339291

URL: http://llvm.org/viewvc/llvm-project?rev=339291&view=rev
Log:
Use rich mangling information in Symtab::InitNameIndexes()

Summary:
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.

Reviewers: labath, jingham, JDevlieghere, erik.pilkington

Subscribers: zturner, clayborg, mgorny, lldb-commits

Differential Revision: https://reviews.llvm.org/D50071

Added:
    lldb/trunk/include/lldb/Core/RichManglingContext.h
    lldb/trunk/source/Core/RichManglingContext.cpp
    lldb/trunk/unittests/Core/RichManglingContextTest.cpp
Modified:
    lldb/trunk/include/lldb/Core/Mangled.h
    lldb/trunk/include/lldb/Symbol/Symtab.h
    lldb/trunk/include/lldb/lldb-forward.h
    lldb/trunk/lldb.xcodeproj/project.pbxproj
    lldb/trunk/source/Core/CMakeLists.txt
    lldb/trunk/source/Core/Mangled.cpp
    lldb/trunk/source/Symbol/Symtab.cpp
    lldb/trunk/unittests/Core/CMakeLists.txt

Modified: lldb/trunk/include/lldb/Core/Mangled.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Mangled.h?rev=339291&r1=339290&r2=339291&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/Mangled.h (original)
+++ lldb/trunk/include/lldb/Core/Mangled.h Wed Aug  8 14:57:37 2018
@@ -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 @@ public:
       return true;
     return GetDemangledName(language) == name;
   }
-
   bool NameMatches(const RegularExpression &regex,
                    lldb::LanguageType language) const;
 
@@ -300,6 +296,36 @@ public:
   //----------------------------------------------------------------------
   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
+  ///     True on success, false otherwise.
+  //----------------------------------------------------------------------
+  bool DemangleWithRichManglingInfo(RichManglingContext &context,
+                                    SkipMangledNameFn *skip_mangled_name);
+
 private:
   //----------------------------------------------------------------------
   /// Mangled member variables.

Added: lldb/trunk/include/lldb/Core/RichManglingContext.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/RichManglingContext.h?rev=339291&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Core/RichManglingContext.h (added)
+++ lldb/trunk/include/lldb/Core/RichManglingContext.h Wed Aug  8 14:57:37 2018
@@ -0,0 +1,110 @@
+//===-- RichManglingContext.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_RichManglingContext_h_
+#define liblldb_RichManglingContext_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_buf_size(2048), m_ipd_str_len(0) {
+    m_ipd_buf = static_cast<char *>(std::malloc(m_ipd_buf_size));
+    m_ipd_buf[m_ipd_str_len] = '\0';
+  }
+
+  ~RichManglingContext() { std::free(m_ipd_buf); }
+
+  /// Use the ItaniumPartialDemangler to obtain rich mangling information from
+  /// the given mangled name.
+  bool FromItaniumName(const ConstString &mangled);
+
+  /// Use the legacy language parser implementation to obtain rich mangling
+  /// information from the given demangled name.
+  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 "a::b<int>" gives "b". The result will overwrite the
+  /// internal buffer. It can be obtained via GetBufferRef().
+  void ParseFunctionBaseName();
+
+  /// Get the context name for a function. For "a::b::c", this function returns
+  /// "a::b". The result will overwrite the internal buffer. It can be obtained
+  /// via GetBufferRef().
+  void ParseFunctionDeclContextName();
+
+  /// Get the entire demangled name. The result will overwrite the internal
+  /// buffer. It can be obtained via GetBufferRef().
+  void ParseFullName();
+
+  /// Obtain a StringRef to the internal buffer that holds the result of the
+  /// most recent ParseXy() operation. The next ParseXy() call invalidates it.
+  llvm::StringRef GetBufferRef() const {
+    assert(m_provider != None && "Initialize a provider first");
+    return m_buffer;
+  }
+
+private:
+  enum InfoProvider { None, ItaniumPartialDemangler, PluginCxxLanguage };
+
+  /// Selects the rich mangling info provider.
+  InfoProvider m_provider;
+
+  /// Reference to the buffer used for results of ParseXy() operations.
+  llvm::StringRef m_buffer;
+
+  /// Members for ItaniumPartialDemangler
+  llvm::ItaniumPartialDemangler m_ipd;
+  char *m_ipd_buf;
+  size_t m_ipd_buf_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;
+
+  /// Clean up memory and set a new info provider for this instance.
+  void ResetProvider(InfoProvider new_provider);
+
+  /// Uniform handling of string buffers for ItaniumPartialDemangler.
+  void processIPDStrResult(char *ipd_res, size_t res_len);
+
+  /// Cast the given parser to the given type. Ideally we would have 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

Modified: lldb/trunk/include/lldb/Symbol/Symtab.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/Symtab.h?rev=339291&r1=339290&r2=339291&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/Symtab.h (original)
+++ lldb/trunk/include/lldb/Symbol/Symtab.h Wed Aug  8 14:57:37 2018
@@ -197,6 +197,15 @@ private:
   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 &rmc);
+
+  void RegisterBacklogEntry(const NameToIndexMap::Entry &entry,
+                            const char *decl_context,
+                            const std::set<const char *> &class_contexts);
+
   DISALLOW_COPY_AND_ASSIGN(Symtab);
 };
 

Modified: lldb/trunk/include/lldb/lldb-forward.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-forward.h?rev=339291&r1=339290&r2=339291&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-forward.h (original)
+++ lldb/trunk/include/lldb/lldb-forward.h Wed Aug  8 14:57:37 2018
@@ -191,6 +191,7 @@ class RegisterLocationList;
 class RegisterValue;
 class RegularExpression;
 class REPL;
+class RichManglingContext;
 class Scalar;
 class ScriptInterpreter;
 class ScriptInterpreterLocker;
@@ -492,5 +493,15 @@ typedef std::shared_ptr<lldb_private::Wa
 
 } // namespace lldb
 
+//----------------------------------------------------------------------
+// llvm forward declarations
+//----------------------------------------------------------------------
+namespace llvm {
+
+struct ItaniumPartialDemangler;
+class StringRef;
+
+} // namespace llvm
+
 #endif // #if defined(__cplusplus)
 #endif // LLDB_lldb_forward_h_

Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=339291&r1=339290&r2=339291&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Wed Aug  8 14:57:37 2018
@@ -487,6 +487,9 @@
 		8C3BD9961EF45DA50016C343 /* MainThreadCheckerRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C3BD9951EF45D9B0016C343 /* MainThreadCheckerRuntime.cpp */; };
 		2689004313353E0400698AC0 /* Mangled.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8010F1B85900F91463 /* Mangled.cpp */; };
 		4F29D3CF21010FA3003B549A /* MangledTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4F29D3CD21010F84003B549A /* MangledTest.cpp */; };
+		4FBC04EF211A06820015A814 /* RichManglingContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 4FBC04EE211A06820015A814 /* RichManglingContext.h */; };
+		4FBC04ED211A06200015A814 /* RichManglingContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4FBC04EC211A06200015A814 /* RichManglingContext.cpp */; };
+		4FBC04F5211A13770015A814 /* RichManglingContextTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4FBC04F3211A0F0F0015A814 /* RichManglingContextTest.cpp */; };
 		4CD44CFC20B37C440003557C /* ManualDWARFIndex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CD44CF920B37C440003557C /* ManualDWARFIndex.cpp */; };
 		49DCF702170E70120092F75E /* Materializer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49DCF700170E70120092F75E /* Materializer.cpp */; };
 		2690B3711381D5C300ECFBAE /* Memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2690B3701381D5C300ECFBAE /* Memory.cpp */; };
@@ -2198,6 +2201,9 @@
 		26BC7E8010F1B85900F91463 /* Mangled.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Mangled.cpp; path = source/Core/Mangled.cpp; sourceTree = "<group>"; };
 		26BC7D6910F1B77400F91463 /* Mangled.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mangled.h; path = include/lldb/Core/Mangled.h; sourceTree = "<group>"; };
 		4F29D3CD21010F84003B549A /* MangledTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MangledTest.cpp; sourceTree = "<group>"; };
+		4FBC04EE211A06820015A814 /* RichManglingContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RichManglingContext.h; path = include/lldb/Core/RichManglingContext.h; sourceTree = "<group>"; };
+		4FBC04EC211A06200015A814 /* RichManglingContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RichManglingContext.cpp; path = source/Core/RichManglingContext.cpp; sourceTree = "<group>"; };
+		4FBC04F3211A0F0F0015A814 /* RichManglingContextTest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RichManglingContextTest.cpp; sourceTree = "<group>"; };
 		4CD44CF920B37C440003557C /* ManualDWARFIndex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ManualDWARFIndex.cpp; sourceTree = "<group>"; };
 		4CD44D0020B37C580003557C /* ManualDWARFIndex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ManualDWARFIndex.h; sourceTree = "<group>"; };
 		2682100C143A59AE004BCF2D /* MappedHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MappedHash.h; path = include/lldb/Core/MappedHash.h; sourceTree = "<group>"; };
@@ -3676,13 +3682,14 @@
 		23CB14E51D66CBEB00EDDDE1 /* Core */ = {
 			isa = PBXGroup;
 			children = (
+				23CB14E61D66CC0E00EDDDE1 /* BroadcasterTest.cpp */,
+				23CB14E71D66CC0E00EDDDE1 /* CMakeLists.txt */,
+				23CB14E81D66CC0E00EDDDE1 /* DataExtractorTest.cpp */,
 				58A080B12112AB2200D5580F /* HighlighterTest.cpp */,
-				4F29D3CD21010F84003B549A /* MangledTest.cpp */,
 				9A3D43E31F3237D500EB767C /* ListenerTest.cpp */,
+				4F29D3CD21010F84003B549A /* MangledTest.cpp */,
+				4FBC04F3211A0F0F0015A814 /* RichManglingContextTest.cpp */,
 				9A3D43E11F3237D500EB767C /* StreamCallbackTest.cpp */,
-				23CB14E71D66CC0E00EDDDE1 /* CMakeLists.txt */,
-				23CB14E61D66CC0E00EDDDE1 /* BroadcasterTest.cpp */,
-				23CB14E81D66CC0E00EDDDE1 /* DataExtractorTest.cpp */,
 			);
 			path = Core;
 			sourceTree = "<group>";
@@ -5047,6 +5054,8 @@
 				26BC7D7110F1B77400F91463 /* PluginManager.h */,
 				26BC7E8A10F1B85900F91463 /* PluginManager.cpp */,
 				2626B6AD143E1BEA00EF935C /* RangeMap.h */,
+				4FBC04EE211A06820015A814 /* RichManglingContext.h */,
+				4FBC04EC211A06200015A814 /* RichManglingContext.cpp */,
 				26BC7CF910F1B71400F91463 /* SearchFilter.h */,
 				26BC7E1510F1B83100F91463 /* SearchFilter.cpp */,
 				26BC7D7510F1B77400F91463 /* Section.h */,
@@ -6955,6 +6964,7 @@
 				2619C4862107A9A2009CDE81 /* RegisterContextMinidump_ARM64.h in Headers */,
 				AF235EB11FBE77B6009C5541 /* RegisterContextPOSIX_ppc64le.h in Headers */,
 				267F68501CC02E270086832B /* RegisterContextPOSIXCore_s390x.h in Headers */,
+				4FBC04EF211A06820015A814 /* RichManglingContext.h in Headers */,
 				4984BA181B979C08008658D4 /* ExpressionVariable.h in Headers */,
 				26C7C4841BFFEA7E009BD01F /* WindowsMiniDump.h in Headers */,
 				30B38A001CAAA6D7009524E3 /* ClangUtil.h in Headers */,
@@ -7473,6 +7483,7 @@
 				9A2057181F3B861400F6C293 /* TestType.cpp in Sources */,
 				9A2057171F3B861400F6C293 /* TestDWARFCallFrameInfo.cpp in Sources */,
 				4F29D3CF21010FA3003B549A /* MangledTest.cpp in Sources */,
+				4FBC04F5211A13770015A814 /* RichManglingContextTest.cpp in Sources */,
 				9A3D43EC1F3237F900EB767C /* ListenerTest.cpp in Sources */,
 				9A3D43DC1F3151C400EB767C /* TimeoutTest.cpp in Sources */,
 				9A3D43D61F3151C400EB767C /* ConstStringTest.cpp in Sources */,
@@ -7590,6 +7601,7 @@
 				4C0083401B9F9BA900D5CF24 /* UtilityFunction.cpp in Sources */,
 				AF415AE71D949E4400FCE0D4 /* x86AssemblyInspectionEngine.cpp in Sources */,
 				26474CCD18D0CB5B0073DEBA /* RegisterContextPOSIX_x86.cpp in Sources */,
+				4FBC04ED211A06200015A814 /* RichManglingContext.cpp in Sources */,
 				AEB0E4591BD6E9F800B24093 /* LLVMUserExpression.cpp in Sources */,
 				2689FFEF13353DB600698AC0 /* Breakpoint.cpp in Sources */,
 				267A47FB1B1411C40021A5BC /* NativeRegisterContext.cpp in Sources */,

Modified: lldb/trunk/source/Core/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/CMakeLists.txt?rev=339291&r1=339290&r2=339291&view=diff
==============================================================================
--- lldb/trunk/source/Core/CMakeLists.txt (original)
+++ lldb/trunk/source/Core/CMakeLists.txt Wed Aug  8 14:57:37 2018
@@ -34,6 +34,7 @@ add_lldb_library(lldbCore
   ModuleList.cpp
   Opcode.cpp
   PluginManager.cpp
+  RichManglingContext.cpp
   SearchFilter.cpp
   Section.cpp
   SourceManager.cpp

Modified: lldb/trunk/source/Core/Mangled.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Mangled.cpp?rev=339291&r1=339290&r2=339291&view=diff
==============================================================================
--- lldb/trunk/source/Core/Mangled.cpp (original)
+++ lldb/trunk/source/Core/Mangled.cpp Wed Aug  8 14:57:37 2018
@@ -16,6 +16,7 @@
 #pragma comment(lib, "dbghelp.lib")
 #endif
 
+#include "lldb/Core/RichManglingContext.h"
 #include "lldb/Utility/ConstString.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/Logging.h"
@@ -233,6 +234,128 @@ void Mangled::SetValue(const ConstString
 }
 
 //----------------------------------------------------------------------
+// Local helpers for different demangling implementations.
+//----------------------------------------------------------------------
+static char *GetMSVCDemangledStr(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
+}
+
+static 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);
+
+    assert(demangled_cstr &&
+           "finishDemangle must always succeed if partialDemangle did");
+    assert(demangled_cstr[demangled_size - 1] == '\0' &&
+           "Expected demangled_size to return length including trailing null");
+  }
+
+  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;
+}
+
+//----------------------------------------------------------------------
+// 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.
+  ManglingScheme scheme = cstring_mangling_scheme(m_mangled.GetCString());
+  if (skip_mangled_name && skip_mangled_name(m_mangled.GetStringRef(), scheme))
+    return false;
+
+  switch (scheme) {
+  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. Copy to string pool and connect the
+      // counterparts to accelerate later access in GetDemangledName().
+      context.ParseFullName();
+      m_demangled.SetStringWithMangledCounterpart(context.GetBufferRef(),
+                                                  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 = GetMSVCDemangledStr(m_mangled.GetCString())) {
+        // If we got an info, we have a name. Copy to string pool and connect
+        // the counterparts to accelerate later access in GetDemangledName().
+        m_demangled.SetStringWithMangledCounterpart(llvm::StringRef(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
 // name. The result is cached and will be kept until a new string value is
@@ -248,8 +371,6 @@ Mangled::GetDemangledName(lldb::Language
     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,56 +380,20 @@ Mangled::GetDemangledName(lldb::Language
       // 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 = GetMSVCDemangledStr(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);
-        }
+        llvm::ItaniumPartialDemangler ipd;
+        demangled_name = GetItaniumDemangledStr(mangled_name, ipd);
         break;
       }
       case eManglingSchemeNone:
-        break;
+        llvm_unreachable("eManglingSchemeNone was handled already");
       }
       if (demangled_name) {
-        m_demangled.SetStringWithMangledCounterpart(demangled_name, m_mangled);
+        m_demangled.SetStringWithMangledCounterpart(
+            llvm::StringRef(demangled_name), m_mangled);
         free(demangled_name);
       }
     }

Added: lldb/trunk/source/Core/RichManglingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/RichManglingContext.cpp?rev=339291&view=auto
==============================================================================
--- lldb/trunk/source/Core/RichManglingContext.cpp (added)
+++ lldb/trunk/source/Core/RichManglingContext.cpp Wed Aug  8 14:57:37 2018
@@ -0,0 +1,178 @@
+//===-- RichManglingContext.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/RichManglingContext.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();
+      LLDB_LOG(log, "demangled itanium: {0} -> \"{1}\"", mangled, m_ipd_buf);
+    } else {
+      LLDB_LOG(log, "demangled itanium: {0} -> error: failed to demangle",
+               mangled);
+    }
+  }
+
+  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 {
+  assert(m_provider != None && "Initialize a provider first");
+  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.startswith("~");
+  }
+  case None:
+    return false;
+  }
+}
+
+bool RichManglingContext::IsFunction() const {
+  assert(m_provider != None && "Initialize a provider first");
+  switch (m_provider) {
+  case ItaniumPartialDemangler:
+    return m_ipd.isFunction();
+  case PluginCxxLanguage:
+    return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->IsValid();
+  case None:
+    return false;
+  }
+}
+
+void RichManglingContext::processIPDStrResult(char *ipd_res, size_t res_size) {
+  if (LLVM_UNLIKELY(ipd_res == nullptr)) {
+    assert(res_size == m_ipd_buf_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_buf_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 %lu",
+                    m_ipd_buf_size);
+    } else {
+      // 99% case: Just remember the string length.
+      m_ipd_str_len = res_len;
+    }
+  }
+
+  m_buffer = llvm::StringRef(m_ipd_buf, m_ipd_str_len);
+}
+
+void RichManglingContext::ParseFunctionBaseName() {
+  assert(m_provider != None && "Initialize a provider first");
+  switch (m_provider) {
+  case ItaniumPartialDemangler: {
+    auto n = m_ipd_buf_size;
+    auto buf = m_ipd.getFunctionBaseName(m_ipd_buf, &n);
+    processIPDStrResult(buf, n);
+    return;
+  }
+  case PluginCxxLanguage:
+    m_buffer =
+        get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename();
+    return;
+  case None:
+    return;
+  }
+}
+
+void RichManglingContext::ParseFunctionDeclContextName() {
+  assert(m_provider != None && "Initialize a provider first");
+  switch (m_provider) {
+  case ItaniumPartialDemangler: {
+    auto n = m_ipd_buf_size;
+    auto buf = m_ipd.getFunctionDeclContextName(m_ipd_buf, &n);
+    processIPDStrResult(buf, n);
+    return;
+  }
+  case PluginCxxLanguage:
+    m_buffer =
+        get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetContext();
+    return;
+  case None:
+    return;
+  }
+}
+
+void RichManglingContext::ParseFullName() {
+  assert(m_provider != None && "Initialize a provider first");
+  switch (m_provider) {
+  case ItaniumPartialDemangler: {
+    auto n = m_ipd_buf_size;
+    auto buf = m_ipd.finishDemangle(m_ipd_buf, &n);
+    processIPDStrResult(buf, n);
+    return;
+  }
+  case PluginCxxLanguage:
+    m_buffer = get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
+                   ->GetFullName()
+                   .GetStringRef();
+    return;
+  case None:
+    return;
+  }
+}

Modified: lldb/trunk/source/Symbol/Symtab.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/Symtab.cpp?rev=339291&r1=339290&r2=339291&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/Symtab.cpp (original)
+++ lldb/trunk/source/Symbol/Symtab.cpp Wed Aug  8 14:57:37 2018
@@ -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/RichManglingContext.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 @@ const Symbol *Symtab::SymbolAtIndex(size
 //----------------------------------------------------------------------
 // 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,16 +279,19 @@ void Symtab::InitNameIndexes() {
     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 rmc;
+    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
@@ -261,7 +300,9 @@ void Symtab::InitNameIndexes() {
       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 @@ void Symtab::InitNameIndexes() {
           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(rmc, lldb_skip_name))
+            RegisterMangledNameEntry(entry, class_contexts, backlog, rmc);
         }
       }
 
+      // 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 @@ void Symtab::InitNameIndexes() {
       }
     }
 
-    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,71 @@ void Symtab::InitNameIndexes() {
   }
 }
 
+void Symtab::RegisterMangledNameEntry(
+    NameToIndexMap::Entry &entry, std::set<const char *> &class_contexts,
+    std::vector<std::pair<NameToIndexMap::Entry, const char *>> &backlog,
+    RichManglingContext &rmc) {
+  // Only register functions that have a base name.
+  rmc.ParseFunctionBaseName();
+  llvm::StringRef base_name = rmc.GetBufferRef();
+  if (base_name.empty())
+    return;
+
+  // The base name will be our entry's name.
+  entry.cstring = ConstString(base_name);
+
+  rmc.ParseFunctionDeclContextName();
+  llvm::StringRef decl_context = rmc.GetBufferRef();
+
+  // Register functions with no context.
+  if (decl_context.empty()) {
+    // 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;
+  }
+
+  // Make sure we have a pool-string pointer and see if we already know the
+  // context name.
+  const char *decl_context_ccstr = ConstString(decl_context).GetCString();
+  auto it = class_contexts.find(decl_context_ccstr);
+
+  // Register constructors and destructors. They are methods and create
+  // declaration contexts.
+  if (rmc.IsCtorOrDtor()) {
+    m_method_to_index.Append(entry);
+    if (it == class_contexts.end())
+      class_contexts.insert(it, decl_context_ccstr);
+    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));
+}
+
+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();

Modified: lldb/trunk/unittests/Core/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Core/CMakeLists.txt?rev=339291&r1=339290&r2=339291&view=diff
==============================================================================
--- lldb/trunk/unittests/Core/CMakeLists.txt (original)
+++ lldb/trunk/unittests/Core/CMakeLists.txt Wed Aug  8 14:57:37 2018
@@ -4,6 +4,7 @@ add_lldb_unittest(LLDBCoreTests
   EventTest.cpp
   ListenerTest.cpp
   MangledTest.cpp
+  RichManglingContextTest.cpp
   StreamCallbackTest.cpp
 
   LINK_LIBS

Added: lldb/trunk/unittests/Core/RichManglingContextTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Core/RichManglingContextTest.cpp?rev=339291&view=auto
==============================================================================
--- lldb/trunk/unittests/Core/RichManglingContextTest.cpp (added)
+++ lldb/trunk/unittests/Core/RichManglingContextTest.cpp Wed Aug  8 14:57:37 2018
@@ -0,0 +1,114 @@
+//===-- RichManglingContextTest.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/RichManglingContext.h"
+
+#include "lldb/Utility/ConstString.h"
+
+#include "gtest/gtest.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+TEST(RichManglingContextTest, Basic) {
+  RichManglingContext RMC;
+  ConstString mangled("_ZN3foo3barEv");
+  EXPECT_TRUE(RMC.FromItaniumName(mangled));
+
+  EXPECT_TRUE(RMC.IsFunction());
+  EXPECT_FALSE(RMC.IsCtorOrDtor());
+
+  RMC.ParseFunctionDeclContextName();
+  EXPECT_EQ("foo", RMC.GetBufferRef());
+
+  RMC.ParseFunctionBaseName();
+  EXPECT_EQ("bar", RMC.GetBufferRef());
+
+  RMC.ParseFullName();
+  EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
+}
+
+TEST(RichManglingContextTest, FromCxxMethodName) {
+  RichManglingContext ItaniumRMC;
+  ConstString mangled("_ZN3foo3barEv");
+  EXPECT_TRUE(ItaniumRMC.FromItaniumName(mangled));
+
+  RichManglingContext CxxMethodRMC;
+  ConstString demangled("foo::bar()");
+  EXPECT_TRUE(CxxMethodRMC.FromCxxMethodName(demangled));
+
+  EXPECT_TRUE(ItaniumRMC.IsFunction() == CxxMethodRMC.IsFunction());
+  EXPECT_TRUE(ItaniumRMC.IsCtorOrDtor() == CxxMethodRMC.IsCtorOrDtor());
+
+  ItaniumRMC.ParseFunctionDeclContextName();
+  CxxMethodRMC.ParseFunctionDeclContextName();
+  EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef());
+
+  ItaniumRMC.ParseFunctionBaseName();
+  CxxMethodRMC.ParseFunctionBaseName();
+  EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef());
+
+  ItaniumRMC.ParseFullName();
+  CxxMethodRMC.ParseFullName();
+  EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef());
+}
+
+TEST(RichManglingContextTest, SwitchProvider) {
+  RichManglingContext RMC;
+  llvm::StringRef mangled = "_ZN3foo3barEv";
+  llvm::StringRef demangled = "foo::bar()";
+
+  EXPECT_TRUE(RMC.FromItaniumName(ConstString(mangled)));
+  RMC.ParseFullName();
+  EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
+
+  EXPECT_TRUE(RMC.FromCxxMethodName(ConstString(demangled)));
+  RMC.ParseFullName();
+  EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
+
+  EXPECT_TRUE(RMC.FromItaniumName(ConstString(mangled)));
+  RMC.ParseFullName();
+  EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
+}
+
+TEST(RichManglingContextTest, IPDRealloc) {
+  // The demangled name should fit into the Itanium default buffer.
+  const char *short_mangled = "_ZN3foo3barEv";
+
+  // The demangled name for this will certainly not fit into the default buffer.
+  const char *long_mangled =
+      "_ZNK3shk6detail17CallbackPublisherIZNS_5ThrowERKNSt15__exception_"
+      "ptr13exception_ptrEEUlOT_E_E9SubscribeINS0_9ConcatMapINS0_"
+      "18CallbackSubscriberIZNS_6GetAllIiNS1_IZZNS_9ConcatMapIZNS_6ConcatIJNS1_"
+      "IZZNS_3MapIZZNS_7IfEmptyIS9_EEDaS7_ENKUlS6_E_clINS1_IZZNS_4TakeIiEESI_"
+      "S7_ENKUlS6_E_clINS1_IZZNS_6FilterIZNS_9ElementAtEmEUlS7_E_EESI_S7_"
+      "ENKUlS6_E_clINS1_IZZNSL_ImEESI_S7_ENKUlS6_E_clINS1_IZNS_4FromINS0_"
+      "22InfiniteRangeContainerIiEEEESI_S7_EUlS7_E_EEEESI_S6_EUlS7_E_EEEESI_S6_"
+      "EUlS7_E_EEEESI_S6_EUlS7_E_EEEESI_S6_EUlS7_E_EESI_S7_ENKUlS6_E_clIS14_"
+      "EESI_S6_EUlS7_E_EERNS1_IZZNSH_IS9_EESI_S7_ENKSK_IS14_EESI_S6_EUlS7_E0_"
+      "EEEEESI_DpOT_EUlS7_E_EESI_S7_ENKUlS6_E_clINS1_IZNS_5StartIJZNS_"
+      "4JustIJS19_S1C_EEESI_S1F_EUlvE_ZNS1K_IJS19_S1C_EEESI_S1F_EUlvE0_EEESI_"
+      "S1F_EUlS7_E_EEEESI_S6_EUlS7_E_EEEESt6vectorIS6_SaIS6_EERKT0_NS_"
+      "12ElementCountEbEUlS7_E_ZNSD_IiS1Q_EES1T_S1W_S1X_bEUlOS3_E_ZNSD_IiS1Q_"
+      "EES1T_S1W_S1X_bEUlvE_EES1G_S1O_E25ConcatMapValuesSubscriberEEEDaS7_";
+
+  RichManglingContext RMC;
+
+  // Demangle the short one and remember the buffer address.
+  EXPECT_TRUE(RMC.FromItaniumName(ConstString(short_mangled)));
+  RMC.ParseFullName();
+  const char *short_demangled_ptr = RMC.GetBufferRef().data();
+
+  // Demangle the long one and make sure the buffer address changed.
+  EXPECT_TRUE(RMC.FromItaniumName(ConstString(long_mangled)));
+  RMC.ParseFullName();
+  const char *long_demangled_ptr = RMC.GetBufferRef().data();
+
+  EXPECT_TRUE(short_demangled_ptr != long_demangled_ptr);
+}




More information about the lldb-commits mailing list