-
Notifications
You must be signed in to change notification settings - Fork 341
[lldb][formatter] Add children of Swift Tasks #10057
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ | |
#include "Plugins/LanguageRuntime/Swift/ReflectionContextInterface.h" | ||
#include "Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h" | ||
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" | ||
#include "Plugins/TypeSystem/Swift/SwiftDemangle.h" | ||
#include "lldb/DataFormatters/FormattersHelpers.h" | ||
#include "lldb/DataFormatters/StringPrinter.h" | ||
#include "lldb/Symbol/CompilerType.h" | ||
|
@@ -28,6 +29,7 @@ | |
#include "lldb/ValueObject/ValueObject.h" | ||
#include "lldb/lldb-enumerations.h" | ||
#include "swift/AST/Types.h" | ||
#include "swift/Demangling/Demangle.h" | ||
#include "swift/Demangling/ManglingMacros.h" | ||
#include "llvm/ADT/STLExtras.h" | ||
#include "llvm/ADT/StringRef.h" | ||
|
@@ -761,10 +763,10 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd { | |
auto ts_or_err = | ||
target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeSwift); | ||
if (auto err = ts_or_err.takeError()) { | ||
LLDB_LOG( | ||
GetLog(LLDBLog::DataFormatters | LLDBLog::Types), | ||
"could not get Swift type system for Task synthetic provider: {0}", | ||
fmt_consume(std::move(err))); | ||
LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters | LLDBLog::Types), | ||
std::move(err), | ||
"could not get Swift type system for Task synthetic " | ||
"provider: {0}"); | ||
return; | ||
} | ||
m_ts = llvm::dyn_cast_or_null<TypeSystemSwiftTypeRef>(ts_or_err->get()); | ||
|
@@ -782,6 +784,7 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd { | |
"isStatusRecordLocked", | ||
"isEscalated", | ||
"isEnqueued", | ||
"children", | ||
"isRunning", | ||
}; | ||
|
||
|
@@ -837,7 +840,22 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd { | |
RETURN_CHILD(m_is_escalated_sp, isEscalated, bool_type); | ||
case 10: | ||
RETURN_CHILD(m_is_enqueued_sp, isEnqueued, bool_type); | ||
case 11: | ||
case 11: { | ||
if (!m_child_tasks_sp) { | ||
const auto &tasks = m_task_info.childTasks; | ||
std::string mangled_typename = | ||
mangledTypenameForTasksTuple(tasks.size()); | ||
CompilerType tasks_tuple_type = | ||
m_ts->GetTypeFromMangledTypename(ConstString(mangled_typename)); | ||
DataExtractor data{tasks.data(), tasks.size() * sizeof(tasks[0]), | ||
endian::InlHostByteOrder(), sizeof(void *)}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe use multiples of the pointer size on the target, since we still need to bake in this knowledge. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment, may have been my misunderstanding! |
||
m_child_tasks_sp = ValueObject::CreateValueObjectFromData( | ||
"children", data, m_backend.GetExecutionContextRef(), | ||
tasks_tuple_type); | ||
} | ||
return m_child_tasks_sp; | ||
} | ||
case 12: | ||
RETURN_CHILD(m_is_running_sp, isRunning, bool_type); | ||
default: | ||
return {}; | ||
|
@@ -858,17 +876,17 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd { | |
llvm::Expected<ReflectionContextInterface::AsyncTaskInfo> task_info = | ||
reflection_ctx->asyncTaskInfo(task_ptr); | ||
if (auto err = task_info.takeError()) { | ||
LLDB_LOG(GetLog(LLDBLog::DataFormatters | LLDBLog::Types), | ||
"could not get info for async task {0:x}: {1}", task_ptr, | ||
fmt_consume(std::move(err))); | ||
LLDB_LOG_ERROR( | ||
GetLog(LLDBLog::DataFormatters | LLDBLog::Types), std::move(err), | ||
"could not get info for async task {0:x}: {1}", task_ptr); | ||
} else { | ||
m_task_info = *task_info; | ||
for (auto child : | ||
{m_id_sp, m_kind_sp, m_enqueue_priority_sp, m_is_child_task_sp, | ||
m_is_future_sp, m_is_group_child_task_sp, | ||
m_is_async_let_task_sp, m_is_cancelled_sp, | ||
m_is_status_record_locked_sp, m_is_escalated_sp, | ||
m_is_enqueued_sp, m_is_running_sp}) | ||
m_is_enqueued_sp, m_child_tasks_sp, m_is_running_sp}) | ||
child.reset(); | ||
} | ||
} | ||
|
@@ -886,6 +904,35 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd { | |
return std::distance(children.begin(), it); | ||
} | ||
|
||
private: | ||
std::string mangledTypenameForTasksTuple(size_t count) { | ||
/* | ||
Global > TypeMangling > Type > Tuple | ||
TupleElement > Type > Structure | ||
Module, text="Swift" | ||
Identifier, text="UnsafeCurrentTask" | ||
*/ | ||
using namespace ::swift::Demangle; | ||
using Kind = Node::Kind; | ||
NodeFactory factory; | ||
auto [root, tuple] = swift_demangle::MakeNodeChain( | ||
{Kind::TypeMangling, Kind::Type, Kind::Tuple}, factory); | ||
|
||
// Make a TupleElement subtree N times, where N is the number of subtasks. | ||
for (size_t i = 0; i < count; ++i) { | ||
auto *structure = swift_demangle::MakeNodeChain( | ||
tuple, {Kind::TupleElement, Kind::Type, Kind::Structure}, factory); | ||
if (structure) { | ||
structure->addChild( | ||
factory.createNode(Kind::Module, ::swift::STDLIB_NAME), factory); | ||
structure->addChild( | ||
factory.createNode(Kind::Identifier, "UnsafeCurrentTask"), factory); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In case you didn't already know, we also have
in TypeSystemSwift. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't, thanks. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm, that interface isn't a match for this use case. I don't have a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably not. |
||
} | ||
} | ||
|
||
return mangleNode(root).result(); | ||
} | ||
|
||
private: | ||
TypeSystemSwiftTypeRef *m_ts = nullptr; | ||
ReflectionContextInterface::AsyncTaskInfo m_task_info; | ||
|
@@ -900,6 +947,7 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd { | |
ValueObjectSP m_is_status_record_locked_sp; | ||
ValueObjectSP m_is_escalated_sp; | ||
ValueObjectSP m_is_enqueued_sp; | ||
ValueObjectSP m_child_tasks_sp; | ||
ValueObjectSP m_is_running_sp; | ||
}; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
SWIFT_SOURCES := main.swift | ||
SWIFTFLAGS_EXTRAS := -parse-as-library | ||
include Makefile.rules |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import lldb | ||
from lldbsuite.test.decorators import * | ||
from lldbsuite.test.lldbtest import * | ||
from lldbsuite.test import lldbutil | ||
|
||
|
||
class TestCase(TestBase): | ||
|
||
@skipUnlessDarwin | ||
@swiftTest | ||
def test(self): | ||
"""""" | ||
self.build() | ||
lldbutil.run_to_source_breakpoint( | ||
self, "break here", lldb.SBFileSpec("main.swift") | ||
) | ||
self.expect( | ||
"language swift task info", | ||
substrs=[ | ||
"(UnsafeCurrentTask) current_task = {", | ||
"id = 1", | ||
"isChildTask = false", | ||
"isAsyncLetTask = false", | ||
"children = {", | ||
"0 = {", | ||
"id = 2", | ||
"isChildTask = true", | ||
"isAsyncLetTask = true", | ||
"children = {}", | ||
], | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
func f() async -> Int { | ||
try? await Task.sleep(for: .seconds(300)) | ||
return 30 | ||
} | ||
|
||
@main struct Main { | ||
static func main() async { | ||
async let number = f() | ||
await print("break here \(number)") | ||
kastiglione marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} |
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 use of
sizeof
raises an eyebrow. Wouldn't you want the size of a task on the target here? (For example because of 32-bit pointers on watchOS)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 reason I did this is because data at hand (an lldb defined struct,
AsyncTaskInfo
), is internal lldb data. It comes from the target, but at this point it's internal data, not target data. Does that sound reasonable to you? It definitely felt like an uncommon scenario as I wrote this.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.
Oh, if this is a
host
data structure then this is of course fine!