Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lldb/source/Core/Mangled.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ ConstString Mangled::GetDemangledName(// BEGIN SWIFT
Log *log = GetLog(LLDBLog::Demangle);
LLDB_LOGF(log, "demangle swift: %s", mangled_name);
std::string demangled(SwiftLanguageRuntime::DemangleSymbolAsString(
mangled_name, SwiftLanguageRuntime::eTypeName, sc));
m_mangled, SwiftLanguageRuntime::eTypeName, sc));
// Don't cache the demangled name the function isn't available yet.
if (!sc || !sc->function) {
LLDB_LOGF(log, "demangle swift: %s -> \"%s\" (not cached)",
Expand Down Expand Up @@ -344,7 +344,7 @@ ConstString Mangled::GetDisplayDemangledName(
if (m_mangled &&
SwiftLanguageRuntime::IsSwiftMangledName(m_mangled.GetStringRef()))
return ConstString(SwiftLanguageRuntime::DemangleSymbolAsString(
m_mangled.GetStringRef(), SwiftLanguageRuntime::eSimplified, sc));
m_mangled, SwiftLanguageRuntime::eSimplified, sc));
#endif // LLDB_ENABLE_SWIFT
// END SWIFT
if (Language *lang = Language::FindPlugin(GuessLanguage()))
Expand Down
4 changes: 2 additions & 2 deletions lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1665,7 +1665,7 @@ bool SwiftLanguage::GetFunctionDisplayName(
if (sc->function->GetLanguage() != eLanguageTypeSwift)
return false;
std::string display_name = SwiftLanguageRuntime::DemangleSymbolAsString(
sc->function->GetMangled().GetMangledName().GetStringRef(),
sc->function->GetMangled().GetMangledName(),
SwiftLanguageRuntime::eSimplified, sc, exe_ctx);
if (display_name.empty())
return false;
Expand All @@ -1678,7 +1678,7 @@ bool SwiftLanguage::GetFunctionDisplayName(
if (sc->function->GetLanguage() != eLanguageTypeSwift)
return false;
std::string display_name = SwiftLanguageRuntime::DemangleSymbolAsString(
sc->function->GetMangled().GetMangledName().GetStringRef(),
sc->function->GetMangled().GetMangledName(),
SwiftLanguageRuntime::eSimplified, sc, exe_ctx);
if (display_name.empty())
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ class SwiftLanguageRuntime : public LanguageRuntime {

enum DemangleMode { eSimplified, eTypeName, eDisplayTypeName };
static std::string
DemangleSymbolAsString(llvm::StringRef symbol, DemangleMode mode,
DemangleSymbolAsString(ConstString symbol, DemangleMode mode,
const SymbolContext *sc = nullptr,
const ExecutionContext *exe_ctx = nullptr);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,7 @@ void SwiftLanguageRuntime::GetGenericParameterNamesForFunction(
}

std::string SwiftLanguageRuntime::DemangleSymbolAsString(
StringRef symbol, DemangleMode mode, const SymbolContext *sc,
ConstString symbol, DemangleMode mode, const SymbolContext *sc,
const ExecutionContext *exe_ctx) {
bool did_init = false;
llvm::DenseMap<ArchetypePath, StringRef> dict;
Expand Down Expand Up @@ -775,7 +775,7 @@ std::string SwiftLanguageRuntime::DemangleSymbolAsString(
return name;
};
}
return swift::Demangle::demangleSymbolAsString(symbol, options);
return swift_demangle::DemangleSymbolAsString(symbol, options);
}

swift::Demangle::NodePointer
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Plugins/TypeSystem/Swift/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ add_lldb_library(lldbPluginTypeSystemSwift PLUGIN
TypeSystemSwift.cpp
TypeSystemSwiftTypeRef.cpp
SwiftASTContext.cpp
SwiftDemangle.cpp

LINK_LIBS
lldbCore
Expand Down
136 changes: 136 additions & 0 deletions lldb/source/Plugins/TypeSystem/Swift/LRUCache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
//===-- LRUCache.h ----------------------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_LRUCache_h_
#define liblldb_LRUCache_h_

#include "lldb/Utility/ConstString.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include <list>
#include <mutex>

namespace lldb_private {
namespace swift_demangle {

/// A thread-safe Least Recently Used (LRU) cache implementation.
///
/// This class template implements an LRU cache with a fixed capacity, which
/// supports insertion, retrieval, and a factory-based retrieval mechanism. It
/// ensures thread safety through the use of a mutex lock. Keys are always
/// `ConstString`
template <typename Value>
class LRUCache {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add short doxygen comments for the class and the public methods?

public:
/// Constructs an instance with the specified capacity.
LRUCache(size_t capacity) : m_capacity(capacity) {}

/// Retrieves a value from the cache for the given key.
/// If the key is found in the cache, the corresponding value is returned and
/// the element is moved to the front of the LRU list, indicating it was
/// recently used. If the key is not found, std::nullopt is returned
std::optional<Value> Get(ConstString key) {
std::lock_guard lock{m_mutex};
auto map_it = m_map.find(key);
if (map_it == m_map.end())
return std::nullopt;
const auto &map_value = map_it->second;
MoveListElementToFront(map_value.list_it);
return map_value.value;
}

/// Inserts a key-value pair into the cache.
/// If the key already exists in the cache, its value is updated and the
/// element is moved to the front of the LRU list. If the key does not exist,
/// it is inserted into the cache. If the cache is at full capacity, the least
/// recently used element is evicted to make space for the new element.
void Put(ConstString key, const Value &value) {
if (m_capacity == 0)
return;
std::lock_guard lock{m_mutex};
auto map_it = m_map.find(key);
if (map_it != m_map.end()) {
auto &map_value = map_it->second;
map_value.value = value;
MoveListElementToFront(map_value.list_it);
} else {
InsertElement(key, value);
}
}

/// Retrieves a value from the cache or creates it if not present.
/// If the key is found in the cache, the corresponding value is returned and
/// the element is moved to the front of the LRU list. If the key is not
/// found, the given factory function is called to create a new value, which
/// is then inserted into the cache before being returned.
Value GetOrCreate(ConstString key, llvm::function_ref<Value()> factory) {
if (m_capacity == 0)
return factory();

{
std::lock_guard lock{m_mutex};
if (auto map_it = m_map.find(key); map_it != m_map.end()) {
const auto &map_value = map_it->second;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just thought about this: it'd be nice if in debug mode we assert that the cached value and the one created from the factory are the same (sorry for giving you more work!)

Copy link
Author

@DmT021 DmT021 Sep 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. The Node doesn't seem to provide an equality function. But it has isSimilarTo which in combination with a simple DFS should be enough to implement it in SharedDemangledNode.
I have a couple of questions then:

  1. Do you want this check to be a part of the LRUCache class or in GetCachedDemangledSymbol? I'm asking because in LRUCache we generally don't need the Value type to be equatable, but with this check we will require that.
  2. Under what flag should I add this check?
  • !define(NDEBUG) works in ReleaseAssert builds
  • defined(LLDB_CONFIGURATION_DEBUG) is defined only in debug builds (AFAICS)
  • Make a new macro like LLDB_LRUCACHE_VALIDATE that defaults to NDEBUG or LLDB_CONFIGURATION_DEBUG:
    #if !defined(LLDB_LRUCACHE_VALIDATE) && !defined(NDEBUG)
    #define LLDB_LRUCACHE_VALIDATE
    #endif
    
    This is more flexible but I doubt anyone will ever want to specify it separately.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetCachedDemangledSymbol would be ok.

#ifndef NDEBUG would be the one I'd pick, we already have similar check guarded (such as Verify) under that.

MoveListElementToFront(map_value.list_it);
return map_value.value;
}
}

// Call `factory` with `m_mutex` unlocked
const auto value = factory();

{
std::lock_guard lock{m_mutex};
InsertElement(key, value);
}

return value;
}

private:
using List = std::list<ConstString>;
struct MapValue {
List::iterator list_it;
Value value;
};
using Map = llvm::DenseMap<ConstString, MapValue>;

void InsertElement(ConstString key, const Value &value) {
assert(m_capacity > 0);

if (m_list.size() >= m_capacity) {
// Evict the least recent element
auto key = m_list.back();
m_list.pop_back();
m_map.erase(key);
}

m_list.emplace_front(key);
std::pair<typename Map::iterator, bool> emplace_result =
m_map.try_emplace(key, MapValue{m_list.begin(), value});
assert(emplace_result.second && "Element with this key already exists");
}

void MoveListElementToFront(typename List::iterator it) {
m_list.splice(m_list.begin(), m_list, it);
}

size_t m_capacity;
List m_list;
Map m_map;
std::mutex m_mutex;
};

} // namespace swift_demangle
} // namespace lldb_private

#endif
37 changes: 37 additions & 0 deletions lldb/source/Plugins/TypeSystem/Swift/SwiftDemangle.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//===-- SwiftDemangle.cpp ---------------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "SwiftDemangle.h"
#include "LRUCache.h"

namespace lldb_private {
namespace swift_demangle {

SharedDemangledNode GetCachedDemangledSymbol(ConstString name) {
static LRUCache<SharedDemangledNode> g_shared_cache{10};
auto factory = [name] {
return SharedDemangledNode::FromMangledSymbol(name);
};
#ifndef NDEBUG
auto validation_result = factory();
#endif
auto result = g_shared_cache.GetOrCreate(name, factory);
#ifndef NDEBUG
assert(validation_result == result &&
"Cached SharedDemangledNode isn't equal to a fresh one");
#endif
return result;
}


} // namespace swift_demangle
} // namespace lldb_private
Loading