Skip to content

Commit 350976f

Browse files
committed
[lldb] Fix caching, add lookup failures to TSSTyperef's LookupClangType
By profiling LLDB running frame variable in a large application with many many .o files, I noticed that one of the biggest bottlenecks of the operation was looking (and failing) to find a certain potential clang type over and over again. While fixing this I found that we will cache the result, but not the decl context to find that result, which introduces the risk of returning the wrong type if the type is cached, but a different decl context is used.
1 parent 5dcf10b commit 350976f

File tree

3 files changed

+81
-11
lines changed

3 files changed

+81
-11
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//===-- ThreadSafeStringMap.h ------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLDB_UTILITY_THREADSAFESTRINGMAP_H
10+
#define LLDB_UTILITY_THREADSAFESTRINGMAP_H
11+
12+
#include <mutex>
13+
14+
#include "llvm/ADT/StringMap.h"
15+
16+
namespace lldb_private {
17+
18+
template <typename _ValueType> class ThreadSafeStringMap {
19+
public:
20+
typedef llvm::StringMap<_ValueType> LLVMMapType;
21+
22+
ThreadSafeStringMap(unsigned map_initial_capacity = 0)
23+
: m_map(map_initial_capacity), m_mutex() {}
24+
25+
void Insert(llvm::StringRef k, _ValueType v) {
26+
std::lock_guard<std::mutex> guard(m_mutex);
27+
m_map.insert(std::make_pair(k, v));
28+
}
29+
30+
void Erase(llvm::StringRef k) {
31+
std::lock_guard<std::mutex> guard(m_mutex);
32+
m_map.erase(k);
33+
}
34+
35+
_ValueType Lookup(llvm::StringRef k) {
36+
std::lock_guard<std::mutex> guard(m_mutex);
37+
return m_map.lookup(k);
38+
}
39+
40+
bool Lookup(llvm::StringRef k, _ValueType &v) {
41+
std::lock_guard<std::mutex> guard(m_mutex);
42+
auto iter = m_map.find(k), end = m_map.end();
43+
if (iter == end)
44+
return false;
45+
v = iter->second;
46+
return true;
47+
}
48+
49+
void Clear() {
50+
std::lock_guard<std::mutex> guard(m_mutex);
51+
m_map.clear();
52+
}
53+
54+
protected:
55+
LLVMMapType m_map;
56+
std::mutex m_mutex;
57+
};
58+
59+
} // namespace lldb_private
60+
61+
#endif // LLDB_UTILITY_THREADSAFESTRINGMAP_H

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -424,36 +424,43 @@ TypeSP TypeSystemSwiftTypeRef::LookupClangType(
424424
TypeSP TypeSystemSwiftTypeRefForExpressions::LookupClangType(
425425
StringRef name_ref, llvm::ArrayRef<CompilerContext> decl_context,
426426
bool ignore_modules, SymbolContext sc) {
427-
// Check the cache first. Negative results are also cached.
427+
// Build up the cache key (the concatenation of the name and the stringified
428+
// decl context).
429+
StreamString stream;
430+
stream << name_ref;
431+
for (auto &context : decl_context)
432+
context.Dump(stream);
433+
428434
TypeSP result;
429-
ConstString name(name_ref);
430-
if (m_clang_type_cache.Lookup(name.AsCString(), result))
435+
// Check the cache first. Negative results are also cached.
436+
auto key = stream.GetString();
437+
if (m_clang_type_cache.Lookup(key, result))
431438
return result;
432439

433-
ModuleSP cur_module = sc.module_sp;
434440
auto lookup = [&](const ModuleSP &m) -> bool {
435-
// Already visited this.
436-
if (m == cur_module)
437-
return true;
438-
439441
// Don't recursively call into LookupClangTypes() to avoid filling
440442
// hundreds of image caches with negative results.
441443
result = ::LookupClangType(const_cast<Module &>(*m), decl_context,
442444
ignore_modules);
443445
// Cache it in the expression context.
444446
if (result)
445-
m_clang_type_cache.Insert(name.AsCString(), result);
447+
m_clang_type_cache.Insert(key, result);
446448
return !result;
447449
};
448450

449451
// Visit the current module first as a performance optimization heuristic.
452+
ModuleSP cur_module = sc.module_sp;
450453
if (cur_module)
451454
if (!lookup(cur_module))
452455
return result;
453456

454457
if (TargetSP target_sp = GetTargetWP().lock())
455458
target_sp->GetImages().ForEach(lookup);
456459

460+
/// Cache the negative result. This is safe to do because ModulesDidLoad will
461+
/// clear the cache.
462+
if (!result)
463+
m_clang_type_cache.Insert(key, result);
457464
return result;
458465
}
459466

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "lldb/Symbol/SymbolContext.h"
1919
#include "lldb/Target/ExecutionContext.h"
2020
#include "lldb/Utility/ThreadSafeDenseMap.h"
21+
#include "lldb/Utility/ThreadSafeStringMap.h"
2122
#include "swift/Demangling/ManglingFlavor.h"
2223

2324
// FIXME: needed only for the DenseMap.
@@ -691,8 +692,9 @@ class TypeSystemSwiftTypeRefForExpressions : public TypeSystemSwiftTypeRef {
691692
/// Perform all the implicit imports for the current frame.
692693
mutable std::unique_ptr<SymbolContext> m_initial_symbol_context_up;
693694
std::unique_ptr<SwiftPersistentExpressionState> m_persistent_state_up;
694-
/// Map ConstString Clang type identifiers to Clang types.
695-
ThreadSafeDenseMap<const char *, lldb::TypeSP> m_clang_type_cache;
695+
/// Map ConstString Clang type identifiers and the concatenation of the
696+
/// compiler context used to find them to Clang types.
697+
ThreadSafeStringMap<lldb::TypeSP> m_clang_type_cache;
696698
};
697699

698700
} // namespace lldb_private

0 commit comments

Comments
 (0)