@@ -2317,14 +2317,15 @@ class CommandObjectLanguageSwiftTaskInfo final : public CommandObjectParsed {
23172317      }
23182318
23192319      TaskInspector task_inspector;
2320-       auto  task_addr_or_err = task_inspector.GetTaskAddrFromThreadLocalStorage (
2321-           m_exe_ctx.GetThreadRef ());
2322-       if  (auto  error = task_addr_or_err.takeError ()) {
2323-         result.AppendError (toString (std::move (error)));
2320+       std::optional<lldb::addr_t > maybe_task_addr =
2321+           task_inspector.GetTaskAddrFromThreadLocalStorage (
2322+               m_exe_ctx.GetThreadRef ());
2323+       if  (!task_addr) {
2324+         result.AppendError (" could find the task address" 
23242325        return ;
23252326      }
23262327
2327-       task_addr = task_addr_or_err. get () ;
2328+       task_addr = *maybe_task_addr ;
23282329    }
23292330
23302331    auto  ts_or_err = m_exe_ctx.GetTargetRef ().GetScratchTypeSystemForLanguage (
@@ -2915,19 +2916,6 @@ std::optional<lldb::addr_t> SwiftLanguageRuntime::TrySkipVirtualParentProlog(
29152916  return  pc_value;
29162917}
29172918
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- 
29312919// / Compute the location where the Task pointer for `real_thread` is stored by
29322920// / the runtime.
29332921static  llvm::Expected<lldb::addr_t >
@@ -2955,48 +2943,154 @@ ComputeTaskAddrLocationFromThreadLocalStorage(Thread &real_thread) {
29552943#endif 
29562944}
29572945
2958- llvm::Expected<lldb::addr_t >
2946+ // / Helper function to read all `pointers` from process memory at once.
2947+ // / Consumes any errors from the input by propagating them to the output.
2948+ static  llvm::SmallVector<std::optional<addr_t >>
2949+ MultiReadPointers (Process &process,
2950+                   llvm::MutableArrayRef<std::optional<addr_t >> maybe_pointers) {
2951+   llvm::SmallVector<std::optional<addr_t >> final_results;
2952+   llvm::SmallVector<addr_t > to_read;
2953+   final_results.reserve (maybe_pointers.size ());
2954+   to_read.reserve (maybe_pointers.size ());
2955+ 
2956+   // / Filter the input: propagate input errors directly to the output, forward
2957+   // / proper inputs to `to_read`.
2958+   for  (std::optional<addr_t > &maybe_ptr : maybe_pointers) {
2959+     if  (!maybe_ptr)
2960+       final_results.emplace_back (std::nullopt );
2961+     else  {
2962+       final_results.push_back (LLDB_INVALID_ADDRESS);
2963+       to_read.push_back (*maybe_ptr);
2964+     }
2965+   }
2966+ 
2967+   // / TODO: convert this loop into a call to the vectorized memory read, once
2968+   // / that is available in Process.
2969+   llvm::SmallVector<std::optional<addr_t >> read_results;
2970+   for  (addr_t  pointer : to_read) {
2971+     Status status;
2972+     addr_t  result = process.ReadPointerFromMemory (pointer, status);
2973+     if  (status.Fail ())
2974+       read_results.push_back (std::nullopt );
2975+     else 
2976+       read_results.push_back (result);
2977+   }
2978+ 
2979+   llvm::MutableArrayRef<std::optional<addr_t >> results_ref = read_results;
2980+ 
2981+   //  Move the results in the slots not filled by errors from the input.
2982+   for  (std::optional<addr_t > &maybe_result : final_results)
2983+     if  (maybe_result)
2984+       maybe_result = results_ref.consume_front ();
2985+ 
2986+   assert (results_ref.empty ());
2987+   return  final_results;
2988+ }
2989+ 
2990+ // / Helper function to read `addr` from process memory. Errors in the input are
2991+ // / propagated to to the output.
2992+ static  std::optional<addr_t > ReadPointer (Process &process,
2993+                                          std::optional<addr_t > addr) {
2994+   return  MultiReadPointers (process, addr)[0 ];
2995+ }
2996+ 
2997+ std::optional<lldb::addr_t >
29592998TaskInspector::GetTaskAddrFromThreadLocalStorage (Thread &thread) {
2960-   //  Look through backing threads when inspecting TLS.
2961-   Thread &real_thread =
2962-       thread.GetBackingThread () ? *thread.GetBackingThread () : thread;
2999+   return  GetTaskAddrFromThreadLocalStorage (&thread)[0 ];
3000+ }
3001+ 
3002+ llvm::SmallVector<std::optional<lldb::addr_t >>
3003+ TaskInspector::GetTaskAddrLocations (llvm::ArrayRef<Thread *> threads) {
3004+   llvm::SmallVector<std::optional<addr_t >> addr_locations;
3005+   addr_locations.reserve (threads.size ());
29633006
2964-   if  (auto  it = m_tid_to_task_addr_location.find (real_thread.GetID ());
2965-       it != m_tid_to_task_addr_location.end ()) {
3007+   for  (auto  [idx, thread] : llvm::enumerate (threads)) {
3008+     Thread &real_thread =
3009+         thread->GetBackingThread () ? *thread->GetBackingThread () : *thread;
3010+ 
3011+     auto  it = m_tid_to_task_addr_location.find (real_thread.GetID ());
3012+     if  (it != m_tid_to_task_addr_location.end ()) {
3013+       addr_locations.push_back (it->second );
29663014#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);
3015+        //  In assert builds, check that caching did not produce incorrect results.
3016+        llvm::Expected<lldb::addr_t > task_addr_location =
3017+            ComputeTaskAddrLocationFromThreadLocalStorage (real_thread);
3018+        assert (task_addr_location);
3019+        assert (it->second  == *task_addr_location);
29723020#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 (),
2980-                    " TaskInspector: evicted task location address due to " 
2981-                    " invalid memory read: {0}" 
2982-   }
2983- 
2984-   llvm::Expected<lldb::addr_t > task_addr_location =
3021+       continue ;
3022+     }
3023+     llvm::Expected<addr_t > addr_loc =
3024+         ComputeTaskAddrLocationFromThreadLocalStorage (real_thread);
3025+     if  (!addr_loc) {
3026+       LLDB_LOG_ERROR (GetLog (LLDBLog::OS), addr_loc.takeError (),
3027+                      " TaskInspector: failed to compute task address location " 
3028+                      " from TLS: {0}" 
3029+       addr_locations.push_back (std::nullopt );
3030+     } else 
3031+       addr_locations.push_back (*addr_loc);
3032+   }
3033+   return  addr_locations;
3034+ }
3035+ 
3036+ std::optional<addr_t > TaskInspector::RetryRead (Thread &thread,
3037+                                                addr_t  task_addr_location) {
3038+   Thread &real_thread =
3039+       thread.GetBackingThread () ? *thread.GetBackingThread () : thread;
3040+   user_id_t  tid = real_thread.GetID ();
3041+ 
3042+   //  For unsuccessful reads whose address was not cached, don't try again.
3043+   if  (!m_tid_to_task_addr_location.erase (tid))
3044+     return  std::nullopt ;
3045+ 
3046+   LLDB_LOG (GetLog (LLDBLog::OS), " TaskInspector: evicted task location " 
3047+                                 " address due to invalid memory read" 
3048+ 
3049+   //  The cached address could not be loaded. "This should never happen", but
3050+   //  recompute the address and try again for completeness.
3051+   llvm::Expected<addr_t > task_addr_loc =
29853052      ComputeTaskAddrLocationFromThreadLocalStorage (real_thread);
2986-   if  (!task_addr_location)
2987-     return  task_addr_location;
2988- 
2989-   llvm::Expected<lldb::addr_t > task_addr =
2990-       ReadTaskAddr (*task_addr_location, *thread.GetProcess ());
2991- 
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;
3053+   if  (!task_addr_loc) {
3054+     LLDB_LOG_ERROR (GetLog (LLDBLog::OS), task_addr_loc.takeError (),
3055+                    " TaskInspector: failed to compute task address location " 
3056+                    " from TLS: {0}" 
3057+     return  std::nullopt ;
3058+   }
3059+ 
3060+   std::optional<addr_t > read_retry_result =
3061+       ReadPointer (*thread.GetProcess (), *task_addr_loc);
3062+   if  (read_retry_result)
3063+     m_tid_to_task_addr_location[tid] = *task_addr_loc;
3064+   return  read_retry_result;
3065+ }
3066+ 
3067+ llvm::SmallVector<std::optional<addr_t >>
3068+ TaskInspector::GetTaskAddrFromThreadLocalStorage (
3069+     llvm::ArrayRef<Thread *> threads) {
3070+   if  (threads.empty ())
3071+     return  {};
3072+ 
3073+   llvm::SmallVector<std::optional<addr_t >> addr_locations =
3074+       GetTaskAddrLocations (threads);
3075+ 
3076+   Process &process = *threads[0 ]->GetProcess ();
3077+   llvm::SmallVector<std::optional<addr_t >> mem_read_results =
3078+       MultiReadPointers (process, addr_locations);
3079+ 
3080+   for  (auto  [idx, thread] : llvm::enumerate (threads)) {
3081+     if  (!addr_locations[idx])
3082+       continue ;
3083+     //  If the read was successful, cache the address.
3084+     if  (mem_read_results[idx]) {
3085+       Thread &real_thread =
3086+           thread->GetBackingThread () ? *thread->GetBackingThread () : *thread;
3087+       m_tid_to_task_addr_location[real_thread.GetID ()] = *addr_locations[idx];
3088+       continue ;
3089+     }
3090+     mem_read_results[idx] = RetryRead (*thread, *addr_locations[idx]);
3091+   }
3092+ 
3093+   return  mem_read_results;
30003094}
30013095
30023096namespace  {
0 commit comments