Skip to content

Commit b44b9a6

Browse files
[lldb][NFC] Prepare SwiftLanguageRuntime for vectorized memory reads
Once the proposal [1] is implemented, the Process class will have the ability to read multiple memory addresses at once. This patch is an NFC refactor to make the code more amenable to that future. [1]: https://discourse.llvm.org/t/rfc-a-new-vectorized-memory-read-packet/
1 parent 0044000 commit b44b9a6

File tree

2 files changed

+118
-45
lines changed

2 files changed

+118
-45
lines changed

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp

Lines changed: 108 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2915,19 +2915,6 @@ std::optional<lldb::addr_t> SwiftLanguageRuntime::TrySkipVirtualParentProlog(
29152915
return pc_value;
29162916
}
29172917

2918-
/// Attempts to read the memory location at `task_addr_location`, producing
2919-
/// the Task pointer if possible.
2920-
static llvm::Expected<lldb::addr_t>
2921-
ReadTaskAddr(lldb::addr_t task_addr_location, Process &process) {
2922-
Status status;
2923-
addr_t task_addr = process.ReadPointerFromMemory(task_addr_location, status);
2924-
if (status.Fail())
2925-
return llvm::joinErrors(
2926-
llvm::createStringError("could not get current task from thread"),
2927-
status.takeError());
2928-
return task_addr;
2929-
}
2930-
29312918
/// Compute the location where the Task pointer for `real_thread` is stored by
29322919
/// the runtime.
29332920
static llvm::Expected<lldb::addr_t>
@@ -2955,48 +2942,124 @@ ComputeTaskAddrLocationFromThreadLocalStorage(Thread &real_thread) {
29552942
#endif
29562943
}
29572944

