@@ -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 {}
@@ -1067,6 +1088,31 @@ class ReflectionContext
10671088 return dyn_cast_or_null<const RecordTypeInfo>(TypeInfo);
10681089 }
10691090
1091+ bool metadataIsActor (StoredPointer MetadataAddress) {
1092+ auto Metadata = readMetadata (MetadataAddress);
1093+ if (!Metadata)
1094+ return false ;
1095+
1096+ // Only classes can be actors.
1097+ if (Metadata->getKind () != MetadataKind::Class)
1098+ return false ;
1099+
1100+ auto DescriptorAddress =
1101+ super::readAddressOfNominalTypeDescriptor (Metadata);
1102+ if (!DescriptorAddress)
1103+ return false ;
1104+
1105+ auto DescriptorBytes =
1106+ getReader ().readBytes (RemoteAddress (DescriptorAddress),
1107+ sizeof (TargetTypeContextDescriptor<Runtime>));
1108+ if (!DescriptorBytes)
1109+ return false ;
1110+ auto Descriptor =
1111+ reinterpret_cast <const TargetTypeContextDescriptor<Runtime> *>(
1112+ DescriptorBytes.get ());
1113+ return Descriptor->getTypeContextDescriptorFlags ().class_isActor ();
1114+ }
1115+
10701116 // / Iterate the protocol conformance cache tree rooted at NodePtr, calling
10711117 // / Call with the type and protocol in each node.
10721118 void iterateConformanceTree (StoredPointer NodePtr,
@@ -1378,22 +1424,179 @@ class ReflectionContext
13781424 return {llvm::None, {Slab->Next , SlabSize, {Chunk}}};
13791425 }
13801426
1381- std::pair<llvm::Optional<std::string>, StoredPointer>
1382- asyncTaskSlabPtr (StoredPointer AsyncTaskPtr) {
1383- using AsyncTask = AsyncTask<Runtime>;
1384-
1385- auto AsyncTaskBytes =
1386- getReader ().readBytes (RemoteAddress (AsyncTaskPtr), sizeof (AsyncTask));
1387- auto *AsyncTaskObj =
1388- reinterpret_cast <const AsyncTask *>(AsyncTaskBytes.get ());
1427+ std::pair<llvm::Optional<std::string>, AsyncTaskInfo>
1428+ asyncTaskInfo (StoredPointer AsyncTaskPtr) {
1429+ auto AsyncTaskObj = readObj<AsyncTask<Runtime>>(AsyncTaskPtr);
13891430 if (!AsyncTaskObj)
1390- return {std::string (" failure reading async task" ), 0 };
1431+ return {std::string (" failure reading async task" ), {}};
1432+
1433+ AsyncTaskInfo Info{};
1434+ Info.JobFlags = AsyncTaskObj->Flags ;
1435+ Info.TaskStatusFlags = AsyncTaskObj->PrivateStorage .Status .Flags ;
1436+ Info.Id =
1437+ AsyncTaskObj->Id | ((uint64_t )AsyncTaskObj->PrivateStorage .Id << 32 );
1438+ Info.AllocatorSlabPtr = AsyncTaskObj->PrivateStorage .Allocator .FirstSlab ;
1439+ Info.RunJob = getRunJob (AsyncTaskObj.get ());
1440+
1441+ // Find all child tasks.
1442+ auto RecordPtr = AsyncTaskObj->PrivateStorage .Status .Record ;
1443+ while (RecordPtr) {
1444+ auto RecordObj = readObj<TaskStatusRecord<Runtime>>(RecordPtr);
1445+ if (!RecordObj)
1446+ break ;
1447+
1448+ // This cuts off high bits if our size_t doesn't match the target's. We
1449+ // only read the Kind bits which are at the bottom, so that's OK here.
1450+ // Beware of this when reading anything else.
1451+ TaskStatusRecordFlags Flags{RecordObj->Flags };
1452+ auto Kind = Flags.getKind ();
1453+
1454+ StoredPointer ChildTask = 0 ;
1455+ if (Kind == TaskStatusRecordKind::ChildTask) {
1456+ auto RecordObj = readObj<ChildTaskStatusRecord<Runtime>>(RecordPtr);
1457+ if (RecordObj)
1458+ ChildTask = RecordObj->FirstChild ;
1459+ } else if (Kind == TaskStatusRecordKind::TaskGroup) {
1460+ auto RecordObj = readObj<TaskGroupTaskStatusRecord<Runtime>>(RecordPtr);
1461+ if (RecordObj)
1462+ ChildTask = RecordObj->FirstChild ;
1463+ }
1464+
1465+ while (ChildTask) {
1466+ Info.ChildTasks .push_back (ChildTask);
1467+
1468+ StoredPointer ChildFragmentAddr =
1469+ ChildTask + sizeof (AsyncTask<Runtime>);
1470+ auto ChildFragmentObj =
1471+ readObj<ChildFragment<Runtime>>(ChildFragmentAddr);
1472+ if (ChildFragmentObj)
1473+ ChildTask = ChildFragmentObj->NextChild ;
1474+ else
1475+ ChildTask = 0 ;
1476+ }
1477+
1478+ RecordPtr = RecordObj->Parent ;
1479+ }
1480+
1481+ // Walk the async backtrace if the task isn't running or cancelled.
1482+ // TODO: Use isEnqueued from https://github.com/apple/swift/pull/41088/ once
1483+ // that's available.
1484+ int IsCancelledFlag = 0x100 ;
1485+ int IsRunningFlag = 0x800 ;
1486+ if (!(AsyncTaskObj->PrivateStorage .Status .Flags & IsCancelledFlag) &&
1487+ !(AsyncTaskObj->PrivateStorage .Status .Flags & IsRunningFlag)) {
1488+ auto ResumeContext = AsyncTaskObj->ResumeContextAndReserved [0 ];
1489+ while (ResumeContext) {
1490+ auto ResumeContextObj = readObj<AsyncContext<Runtime>>(ResumeContext);
1491+ if (!ResumeContextObj)
1492+ break ;
1493+ Info.AsyncBacktraceFrames .push_back (
1494+ stripSignedPointer (ResumeContextObj->ResumeParent ));
1495+ ResumeContext = stripSignedPointer (ResumeContextObj->Parent );
1496+ }
1497+ }
1498+
1499+ return {llvm::None, Info};
1500+ }
1501+
1502+ std::pair<llvm::Optional<std::string>, ActorInfo>
1503+ actorInfo (StoredPointer ActorPtr) {
1504+ using DefaultActorImpl = DefaultActorImpl<Runtime>;
1505+
1506+ auto ActorObj = readObj<DefaultActorImpl>(ActorPtr);
1507+ if (!ActorObj)
1508+ return {std::string (" failure reading actor" ), {}};
1509+
1510+ ActorInfo Info{};
1511+ Info.Flags = ActorObj->Flags ;
1512+
1513+ // Status is the low 3 bits of Flags. Status of 0 is Idle. Don't read
1514+ // FirstJob when idle.
1515+ auto Status = Info.Flags & 0x7 ;
1516+ if (Status != 0 ) {
1517+ // This is a JobRef which stores flags in the low bits.
1518+ Info.FirstJob = ActorObj->FirstJob & ~StoredPointer (0x3 );
1519+ }
1520+ return {llvm::None, Info};
1521+ }
13911522
1392- StoredPointer SlabPtr = AsyncTaskObj->PrivateStorage .Allocator .FirstSlab ;
1393- return {llvm::None, SlabPtr};
1523+ StoredPointer nextJob (StoredPointer JobPtr) {
1524+ using Job = Job<Runtime>;
1525+
1526+ auto JobBytes = getReader ().readBytes (RemoteAddress (JobPtr), sizeof (Job));
1527+ auto *JobObj = reinterpret_cast <const Job *>(JobBytes.get ());
1528+ if (!JobObj)
1529+ return 0 ;
1530+
1531+ // This is a JobRef which stores flags in the low bits.
1532+ return JobObj->SchedulerPrivate [0 ] & ~StoredPointer (0x3 );
13941533 }
13951534
13961535private:
1536+ // Get the most human meaningful "run job" function pointer from the task,
1537+ // like AsyncTask::getResumeFunctionForLogging does.
1538+ StoredPointer getRunJob (const AsyncTask<Runtime> *AsyncTaskObj) {
1539+ auto Fptr = stripSignedPointer (AsyncTaskObj->RunJob );
1540+
1541+ loadTargetPointers ();
1542+ auto ResumeContextPtr = AsyncTaskObj->ResumeContextAndReserved [0 ];
1543+ if (target_non_future_adapter && Fptr == target_non_future_adapter) {
1544+ using Prefix = AsyncContextPrefix<Runtime>;
1545+ auto PrefixAddr = ResumeContextPtr - sizeof (Prefix);
1546+ auto PrefixBytes =
1547+ getReader ().readBytes (RemoteAddress (PrefixAddr), sizeof (Prefix));
1548+ if (PrefixBytes) {
1549+ auto PrefixPtr = reinterpret_cast <const Prefix *>(PrefixBytes.get ());
1550+ return stripSignedPointer (PrefixPtr->AsyncEntryPoint );
1551+ }
1552+ } else if (target_future_adapter && Fptr == target_future_adapter) {
1553+ using Prefix = FutureAsyncContextPrefix<Runtime>;
1554+ auto PrefixAddr = ResumeContextPtr - sizeof (Prefix);
1555+ auto PrefixBytes =
1556+ getReader ().readBytes (RemoteAddress (PrefixAddr), sizeof (Prefix));
1557+ if (PrefixBytes) {
1558+ auto PrefixPtr = reinterpret_cast <const Prefix *>(PrefixBytes.get ());
1559+ return stripSignedPointer (PrefixPtr->AsyncEntryPoint );
1560+ }
1561+ } else if ((target_task_wait_throwing_resume_adapter &&
1562+ Fptr == target_task_wait_throwing_resume_adapter) ||
1563+ (target_task_future_wait_resume_adapter &&
1564+ Fptr == target_task_future_wait_resume_adapter)) {
1565+ auto ContextBytes = getReader ().readBytes (RemoteAddress (ResumeContextPtr),
1566+ sizeof (AsyncContext<Runtime>));
1567+ if (ContextBytes) {
1568+ auto ContextPtr =
1569+ reinterpret_cast <const AsyncContext<Runtime> *>(ContextBytes.get ());
1570+ return stripSignedPointer (ContextPtr->ResumeParent );
1571+ }
1572+ }
1573+
1574+ return Fptr;
1575+ }
1576+
1577+ void loadTargetPointers () {
1578+ if (setupTargetPointers)
1579+ return ;
1580+
1581+ auto getFunc = [&](const std::string &name) -> StoredPointer {
1582+ auto Symbol = getReader ().getSymbolAddress (name);
1583+ if (!Symbol)
1584+ return 0 ;
1585+ auto Pointer = getReader ().readPointer (Symbol, sizeof (StoredPointer));
1586+ if (!Pointer)
1587+ return 0 ;
1588+ return Pointer->getResolvedAddress ().getAddressData ();
1589+ };
1590+ target_non_future_adapter =
1591+ getFunc (" _swift_concurrency_debug_non_future_adapter" );
1592+ target_future_adapter = getFunc (" _swift_concurrency_debug_future_adapter" );
1593+ target_task_wait_throwing_resume_adapter =
1594+ getFunc (" _swift_concurrency_debug_task_wait_throwing_resume_adapter" );
1595+ target_task_future_wait_resume_adapter =
1596+ getFunc (" _swift_concurrency_debug_task_future_wait_resume_adapter" );
1597+ setupTargetPointers = true ;
1598+ }
1599+
13971600 const TypeInfo *
13981601 getClosureContextInfo (StoredPointer Context, const ClosureContextInfo &Info,
13991602 remote::TypeInfoProvider *ExternalTypeInfo) {
@@ -1615,6 +1818,11 @@ class ReflectionContext
16151818
16161819 return llvm::None;
16171820 }
1821+
1822+ template <typename T>
1823+ MemoryReader::ReadObjResult<T> readObj (StoredPointer Ptr) {
1824+ return getReader ().template readObj <T>(RemoteAddress (Ptr));
1825+ }
16181826};
16191827
16201828} // end namespace reflection
0 commit comments