Index: include/lldb/Utility/ConstString.h =================================================================== --- include/lldb/Utility/ConstString.h +++ include/lldb/Utility/ConstString.h @@ -480,6 +480,18 @@ } // namespace lldb_private +namespace std { +template<> +struct hash { + size_t operator()(const lldb_private::ConstString & str) const { + return m_substr_hash(str.GetCString()); + } + +private: + std::hash m_substr_hash; +}; +} // namespace std + namespace llvm { template <> struct format_provider { static void format(const lldb_private::ConstString &CS, llvm::raw_ostream &OS, Index: source/Symbol/Symtab.cpp =================================================================== --- source/Symbol/Symtab.cpp +++ source/Symbol/Symtab.cpp @@ -22,6 +22,7 @@ #include "lldb/Symbol/Symtab.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" +#include "lldb/Utility/TaskPool.h" using namespace lldb; using namespace lldb_private; @@ -243,16 +244,17 @@ 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 class_contexts; - UniqueCStringMap mangled_name_to_index; - std::vector symbol_contexts(num_symbols, nullptr); + struct demangle_state { + ConstString name_to_index[5]; + ConstString selector_to_index[1]; + ConstString const_context; + ConstString cxx_basename; + bool is_definitely_class_context = false; + }; + std::vector states(num_symbols); - for (entry.value = 0; entry.value < num_symbols; ++entry.value) { - const Symbol *symbol = &m_symbols[entry.value]; + auto symbol_fn = [&states, this](size_t value) { + const Symbol *symbol = &m_symbols[value]; // Don't let trampolines get into the lookup by name map // If we ever need the trampoline symbols to be searchable by name @@ -260,25 +262,26 @@ // Symtab functions that lookup symbols by name to indicate if they // want trampolines. if (symbol->IsTrampoline()) - continue; + return; + demangle_state &state = states[value]; const Mangled &mangled = symbol->GetMangled(); - entry.cstring = mangled.GetMangledName(); - if (entry.cstring) { - m_name_to_index.Append(entry); + ConstString cstring = mangled.GetMangledName(); + if (cstring) { + state.name_to_index[0] = cstring; if (symbol->ContainsLinkerAnnotations()) { // If the symbol has linker annotations, also add the version without // the annotations. - entry.cstring = ConstString(m_objfile->StripLinkerSymbolAnnotations( - entry.cstring.GetStringRef())); - m_name_to_index.Append(entry); + cstring = ConstString(m_objfile->StripLinkerSymbolAnnotations( + cstring.GetStringRef())); + state.name_to_index[1] = cstring; } const SymbolType symbol_type = symbol->GetType(); if (symbol_type == eSymbolTypeCode || symbol_type == eSymbolTypeResolver) { - llvm::StringRef entry_ref(entry.cstring.GetStringRef()); + llvm::StringRef entry_ref(cstring.GetStringRef()); if (entry_ref[0] == '_' && entry_ref[1] == 'Z' && (entry_ref[2] != 'T' && // avoid virtual table, VTT structure, // typeinfo structure, and typeinfo @@ -290,103 +293,92 @@ { CPlusPlusLanguage::MethodName cxx_method( mangled.GetDemangledName(lldb::eLanguageTypeC_plus_plus)); - entry.cstring = ConstString(cxx_method.GetBasename()); - if (entry.cstring) { + cstring = ConstString(cxx_method.GetBasename()); + if (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; - } - } - } + entry_ref = cstring.GetStringRef(); + ConstString const_context = ConstString(cxx_method.GetContext()); + + state.const_context = const_context; + state.cxx_basename = cstring; + state.is_definitely_class_context = entry_ref[0] == '~' || + !cxx_method.GetQualifiers().empty(); } } } } - entry.cstring = mangled.GetDemangledName(symbol->GetLanguage()); - if (entry.cstring) { - m_name_to_index.Append(entry); + cstring = mangled.GetDemangledName(symbol->GetLanguage()); + if (cstring) { + state.name_to_index[2] = cstring; if (symbol->ContainsLinkerAnnotations()) { // If the symbol has linker annotations, also add the version without // the annotations. - entry.cstring = ConstString(m_objfile->StripLinkerSymbolAnnotations( - entry.cstring.GetStringRef())); - m_name_to_index.Append(entry); + cstring = ConstString(m_objfile->StripLinkerSymbolAnnotations( + cstring.GetStringRef())); + state.name_to_index[3] = cstring; } } // If the demangled name turns out to be an ObjC name, and // is a category name, add the version without categories to the index // too. - ObjCLanguage::MethodName objc_method(entry.cstring.GetStringRef(), true); + ObjCLanguage::MethodName objc_method(cstring.GetStringRef(), true); if (objc_method.IsValid(true)) { - entry.cstring = objc_method.GetSelector(); - m_selector_to_index.Append(entry); + cstring = objc_method.GetSelector(); + state.selector_to_index[0] = cstring; ConstString objc_method_no_category( objc_method.GetFullNameWithoutCategory(true)); if (objc_method_no_category) { - entry.cstring = objc_method_no_category; - m_name_to_index.Append(entry); + cstring = objc_method_no_category; + state.name_to_index[4] = cstring; + } + } + }; + + TaskMapOverInt(num_symbols, 16, symbol_fn); + + std::unordered_set class_contexts; + for (size_t i = 0; i < num_symbols; i++) { + demangle_state const & state = states[i]; + for (auto name : state.name_to_index) { + if (name) { + m_name_to_index.Append(name, i); + } + } + for (auto name : state.selector_to_index) { + if (name) { + m_selector_to_index.Append(name, i); } } + if (state.is_definitely_class_context) { + class_contexts.insert(state.const_context); + } } - 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 (size_t i = 0; i < num_symbols; i++) { + demangle_state const & state = states[i]; + if (!state.cxx_basename) + continue; + if (!state.const_context) { + // No context for this function so this has to be a basename + m_basename_to_index.Append(state.cxx_basename, i); + // 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(state.cxx_basename, i); + } else { + m_method_to_index.Append(state.cxx_basename, i); + if (!state.is_definitely_class_context && + class_contexts.find(state.const_context) == class_contexts.end()) { + // 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_basename_to_index.Append(state.cxx_basename, i); } } }