@@ -1837,19 +1837,109 @@ SwiftLanguage::GetDemangledFunctionNameWithoutArguments(Mangled mangled) const {
18371837 return mangled_name;
18381838}
18391839
1840- void SwiftLanguage::FilterForLineBreakpoints (
1841- llvm::SmallVectorImpl<SymbolContext> &sc_list) const {
1842- llvm::erase_if (sc_list, [](const SymbolContext &sc) {
1843- // If we don't have a function, conservatively keep this sc.
1844- if (!sc.function )
1845- return false ;
1840+ namespace {
1841+ using namespace swift ::Demangle;
1842+ struct AsyncInfo {
1843+ const Function *function;
1844+ NodePointer demangle_node;
1845+ std::optional<uint64_t > funclet_number;
1846+ };
18461847
1847- // In async functions, ignore await resume ("Q") funclets, these only
1848- // deallocate the async context and task_switch back to user code.
1848+ std::string to_string (const AsyncInfo &async_info) {
1849+ StreamString stream_str;
1850+ llvm::raw_ostream &str = stream_str.AsRawOstream ();
1851+ str << " function = " ;
1852+ if (async_info.function )
1853+ str << async_info.function ->GetMangled ().GetMangledName ();
1854+ else
1855+ str << " nullptr" ;
1856+ str << " , demangle_node: " << async_info.demangle_node ;
1857+ str << " , funclet_number = " ;
1858+ if (async_info.funclet_number )
1859+ str << *async_info.funclet_number ;
1860+ else
1861+ str << " nullopt" ;
1862+ return stream_str.GetString ().str ();
1863+ }
1864+
1865+ // / Map each unique Function in sc_list to a Demangle::NodePointer, or null if
1866+ // / demangling is not possible.
1867+ llvm::SmallVector<AsyncInfo> GetAsyncInfo (llvm::ArrayRef<SymbolContext> sc_list,
1868+ swift::Demangle::Context &ctx) {
1869+ Log *log (GetLog (LLDBLog::Demangle));
1870+ llvm::SmallSet<Function *, 8 > seen_functions;
1871+ llvm::SmallVector<AsyncInfo> async_infos;
1872+ for (const SymbolContext &sc : sc_list) {
1873+ if (!sc.function || seen_functions.contains (sc.function ))
1874+ continue ;
1875+ seen_functions.insert (sc.function );
18491876 llvm::StringRef name =
18501877 sc.function ->GetMangled ().GetMangledName ().GetStringRef ();
1851- return SwiftLanguageRuntime::IsSwiftAsyncAwaitResumePartialFunctionSymbol (
1852- name);
1878+ NodePointer node = SwiftLanguageRuntime::DemangleSymbolAsNode (name, ctx);
1879+ async_infos.push_back (
1880+ {sc.function , node, SwiftLanguageRuntime::GetFuncletNumber (node)});
1881+
1882+ if (log) {
1883+ std::string as_str = to_string (async_infos.back ());
1884+ LLDB_LOGF (log, " %s: %s" , __FUNCTION__, as_str.c_str ());
1885+ }
1886+ }
1887+ return async_infos;
1888+ }
1889+ } // namespace
1890+
1891+ void SwiftLanguage::FilterForLineBreakpoints (
1892+ llvm::SmallVectorImpl<SymbolContext> &sc_list) const {
1893+ using namespace swift ::Demangle;
1894+ Context ctx;
1895+
1896+ llvm::SmallVector<AsyncInfo> async_infos = GetAsyncInfo (sc_list, ctx);
1897+
1898+ // Vector containing one representative funclet of each unique async function
1899+ // in sc_list. The representative is always the one with the smallest funclet
1900+ // number seen so far.
1901+ llvm::SmallVector<AsyncInfo> unique_async_funcs;
1902+
1903+ // Note the subtlety: this deletes based on functions, not SymbolContexts, as
1904+ // there might be multiple SCs with the same Function at this point.
1905+ llvm::SmallPtrSet<const Function *, 4 > to_delete;
1906+
1907+ for (const auto &async_info : async_infos) {
1908+ // If we can't find a funclet number, don't delete this.
1909+ if (!async_info.funclet_number )
1910+ continue ;
1911+
1912+ // Have we found other funclets of the same async function?
1913+ auto *representative =
1914+ llvm::find_if (unique_async_funcs, [&](AsyncInfo &other_info) {
1915+ // This looks quadratic, but in practice it is not. We should have at
1916+ // most 2 different async functions in the same line, unless a user
1917+ // writes many closures on the same line.
1918+ return SwiftLanguageRuntime::AreFuncletsOfSameAsyncFunction (
1919+ async_info.demangle_node , other_info.demangle_node ) ==
1920+ SwiftLanguageRuntime::FuncletComparisonResult::
1921+ SameAsyncFunction;
1922+ });
1923+
1924+ // We found a new async function.
1925+ if (representative == unique_async_funcs.end ()) {
1926+ unique_async_funcs.push_back (async_info);
1927+ continue ;
1928+ }
1929+
1930+ // This is another funclet of the same async function. Keep the one with the
1931+ // smallest number, erase the other. If they have the same number, don't
1932+ // erase it.
1933+ if (async_info.funclet_number > representative->funclet_number )
1934+ to_delete.insert (async_info.function );
1935+ else if (async_info.funclet_number < representative->funclet_number ) {
1936+ to_delete.insert (representative->function );
1937+ *representative = async_info;
1938+ }
1939+ }
1940+
1941+ llvm::erase_if (sc_list, [&](const SymbolContext &sc) {
1942+ return to_delete.contains (sc.function );
18531943 });
18541944}
18551945
0 commit comments