Skip to content

Commit b7248c7

Browse files
authored
[lldb] Add summary formatter for DefaultActorStorage (#10388)
Show the actor's state (idle, scheduled, running, or zombie) as its summary.
1 parent 73856a5 commit b7248c7

File tree

4 files changed

+61
-15
lines changed

4 files changed

+61
-15
lines changed

lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "lldb/lldb-enumerations.h"
3434
#include "swift/ABI/Task.h"
3535
#include "swift/AST/Types.h"
36+
#include "swift/Concurrency/Actor.h"
3637
#include "swift/Demangling/Demangle.h"
3738
#include "swift/Demangling/ManglingMacros.h"
3839
#include "llvm/ADT/STLExtras.h"
@@ -1321,6 +1322,25 @@ class TaskGroupSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
13211322
std::vector<ValueObjectSP> m_children;
13221323
};
13231324

1325+
/// Offset of ActiveActorStatus from _$defaultActor_.
1326+
///
1327+
/// DefaultActorImpl has the following (labeled) layout.
1328+
///
1329+
/// DefaultActorImpl:
1330+
/// 0: HeapObject
1331+
/// $defaultActor:
1332+
/// 16/0: isDistributedRemoteActor
1333+
/// 17/1: <alignment padding>
1334+
/// 32/16: StatusStorage
1335+
///
1336+
/// As shown, the $defaultActor field does not point to the start of the
1337+
/// DefaultActorImpl.
1338+
///
1339+
/// The StatusStorage is at offset of +32 from the start of DefaultActorImpl, or
1340+
/// at +16 relative to $defaultActor. The formatters are based on $defaultActor,
1341+
/// and as such use the relative offset.
1342+
static constexpr offset_t ActiveActorStatusOffset = 16;
1343+
13241344
class ActorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
13251345
public:
13261346
ActorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
@@ -1458,20 +1478,6 @@ class ActorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
14581478
ProcessSP process_sp;
14591479
addr_t addr;
14601480

1461-
// `$defaultActor`'s offset within the actor object.
1462-
//
1463-
// The $defaultActor field does not point to the start of DefaultActorImpl,
1464-
// it has as an address that points past the HeapObject layout.
1465-
static constexpr offset_t DefaultActorFieldOffset = 16;
1466-
// ActiveActorStatus's offset within DefaultActorImpl.
1467-
//
1468-
// ActiveActorStatus is declared alignas(2*sizeof(void*)). The layout of
1469-
// DefaultActorImpl puts the status record after HeapObject (size 16), and
1470-
// its first field (bool size 1), an offset of +32 from the start of the
1471-
// actor. This offset is relative to DefaultActorImpl, but this code needs
1472-
// an offset relative to the $defaultActor field, and is adjusted as such.
1473-
static constexpr offset_t ActiveActorStatusOffset =
1474-
32 - DefaultActorFieldOffset;
14751481
// FirstJob's offset within ActiveActorStatus.
14761482
static constexpr offset_t FirstJobOffset = ActiveActorStatusOffset + 8;
14771483

@@ -1865,6 +1871,37 @@ bool lldb_private::formatters::swift::Task_SummaryProvider(
18651871
return true;
18661872
}
18671873

1874+
bool lldb_private::formatters::swift::Actor_SummaryProvider(
1875+
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
1876+
static constexpr offset_t FlagsOffset = ActiveActorStatusOffset;
1877+
auto addr = valobj.GetLoadAddress();
1878+
if (addr == LLDB_INVALID_ADDRESS)
1879+
return false;
1880+
1881+
auto flags_addr = addr + FlagsOffset;
1882+
Status status;
1883+
uint64_t flags = 0;
1884+
if (auto process_sp = valobj.GetProcessSP())
1885+
flags = process_sp->ReadUnsignedIntegerFromMemory(flags_addr, 4, 0, status);
1886+
1887+
if (status.Fail()) {
1888+
stream.PutCString("<could not read actor state>");
1889+
return true;
1890+
}
1891+
1892+
using namespace ::swift::concurrency::ActorFlagConstants;
1893+
uint8_t state = flags & ActorStateMask;
1894+
static_assert(Zombie_ReadyForDeallocation == 3);
1895+
if (state > Zombie_ReadyForDeallocation) {
1896+
stream << "<unknown actor state: " << Twine(state).str() << ">";
1897+
return true;
1898+
}
1899+
1900+
static const StringRef states[] = {"idle", "scheduled", "running", "zombie"};
1901+
stream.PutCString(states[state]);
1902+
return true;
1903+
}
1904+
18681905
namespace {
18691906

18701907
/// Enumerate the kinds of SIMD elements.

lldb/source/Plugins/Language/Swift/SwiftFormatters.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ bool TaskPriority_SummaryProvider(ValueObject &valobj, Stream &stream,
120120
bool Task_SummaryProvider(ValueObject &valobj, Stream &stream,
121121
const TypeSummaryOptions &options);
122122

123+
bool Actor_SummaryProvider(ValueObject &valobj, Stream &stream,
124+
const TypeSummaryOptions &options);
125+
123126
SyntheticChildrenFrontEnd *EnumSyntheticFrontEndCreator(CXXSyntheticChildren *,
124127
lldb::ValueObjectSP);
125128

lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,10 @@ static void LoadSwiftFormatters(lldb::TypeCategoryImplSP swift_category_sp) {
508508
lldb_private::formatters::swift::Task_SummaryProvider,
509509
"Swift UnsafeCurrentTask summary provider",
510510
"Swift.UnsafeCurrentTask", task_summary_flags);
511+
AddCXXSummary(swift_category_sp,
512+
lldb_private::formatters::swift::Actor_SummaryProvider,
513+
"Swift Actor summary provider", "Builtin.DefaultActorStorage",
514+
task_summary_flags);
511515
}
512516

513517
summary_flags.SetSkipPointers(false);

lldb/test/API/lang/swift/async/actors/unprioritised_jobs/TestSwiftActorUnprioritisedJobs.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ def test_actor_unprioritised_jobs(self):
1515
self, "break here", lldb.SBFileSpec("main.swift")
1616
)
1717
frame = thread.GetSelectedFrame()
18-
unprioritised_jobs = frame.var("a.$defaultActor.unprioritised_jobs")
18+
defaultActor = frame.var("a.$defaultActor")
19+
self.assertEqual(defaultActor.summary, "running")
20+
unprioritised_jobs = defaultActor.GetChildMemberWithName("unprioritised_jobs")
1921
# There are 4 child tasks (async let), the first one occupies the actor
2022
# with a sleep, the next 3 go on to the queue.
2123
# TODO: rdar://148377173

0 commit comments

Comments
 (0)