Index: include/lldb/Utility/ConstString.h =================================================================== --- include/lldb/Utility/ConstString.h +++ include/lldb/Utility/ConstString.h @@ -480,6 +480,17 @@ } // 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 @@ -13,8 +13,8 @@ #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" #include "Plugins/Language/ObjC/ObjCLanguage.h" #include "lldb/Core/Module.h" -#include "lldb/Core/Section.h" #include "lldb/Core/STLUtils.h" +#include "lldb/Core/Section.h" #include "lldb/Core/Timer.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Symbol.h" @@ -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; @@ -213,6 +214,105 @@ return nullptr; } +namespace { + +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; +}; + +} // namespace + +// This is not a method of Symtab so it is easier to understand it's inputs. +// This function is run in parallel so we need to be careful about side effects. +static void IndexOneName(demangle_state &state, const Symbol &symbol, + const ObjectFile &objfile) { + // 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()) + return; + + const Mangled &mangled = symbol.GetMangled(); + 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. + cstring = ConstString( + 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(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)); + 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 + 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(); + } + } + } + } + + 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. + cstring = ConstString( + 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(cstring.GetStringRef(), true); + if (objc_method.IsValid(true)) { + cstring = objc_method.GetSelector(); + state.selector_to_index[0] = cstring; + + ConstString objc_method_no_category( + objc_method.GetFullNameWithoutCategory(true)); + if (objc_method_no_category) { + cstring = objc_method_no_category; + state.name_to_index[4] = cstring; + } + } +} + //---------------------------------------------------------------------- // InitNameIndexes //---------------------------------------------------------------------- @@ -244,150 +344,48 @@ 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); - - for (entry.value = 0; entry.value < num_symbols; ++entry.value) { - const 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; + std::vector states(num_symbols); - const Mangled &mangled = symbol->GetMangled(); - entry.cstring = mangled.GetMangledName(); - if (entry.cstring) { - m_name_to_index.Append(entry); - - 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); - } + TaskMapOverInt(0, num_symbols, [&states, this](size_t value) { + IndexOneName(states[value], m_symbols[value], *m_objfile); + }); - 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; - } - } - } - } - } + 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); } } - - entry.cstring = mangled.GetDemangledName(symbol->GetLanguage()); - if (entry.cstring) { - m_name_to_index.Append(entry); - - 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); + for (auto name : state.selector_to_index) { + if (name) { + m_selector_to_index.Append(name, i); } } - - // 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); - if (objc_method.IsValid(true)) { - entry.cstring = objc_method.GetSelector(); - m_selector_to_index.Append(entry); - - 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); - } + 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); } } }