@@ -101,6 +101,12 @@ class ReflectionContext
101101 std::vector<MemoryReader::ReadBytesResult> savedBuffers;
102102 std::vector<std::tuple<RemoteAddress, RemoteAddress>> imageRanges;
103103
104+ bool setupTargetPointers = false ;
105+ typename super::StoredPointer target_non_future_adapter = 0 ;
106+ typename super::StoredPointer target_future_adapter = 0 ;
107+ typename super::StoredPointer target_task_wait_throwing_resume_adapter = 0 ;
108+ typename super::StoredPointer target_task_future_wait_resume_adapter = 0 ;
109+
104110public:
105111 using super::getBuilder;
106112 using super::readDemanglingForContextDescriptor;
@@ -137,6 +143,21 @@ class ReflectionContext
137143 std::vector<AsyncTaskAllocationChunk> Chunks;
138144 };
139145
146+ struct AsyncTaskInfo {
147+ uint32_t JobFlags;
148+ uint64_t TaskStatusFlags;
149+ uint64_t Id;
150+ StoredPointer RunJob;
151+ StoredPointer AllocatorSlabPtr;
152+ std::vector<StoredPointer> ChildTasks;
153+ std::vector<StoredPointer> AsyncBacktraceFrames;
154+ };
155+
156+ struct ActorInfo {
157+ StoredSize Flags;
158+ StoredPointer FirstJob;
159+ };
160+
140161 explicit ReflectionContext (std::shared_ptr<MemoryReader> reader)
141162 : super(std::move(reader), *this)
142163 {}
@@ -1083,6 +1104,31 @@ class ReflectionContext
10831104 return dyn_cast_or_null<const RecordTypeInfo>(TypeInfo);
10841105 }
10851106
1107+ bool metadataIsActor (StoredPointer MetadataAddress) {
1108+ auto Metadata = readMetadata (MetadataAddress);
1109+ if (!Metadata)
1110+ return false ;
1111+
1112+ // Only classes can be actors.
1113+ if (Metadata->getKind () != MetadataKind::Class)
1114+ return false ;
1115+
1116+ auto DescriptorAddress =
1117+ super::readAddressOfNominalTypeDescriptor (Metadata);
1118+ if (!DescriptorAddress)
1119+ return false ;
1120+
1121+ auto DescriptorBytes =
1122+ getReader ().readBytes (RemoteAddress (DescriptorAddress),
1123+ sizeof (TargetTypeContextDescriptor<Runtime>));
1124+ if (!DescriptorBytes)
1125+ return false ;
1126+ auto Descriptor =
1127+ reinterpret_cast <const TargetTypeContextDescriptor<Runtime> *>(
1128+ DescriptorBytes.get ());
1129+ return Descriptor->getTypeContextDescriptorFlags ().class_isActor ();
1130+ }
1131+
10861132 // / Iterate the protocol conformance cache tree rooted at NodePtr, calling
10871133 // / Call with the type and protocol in each node.
10881134 void iterateConformanceTree (StoredPointer NodePtr,
@@ -1394,22 +1440,179 @@ class ReflectionContext
13941440 return {llvm::None, {Slab->Next , SlabSize, {Chunk}}};
13951441 }
13961442
1397- std::pair<llvm::Optional<std::string>, StoredPointer>
1398- asyncTaskSlabPtr (StoredPointer AsyncTaskPtr) {
1399- using AsyncTask = AsyncTask<Runtime>;
1400-
1401- auto AsyncTaskBytes =
1402- getReader ().readBytes (RemoteAddress (AsyncTaskPtr), sizeof (AsyncTask));
1403- auto *AsyncTaskObj =
1404- reinterpret_cast <const AsyncTask *>(AsyncTaskBytes.get ());
1443+ std::pair<llvm::Optional<std::string>, AsyncTaskInfo>
1444+ asyncTaskInfo (StoredPointer AsyncTaskPtr) {
1445+ auto AsyncTaskObj = readObj<AsyncTask<Runtime>>(AsyncTaskPtr);
14051446 if (!AsyncTaskObj)
1406- return {std::string (" failure reading async task" ), 0 };
1447+ return {std::string (" failure reading async task" ), {}};
1448+
1449+ AsyncTaskInfo Info{};
1450+ Info.JobFlags = AsyncTaskObj->Flags ;
1451+ Info.TaskStatusFlags = AsyncTaskObj->PrivateStorage .Status .Flags ;
1452+ Info.Id =
1453+ AsyncTaskObj->Id | ((uint64_t )AsyncTaskObj->PrivateStorage .Id << 32 );
1454+ Info.AllocatorSlabPtr = AsyncTaskObj->PrivateStorage .Allocator .FirstSlab ;
1455+ Info.RunJob = getRunJob (AsyncTaskObj.get ());
1456+
1457+ // Find all child tasks.
1458+ auto RecordPtr = AsyncTaskObj->PrivateStorage .Status .Record ;
1459+ while (RecordPtr) {
1460+ auto RecordObj = readObj<TaskStatusRecord<Runtime>>(RecordPtr);
1461+ if (!RecordObj)
1462+ break ;
1463+
1464+ // This cuts off high bits if our size_t doesn't match the target's. We
1465+ // only read the Kind bits which are at the bottom, so that's OK here.
1466+ // Beware of this when reading anything else.
1467+ TaskStatusRecordFlags Flags{RecordObj->Flags };
1468+ auto Kind = Flags.getKind ();
1469+
1470+ StoredPointer ChildTask = 0 ;
1471+ if (Kind == TaskStatusRecordKind::ChildTask) {
1472+ auto RecordObj = readObj<ChildTaskStatusRecord<Runtime>>(RecordPtr);
1473+ if (RecordObj)
1474+ ChildTask = RecordObj->FirstChild ;
1475+ } else if (Kind == TaskStatusRecordKind::TaskGroup) {
1476+ auto RecordObj = readObj<TaskGroupTaskStatusRecord<Runtime>>(RecordPtr);
1477+ if (RecordObj)
1478+ ChildTask = RecordObj->FirstChild ;
1479+ }
1480+
1481+ while (ChildTask) {
1482+ Info.ChildTasks .push_back (ChildTask);
1483+
1484+ StoredPointer ChildFragmentAddr =
1485+ ChildTask + sizeof (AsyncTask<Runtime>);
1486+ auto ChildFragmentObj =
1487+ readObj<ChildFragment<Runtime>>(ChildFragmentAddr);
1488+ if (ChildFragmentObj)
1489+ ChildTask = ChildFragmentObj->NextChild ;
1490+ else
1491+ ChildTask = 0 ;
1492+ }
1493+
1494+ RecordPtr = RecordObj->Parent ;
1495+ }
1496+
1497+ // Walk the async backtrace if the task isn't running or cancelled.
1498+ // TODO: Use isEnqueued from https://github.com/apple/swift/pull/41088/ once
1499+ // that's available.
1500+ int IsCancelledFlag = 0x100 ;
1501+ int IsRunningFlag = 0x800 ;
1502+ if (!(AsyncTaskObj->PrivateStorage .Status .Flags & IsCancelledFlag) &&
1503+ !(AsyncTaskObj->PrivateStorage .Status .Flags & IsRunningFlag)) {
1504+ auto ResumeContext = AsyncTaskObj->ResumeContextAndReserved [0 ];
1505+ while (ResumeContext) {
1506+ auto ResumeContextObj = readObj<AsyncContext<Runtime>>(ResumeContext);
1507+ if (!ResumeContextObj)
1508+ break ;
1509+ Info.AsyncBacktraceFrames .push_back (
1510+ stripSignedPointer (ResumeContextObj->ResumeParent ));
1511+ ResumeContext = stripSignedPointer (ResumeContextObj->Parent );
1512+ }
1513+ }
1514+
1515+ return {llvm::None, Info};
1516+ }
1517+
1518+ std::pair<llvm::Optional<std::string>, ActorInfo>
1519+ actorInfo (StoredPointer ActorPtr) {
1520+ using DefaultActorImpl = DefaultActorImpl<Runtime>;
1521+
1522+ auto ActorObj = readObj<DefaultActorImpl>(ActorPtr);
1523+ if (!ActorObj)
1524+ return {std::string (" failure reading actor" ), {}};
1525+
1526+ ActorInfo Info{};
1527+ Info.Flags = ActorObj->Flags ;
1528+
1529+ // Status is the low 3 bits of Flags. Status of 0 is Idle. Don't read
1530+ // FirstJob when idle.
1531+ auto Status = Info.Flags & 0x7 ;
1532+ if (Status != 0 ) {
1533+ // This is a JobRef which stores flags in the low bits.
1534+ Info.FirstJob = ActorObj->FirstJob & ~StoredPointer (0x3 );
1535+ }
1536+ return {llvm::None, Info};
1537+ }
14071538
1408- StoredPointer SlabPtr = AsyncTaskObj->PrivateStorage .Allocator .FirstSlab ;
1409- return {llvm::None, SlabPtr};
1539+ StoredPointer nextJob (StoredPointer JobPtr) {
1540+ using Job = Job<Runtime>;
1541+
1542+ auto JobBytes = getReader ().readBytes (RemoteAddress (JobPtr), sizeof (Job));
1543+ auto *JobObj = reinterpret_cast <const Job *>(JobBytes.get ());
1544+ if (!JobObj)
1545+ return 0 ;
1546+
1547+ // This is a JobRef which stores flags in the low bits.
1548+ return JobObj->SchedulerPrivate [0 ] & ~StoredPointer (0x3 );
14101549 }
14111550
14121551private:
1552+ // Get the most human meaningful "run job" function pointer from the task,
1553+ // like AsyncTask::getResumeFunctionForLogging does.
1554+ StoredPointer getRunJob (const AsyncTask<Runtime> *AsyncTaskObj) {
1555+ auto Fptr = stripSignedPointer (AsyncTaskObj->RunJob );
1556+
1557+ loadTargetPointers ();
1558+ auto ResumeContextPtr = AsyncTaskObj->ResumeContextAndReserved [0 ];
1559+ if (target_non_future_adapter && Fptr == target_non_future_adapter) {
1560+ using Prefix = AsyncContextPrefix<Runtime>;
1561+ auto PrefixAddr = ResumeContextPtr - sizeof (Prefix);
1562+ auto PrefixBytes =
1563+ getReader ().readBytes (RemoteAddress (PrefixAddr), sizeof (Prefix));
1564+ if (PrefixBytes) {
1565+ auto PrefixPtr = reinterpret_cast <const Prefix *>(PrefixBytes.get ());
1566+ return stripSignedPointer (PrefixPtr->AsyncEntryPoint );
1567+ }
1568+ } else if (target_future_adapter && Fptr == target_future_adapter) {
1569+ using Prefix = FutureAsyncContextPrefix<Runtime>;
1570+ auto PrefixAddr = ResumeContextPtr - sizeof (Prefix);
1571+ auto PrefixBytes =
1572+ getReader ().readBytes (RemoteAddress (PrefixAddr), sizeof (Prefix));
1573+ if (PrefixBytes) {
1574+ auto PrefixPtr = reinterpret_cast <const Prefix *>(PrefixBytes.get ());
1575+ return stripSignedPointer (PrefixPtr->AsyncEntryPoint );
1576+ }
1577+ } else if ((target_task_wait_throwing_resume_adapter &&
1578+ Fptr == target_task_wait_throwing_resume_adapter) ||
1579+ (target_task_future_wait_resume_adapter &&
1580+ Fptr == target_task_future_wait_resume_adapter)) {
1581+ auto ContextBytes = getReader ().readBytes (RemoteAddress (ResumeContextPtr),
1582+ sizeof (AsyncContext<Runtime>));
1583+ if (ContextBytes) {
1584+ auto ContextPtr =
1585+ reinterpret_cast <const AsyncContext<Runtime> *>(ContextBytes.get ());
1586+ return stripSignedPointer (ContextPtr->ResumeParent );
1587+ }
1588+ }
1589+
1590+ return Fptr;
1591+ }
1592+
1593+ void loadTargetPointers () {
1594+ if (setupTargetPointers)
1595+ return ;
1596+
1597+ auto getFunc = [&](const std::string &name) -> StoredPointer {
1598+ auto Symbol = getReader ().getSymbolAddress (name);
1599+ if (!Symbol)
1600+ return 0 ;
1601+ auto Pointer = getReader ().readPointer (Symbol, sizeof (StoredPointer));
1602+ if (!Pointer)
1603+ return 0 ;
1604+ return Pointer->getResolvedAddress ().getAddressData ();
1605+ };
1606+ target_non_future_adapter =
1607+ getFunc (" _swift_concurrency_debug_non_future_adapter" );
1608+ target_future_adapter = getFunc (" _swift_concurrency_debug_future_adapter" );
1609+ target_task_wait_throwing_resume_adapter =
1610+ getFunc (" _swift_concurrency_debug_task_wait_throwing_resume_adapter" );
1611+ target_task_future_wait_resume_adapter =
1612+ getFunc (" _swift_concurrency_debug_task_future_wait_resume_adapter" );
1613+ setupTargetPointers = true ;
1614+ }
1615+
14131616 const TypeInfo *
14141617 getClosureContextInfo (StoredPointer Context, const ClosureContextInfo &Info,
14151618 remote::TypeInfoProvider *ExternalTypeInfo) {
@@ -1631,6 +1834,11 @@ class ReflectionContext
16311834
16321835 return llvm::None;
16331836 }
1837+
1838+ template <typename T>
1839+ MemoryReader::ReadObjResult<T> readObj (StoredPointer Ptr) {
1840+ return getReader ().template readObj <T>(RemoteAddress (Ptr));
1841+ }
16341842};
16351843
16361844} // end namespace reflection
0 commit comments