2945+
/// Helper function to read all `pointers` from process memory at once.
2946+
static llvm::SmallVector<llvm::Expected<addr_t>>
2947+
vector_read_pointers_from_process_mem(
2948+
Process &process, llvm::MutableArrayRef<llvm::Expected<addr_t>> pointers,
2949+
StringRef error_msg) {
2950+
std::vector<llvm::Expected<addr_t>> results;
2951+
results.reserve(pointers.size());
2952+
2953+
/// TODO: convert this loop into a call to the vectorized memory read, once
2954+
/// that is available in Process.
2955+
for (llvm::Expected<addr_t> &maybe_ptr : pointers) {
2956+
if (!maybe_ptr) {
2957+
results.push_back(std::move(maybe_ptr));
2958+
continue;
2959+
}
2960+
2961+
Status status;
2962+
addr_t result = process.ReadPointerFromMemory(*maybe_ptr, status);
2963+
if (status.Fail()) {
2964+
results.push_back(llvm::joinErrors(llvm::createStringError(error_msg),
2965+
status.takeError()));
2966+
} else
2967+
results.push_back(result);
2968+
}
2969+
2970+
return results;
2971+
}
2972+
2973+
/// Helper function to read `addr` from process memory.
2974+
static llvm::Expected<addr_t>
2975+
read_pointer_from_process_mem(Process &process, llvm::Expected<addr_t> addr,
2976+
StringRef error_msg) {
2977+
auto read_result =
2978+
vector_read_pointers_from_process_mem(process, addr, error_msg);
2979+
return std::move(read_result[0]);
2980+
}
2981+
29582982
llvm::Expected<lldb::addr_t>
29592983
TaskInspector::GetTaskAddrFromThreadLocalStorage(Thread &thread) {
2960-
// Look through backing threads when inspecting TLS.
2961-
Thread &real_thread =
2962-
thread.GetBackingThread() ? *thread.GetBackingThread() : thread;
2984+
return std::move(GetTaskAddrFromThreadLocalStorage(&thread)[0]);
2985+
}
2986+
2987+
llvm::SmallVector<llvm::Expected<lldb::addr_t>>
2988+
TaskInspector::GetTaskAddrLocations(llvm::ArrayRef<Thread *> threads) {
2989+
llvm::SmallVector<llvm::Expected<addr_t>> addr_locations;
2990+
addr_locations.reserve(threads.size());
29632991

2964-
if (auto it = m_tid_to_task_addr_location.find(real_thread.GetID());
2965-
it != m_tid_to_task_addr_location.end()) {
2992+
for (auto [idx, thread] : llvm::enumerate(threads)) {
2993+
Thread &real_thread =
2994+
thread->GetBackingThread() ? *thread->GetBackingThread() : *thread;
2995+
2996+
auto it = m_tid_to_task_addr_location.find(real_thread.GetID());
2997+
if (it != m_tid_to_task_addr_location.end()) {
2998+
addr_locations.push_back(it->second);
29662999
#ifndef NDEBUG
2967-
// In assert builds, check that caching did not produce incorrect results.
2968-
llvm::Expected<lldb::addr_t> task_addr_location =
2969-
ComputeTaskAddrLocationFromThreadLocalStorage(real_thread);
2970-
assert(task_addr_location);
2971-
assert(it->second == *task_addr_location);
3000+
// In assert builds, check that caching did not produce incorrect results.
3001+
llvm::Expected<lldb::addr_t> task_addr_location =
3002+
ComputeTaskAddrLocationFromThreadLocalStorage(real_thread);
3003+
assert(task_addr_location);
3004+
assert(it->second == *task_addr_location);
29723005
#endif
2973-
llvm::Expected<lldb::addr_t> task_addr =
2974-
ReadTaskAddr(it->second, *thread.GetProcess());
2975-
if (task_addr)
2976-
return task_addr;
2977-
// If the cached task addr location became invalid, invalidate the cache.
2978-
m_tid_to_task_addr_location.erase(it);
2979-
LLDB_LOG_ERROR(GetLog(LLDBLog::OS), task_addr.takeError(),
3006+
continue;
3007+
}
3008+
addr_locations.push_back(
3009+
ComputeTaskAddrLocationFromThreadLocalStorage(real_thread));
3010+
}
3011+
return addr_locations;
3012+
}
3013+
3014+
std::vector<llvm::Expected<addr_t>>
3015+
TaskInspector::GetTaskAddrFromThreadLocalStorage(
3016+
llvm::ArrayRef<Thread *> threads) {
3017+
if (threads.empty())
3018+
return {};
3019+
3020+
llvm::SmallVector<llvm::Expected<addr_t>> addr_locations =
3021+
GetTaskAddrLocations(threads);
3022+
3023+
Process &process = *threads[0]->GetProcess();
3024+
StringRef error_msg = "could not get current task from thread";
3025+
llvm::SmallVector<llvm::Expected<addr_t>> mem_read_results_vec =
3026+
vector_read_pointers_from_process_mem(process, addr_locations, error_msg);
3027+
3028+
for (auto [idx, thread] : llvm::enumerate(threads)) {
3029+
Thread &real_thread =
3030+
thread->GetBackingThread() ? *thread->GetBackingThread() : *thread;
3031+
user_id_t tid = real_thread.GetID();
3032+
3033+
// If the read was successful, cache the address.
3034+
if (mem_read_results_vec[idx]) {
3035+
m_tid_to_task_addr_location[tid] = *addr_locations[idx];
3036+
continue;
3037+
}
3038+
3039+
// For unsuccessful reads whose address was not cached, don't try again.
3040+
if (!m_tid_to_task_addr_location.erase(tid))
3041+
continue;
3042+
3043+
LLDB_LOG_ERROR(GetLog(LLDBLog::OS), mem_read_results_vec[idx].takeError(),
29803044
"TaskInspector: evicted task location address due to "
29813045
"invalid memory read: {0}");
2982-
}
29833046

2984-
llvm::Expected<lldb::addr_t> task_addr_location =
2985-
ComputeTaskAddrLocationFromThreadLocalStorage(real_thread);
2986-
if (!task_addr_location)
2987-
return task_addr_location;
3047+
// The cached address could not be loaded. "This should never happen", but
3048+
// recompute the address and try again for completeness.
3049+
llvm::Expected<addr_t> task_addr_loc =
3050+
ComputeTaskAddrLocationFromThreadLocalStorage(real_thread);
3051+
if (!task_addr_loc) {
3052+
mem_read_results_vec[idx] = std::move(task_addr_loc);
3053+
continue;
3054+
}
29883055

2989-
llvm::Expected<lldb::addr_t> task_addr =
2990-
ReadTaskAddr(*task_addr_location, *thread.GetProcess());
3056+
mem_read_results_vec[idx] =
3057+
read_pointer_from_process_mem(process, *task_addr_loc, error_msg);
3058+
if (mem_read_results_vec[idx])
3059+
m_tid_to_task_addr_location[tid] = *task_addr_loc;
3060+
}
29913061

2992-
// If the read from this TLS address is successful, cache the TLS address.
2993-
// Caching without a valid read is dangerous: earlier in the thread
2994-
// lifetime, the result of GetExtendedInfo can be invalid.
2995-
if (task_addr &&
2996-
real_thread.GetProcess()->GetTarget().GetSwiftCacheTaskPointerLocation())
2997-
m_tid_to_task_addr_location.try_emplace(real_thread.GetID(),
2998-
*task_addr_location);
2999-
return task_addr;
3062+
return mem_read_results_vec;
30003063
}
30013064

30023065
namespace {

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,7 +921,17 @@ class TaskInspector {
921921
llvm::Expected<lldb::addr_t>
922922
GetTaskAddrFromThreadLocalStorage(Thread &thread);
923923

924+
/// Inspects thread local storage to find the address of the currently
925+
/// executing task, if any.
926+
std::vector<llvm::Expected<lldb::addr_t>>
927+
GetTaskAddrFromThreadLocalStorage(llvm::ArrayRef<Thread *> threads);
928+
924929
private:
930+
/// For each thread in `threads`, return the location of the its task
931+
/// pointer, if it exists.
932+
llvm::SmallVector<llvm::Expected<lldb::addr_t>>
933+
GetTaskAddrLocations(llvm::ArrayRef<Thread *> threads);
934+
925935
llvm::DenseMap<uint64_t, lldb::addr_t> m_tid_to_task_addr_location;
926936
};
927937

0 commit comments

Comments
 (0)