Skip to content

Commit b60b9ef

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 92e60fa commit b60b9ef

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
@@ -422,35 +422,42 @@ TypeSP TypeSystemSwiftTypeRef::LookupClangType(
422422
TypeSP TypeSystemSwiftTypeRefForExpressions::LookupClangType(
423423
StringRef name_ref, llvm::ArrayRef<CompilerContext> decl_context,
424424
SymbolContext sc) {
425-
// Check the cache first. Negative results are also cached.
425+
// Build up the cache key (the concatenation of the name and the stringified
426+
// decl context).
427+
StreamString stream;
428+
stream << name_ref;
429+
for (auto &context : decl_context)
430+
context.Dump(stream);
431+
426432
TypeSP result;
427-
ConstString name(name_ref);
428-
if (m_clang_type_cache.Lookup(name.AsCString(), result))
433+
// Check the cache first. Negative results are also cached.
434+
auto key = stream.GetString();
435+
if (m_clang_type_cache.Lookup(key, result))
429436
return result;
430437

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

446448
// Visit the current module first as a performance optimization heuristic.
449+
ModuleSP cur_module = sc.module_sp;
447450
if (cur_module)
448451
if (!lookup(cur_module))
449452
return result;
450453

451454
if (TargetSP target_sp = GetTargetWP().lock())
452455
target_sp->GetImages().ForEach(lookup);
453456

457+
/// Cache the negative result. This is safe to do because ModulesDidLoad will
458+
/// clear the cache.
459+
if (!result)
460+
m_clang_type_cache.Insert(key, result);
454461
return result;
455462
}
456463

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.
@@ -686,8 +687,9 @@ class TypeSystemSwiftTypeRefForExpressions : public TypeSystemSwiftTypeRef {
686687
/// Perform all the implicit imports for the current frame.
687688
mutable std::unique_ptr<SymbolContext> m_initial_symbol_context_up;
688689
std::unique_ptr<SwiftPersistentExpressionState> m_persistent_state_up;
689-
/// Map ConstString Clang type identifiers to Clang types.
690-
ThreadSafeDenseMap<const char *, lldb::TypeSP> m_clang_type_cache;
690+
/// Map ConstString Clang type identifiers and the concatenation of the
691+
/// compiler context used to find them to Clang types.
692+
ThreadSafeStringMap<lldb::TypeSP> m_clang_type_cache;
691693
};
692694

693695
} // namespace lldb_private

0 commit comments

Comments
 (0)