-
Notifications
You must be signed in to change notification settings - Fork 341
[lldb][swift] Filter unnecessary funclets when setting line breakpoints #10259
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[lldb][swift] Filter unnecessary funclets when setting line breakpoints #10259
Conversation
@swift-ci test |
std::optional<uint64_t> funclet_number; | ||
|
||
/// Helper function for logging. | ||
std::string to_str() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The more idiomatic thing in LLVM is to add a free-standing toString() function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
which I think will make it work with operator<< as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point!
/// Map each unique Function in sc_list to a Demangle::NodePointer, or null if | ||
/// demangling is not possible. | ||
llvm::SmallVector<AsyncInfo> GetAsyncInfo(llvm::ArrayRef<SymbolContext> sc_list, | ||
swift::Demangle::Context &ctx) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be a function that translates just one symbol context and then you use a std::algorithm to apply that on an entire vector?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sadly there is no std::transform_if
or anything along those lines that help here.
We would need to apply a unique filter based on SymbolContext.function and then std::transform.
Prior to this commit, line breakpoints that match multiple funclets were being filtered out to remove "Q" funclets from them. This generally works for simple "await foo()" expressions, but it is not a comprehensive solution, as it does not address the patterns emerging from `async let` and `await <async_let_variable>` statements. This commit generalizes the filtering algorithm: 1. Locations are bundled together based on the async function that generated them. 2. For each bundle, choose the funclet with the smallest "number" as per its mangling. To see why this is helpful, consider an `async let` statement like: `async let timestamp3 = getTimestamp(i: 44)` It creates 4 funclets: ``` 2.1: function = (3) suspend resume partial function for test.some_other_async() async -> () mangled function = $s4test16some_other_asyncyyYaFTY2_ 2.2: function = implicit closure swiftlang#1 @sendable () async -> Swift.Int in test.some_other_async() async -> () mangled function = $s4test16some_other_asyncyyYaFSiyYaYbcfu_ 2.3: function = (1) await resume partial function for implicit closure swiftlang#1 @sendable () async -> Swift.Int in test.some_other_async() async -> () mangled function = $s4test16some_other_asyncyyYaFSiyYaYbcfu_TQ0_ 2.4: function = (2) suspend resume partial function for implicit closure swiftlang#1 @sendable () async -> Swift.Int in test.some_other_async() async -> () mangled function = $s4test16some_other_asyncyyYaFSiyYaYbcfu_TY1_ ``` The first is for the LHS, the others are for the RHS expression and are only executed by the new Task. Only 2.1 and 2.2 should receive breakpoints. Likewise, a breakpoint on an `await <async_let_variable>` line would create 3 funclets: ``` 3.1: function = (3) suspend resume partial function for test.some_other_async() async -> () mangled function = $s4test16some_other_asyncyyYaFTY2_ 3.2: function = (4) suspend resume partial function for test.some_other_async() async -> () mangled function = $s4test16some_other_asyncyyYaFTY3_ 3.3: function = (5) suspend resume partial function for test.some_other_async() async -> () mangled function = $s4test16some_other_asyncyyYaFTY4_ ``` The first is for "before" the await, the other two for "after". Only the first should receive a breakpoint.
2a3a35b
to
de7263a
Compare
@swift-ci test |
I am going to merge this to unblock follow up patches, but happy to address any other review feedback in post. |
Prior to this commit, line breakpoints that match multiple funclets were being filtered out to remove "Q" funclets from them. This generally works for simple "await foo()" expressions, but it is not a comprehensive solution, as it does not address the patterns emerging from
async let
andawait <async_let_variable>
statements.This commit generalizes the filtering algorithm:
To see why this is helpful, consider an
async let
statement like:async let timestamp3 = getTimestamp(i: 44)
It creates 4 funclets:
The first is for the LHS, the others are for the RHS expression and are only executed by the new Task. Only 2.1 and 2.2 should receive breakpoints.
Likewise, a breakpoint on an
await <async_let_variable>
line would create 3 funclets:The first is for "before" the await, the other two for "after". Only the first should receive a breakpoint.
rdar://146123772