@@ -1837,19 +1837,109 @@ SwiftLanguage::GetDemangledFunctionNameWithoutArguments(Mangled mangled) const {
1837
1837
return mangled_name;
1838
1838
}
1839
1839
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
+ };
1846
1847
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 );
1849
1876
llvm::StringRef name =
1850
1877
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 );
1853
1943
});
1854
1944
}
1855
1945
0 commit comments