Skip to content

Commit 31f68b1

Browse files
committed
[RemoteMirror] Add a call for iterating over the allocations belonging to an AsyncTask.
rdar://72907056
1 parent 22acb2f commit 31f68b1

File tree

8 files changed

+210
-3
lines changed

8 files changed

+210
-3
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,22 @@ class ReflectionContext
114114
using typename super::StoredSignedPointer;
115115
using typename super::StoredSize;
116116

117+
struct AsyncTaskAllocationChunk {
118+
enum class ChunkKind {
119+
Unknown,
120+
NonPointer,
121+
RawPointer,
122+
StrongReference,
123+
UnownedReference,
124+
WeakReference,
125+
UnmanagedReference
126+
};
127+
128+
StoredPointer Start;
129+
unsigned Length;
130+
ChunkKind Kind;
131+
};
132+
117133
explicit ReflectionContext(std::shared_ptr<MemoryReader> reader)
118134
: super(std::move(reader), *this)
119135
{}
@@ -1165,6 +1181,48 @@ class ReflectionContext
11651181
return llvm::None;
11661182
}
11671183

1184+
llvm::Optional<std::string> iterateAsyncTaskAllocations(
1185+
StoredPointer AsyncTaskPtr,
1186+
std::function<void(StoredPointer, unsigned, AsyncTaskAllocationChunk[])>
1187+
Call) {
1188+
using AsyncTask = AsyncTask<Runtime>;
1189+
using StackAllocator = StackAllocator<Runtime>;
1190+
1191+
auto AsyncTaskBytes =
1192+
getReader().readBytes(RemoteAddress(AsyncTaskPtr), sizeof(AsyncTask));
1193+
auto *AsyncTaskObj =
1194+
reinterpret_cast<const AsyncTask *>(AsyncTaskBytes.get());
1195+
if (!AsyncTaskObj)
1196+
return std::string("failure reading async task");
1197+
1198+
auto *Allocator = reinterpret_cast<const StackAllocator *>(
1199+
&AsyncTaskObj->AllocatorPrivate);
1200+
StoredPointer SlabPtr = Allocator->FirstSlab;
1201+
while (SlabPtr) {
1202+
auto SlabBytes = getReader().readBytes(
1203+
RemoteAddress(SlabPtr), sizeof(typename StackAllocator::Slab));
1204+
auto Slab = reinterpret_cast<const typename StackAllocator::Slab *>(
1205+
SlabBytes.get());
1206+
if (!Slab)
1207+
return std::string("failure reading slab");
1208+
1209+
// For now, we won't try to walk the allocations in the slab, we'll just
1210+
// provide the whole thing as one big chunk.
1211+
size_t HeaderSize =
1212+
llvm::alignTo(sizeof(*Slab), llvm::Align(alignof(std::max_align_t)));
1213+
AsyncTaskAllocationChunk Chunk;
1214+
1215+
Chunk.Start = SlabPtr + HeaderSize;
1216+
Chunk.Length = Slab->CurrentOffset;
1217+
Chunk.Kind = AsyncTaskAllocationChunk::ChunkKind::Unknown;
1218+
Call(SlabPtr, 1, &Chunk);
1219+
1220+
SlabPtr = Slab->Next;
1221+
}
1222+
1223+
return llvm::None;
1224+
}
1225+
11681226
private:
11691227
const TypeInfo *
11701228
getClosureContextInfo(StoredPointer Context, const ClosureContextInfo &Info,

include/swift/Reflection/RuntimeInternals.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,40 @@ template <typename Runtime> struct ConformanceCacheEntry {
6060
typename Runtime::StoredPointer Witness;
6161
};
6262

63+
template <typename Runtime>
64+
struct HeapObject {
65+
typename Runtime::StoredPointer Metadata;
66+
typename Runtime::StoredSize RefCounts;
67+
};
68+
69+
template <typename Runtime>
70+
struct Job {
71+
typename Runtime::StoredPointer Opaque[4];
72+
};
73+
74+
template <typename Runtime>
75+
struct StackAllocator {
76+
typename Runtime::StoredPointer LastAllocation;
77+
typename Runtime::StoredPointer FirstSlab;
78+
int32_t NumAllocatedSlabs;
79+
bool FirstSlabIsPreallocated;
80+
81+
struct Slab {
82+
typename Runtime::StoredPointer Next;
83+
uint32_t Capacity;
84+
uint32_t CurrentOffset;
85+
};
86+
};
87+
88+
template <typename Runtime>
89+
struct AsyncTask {
90+
HeapObject<Runtime> HeapObject;
91+
Job<Runtime> Job;
92+
typename Runtime::StoredPointer ResumeContext;
93+
typename Runtime::StoredSize Status;
94+
typename Runtime::StoredPointer AllocatorPrivate[4];
95+
};
96+
6397
} // end namespace reflection
6498
} // end namespace swift
6599

include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,34 @@ const char *swift_reflection_iterateMetadataAllocationBacktraces(
372372
SwiftReflectionContextRef ContextRef,
373373
swift_metadataAllocationBacktraceIterator Call, void *ContextPtr);
374374

375+
/// Allocation iterator passed to swift_reflection_iterateAsyncTaskAllocations
376+
typedef void (*swift_asyncTaskAllocationIterator)(
377+
swift_reflection_ptr_t AllocationPtr, unsigned Count,
378+
swift_async_task_allocation_chunk_t Chunks[], void *ContextPtr);
379+
380+
/// Iterate over the allocations associated with the given async task object.
381+
/// This object must have an isa value equal to
382+
/// _swift_concurrency_debug_asyncTaskMetadata.
383+
///
384+
/// Calls the passed in Call function for each allocation associated with the
385+
/// async task object. The function is passed the allocation pointer and an
386+
/// array of chunks. Each chunk consists of a start, length, and kind for that
387+
/// chunk of the allocated memory. Any regions of the allocation that are not
388+
/// covered by a chunk are unallocated or garbage. The chunk array is valid only
389+
/// for the duration of the call.
390+
///
391+
/// An async task may have more than one allocation associated with it, so the
392+
/// function may be called more than once. It may also have no allocations, in
393+
/// which case the function is not called.
394+
///
395+
/// Returns NULL on success. On error, returns a pointer to a C string
396+
/// describing the error. This pointer remains valid until the next
397+
/// swift_reflection call on the given context.
398+
SWIFT_REMOTE_MIRROR_LINKAGE
399+
const char *swift_reflection_iterateAsyncTaskAllocations(
400+
SwiftReflectionContextRef ContextRef, swift_reflection_ptr_t AsyncTaskPtr,
401+
swift_asyncTaskAllocationIterator Call, void *ContextPtr);
402+
375403
#ifdef __cplusplus
376404
} // extern "C"
377405
#endif

include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,12 @@ typedef struct swift_metadata_cache_node {
189189
swift_reflection_ptr_t Right;
190190
} swift_metadata_cache_node_t;
191191

192+
typedef struct swift_async_task_allocation_chunk {
193+
swift_reflection_ptr_t Start;
194+
unsigned Length;
195+
swift_layout_kind_t Kind;
196+
} swift_async_task_allocation_chunk_t;
197+
192198
/// An opaque pointer to a context which maintains state and
193199
/// caching of reflection structure for heap instances.
194200
typedef struct SwiftReflectionContext *SwiftReflectionContextRef;

stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ public enum InstanceKind: UInt8 {
179179
case Closure
180180
case Enum
181181
case EnumValue
182+
case AsyncTask
182183
}
183184

184185
/// Represents a section in a loaded image in this process.
@@ -579,6 +580,12 @@ public func reflect(function: @escaping (Int, String, AnyObject?) -> Void) {
579580
fn.deallocate()
580581
}
581582

583+
584+
/// Reflect an AsyncTask.
585+
public func reflect(asyncTask: UInt) {
586+
reflect(instanceAddress: asyncTask, kind: .AsyncTask)
587+
}
588+
582589
/// Call this function to indicate to the parent that there are
583590
/// no more instances to look at.
584591
public func doneReflecting() {

stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,30 @@ static swift_childinfo_t convertChild(const TypeInfo *TI, unsigned Index) {
463463
};
464464
}
465465

466+
static swift_layout_kind_t convertAllocationChunkKind(
467+
NativeReflectionContext::AsyncTaskAllocationChunk::ChunkKind Kind) {
468+
switch (Kind) {
469+
case NativeReflectionContext::AsyncTaskAllocationChunk::ChunkKind::Unknown:
470+
return SWIFT_UNKNOWN;
471+
case NativeReflectionContext::AsyncTaskAllocationChunk::ChunkKind::NonPointer:
472+
return SWIFT_BUILTIN;
473+
case NativeReflectionContext::AsyncTaskAllocationChunk::ChunkKind::RawPointer:
474+
return SWIFT_RAW_POINTER;
475+
case NativeReflectionContext::AsyncTaskAllocationChunk::ChunkKind::
476+
StrongReference:
477+
return SWIFT_STRONG_REFERENCE;
478+
case NativeReflectionContext::AsyncTaskAllocationChunk::ChunkKind::
479+
UnownedReference:
480+
return SWIFT_UNOWNED_REFERENCE;
481+
case NativeReflectionContext::AsyncTaskAllocationChunk::ChunkKind::
482+
WeakReference:
483+
return SWIFT_WEAK_REFERENCE;
484+
case NativeReflectionContext::AsyncTaskAllocationChunk::ChunkKind::
485+
UnmanagedReference:
486+
return SWIFT_UNMANAGED_REFERENCE;
487+
}
488+
}
489+
466490
static const char *returnableCString(SwiftReflectionContextRef ContextRef,
467491
llvm::Optional<std::string> String) {
468492
if (String) {
@@ -718,3 +742,23 @@ const char *swift_reflection_iterateMetadataAllocationBacktraces(
718742
});
719743
return returnableCString(ContextRef, Error);
720744
}
745+
746+
const char *swift_reflection_iterateAsyncTaskAllocations(
747+
SwiftReflectionContextRef ContextRef, swift_reflection_ptr_t AsyncTaskPtr,
748+
swift_asyncTaskAllocationIterator Call, void *ContextPtr) {
749+
auto Context = ContextRef->nativeContext;
750+
auto Error = Context->iterateAsyncTaskAllocations(
751+
AsyncTaskPtr, [&](auto AllocationPtr, auto Count, auto Chunks) {
752+
std::vector<swift_async_task_allocation_chunk_t> ConvertedChunks;
753+
ConvertedChunks.reserve(Count);
754+
for (unsigned i = 0; i < Count; i++) {
755+
swift_async_task_allocation_chunk_t Chunk;
756+
Chunk.Start = Chunks[i].Start;
757+
Chunk.Length = Chunks[i].Length;
758+
Chunk.Kind = convertAllocationChunkKind(Chunks[i].Kind);
759+
ConvertedChunks.push_back(Chunk);
760+
}
761+
Call(AllocationPtr, Count, ConvertedChunks.data(), ContextPtr);
762+
});
763+
return returnableCString(ContextRef, Error);
764+
}

stdlib/tools/swift-reflection-test/messages.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ typedef enum InstanceKind {
2727
ErrorExistential,
2828
Closure,
2929
Enum,
30-
EnumValue
30+
EnumValue,
31+
AsyncTask
3132
} InstanceKind;

stdlib/tools/swift-reflection-test/swift-reflection-test.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include <assert.h>
2626
#include <errno.h>
27+
#include <inttypes.h>
2728
#include <stdint.h>
2829
#include <stdio.h>
2930
#include <stdlib.h>
@@ -70,7 +71,6 @@ static void errnoAndExit(const char *message) {
7071
}
7172

7273
#if 0
73-
#include <inttypes.h>
7474
#define DEBUG_LOG(fmt, ...) fprintf(stderr, "%s: " fmt "\n",\
7575
__func__, __VA_ARGS__)
7676
#else
@@ -281,7 +281,7 @@ PipeMemoryReader_receiveImages(SwiftReflectionContextRef RC,
281281
size_t NumReflectionInfos;
282282
PipeMemoryReader_collectBytesFromPipe(Reader, &NumReflectionInfos,
283283
sizeof(NumReflectionInfos));
284-
DEBUG_LOG("Receiving %z images from child", NumReflectionInfos);
284+
DEBUG_LOG("Receiving %zu images from child", NumReflectionInfos);
285285

286286
if (NumReflectionInfos == 0)
287287
return;
@@ -628,6 +628,29 @@ int reflectEnumValue(SwiftReflectionContextRef RC,
628628

629629
}
630630

631+
static void
632+
asyncTaskIterationCallback(swift_reflection_ptr_t AllocationPtr, unsigned Count,
633+
swift_async_task_allocation_chunk_t Chunks[],
634+
void *ContextPtr) {
635+
printf(" Allocation block %#" PRIx64 "\n", (uint64_t)AllocationPtr);
636+
for (unsigned i = 0; i < Count; i++)
637+
printf(" Chunk at %#" PRIx64 " length %u kind %u\n",
638+
(uint64_t)Chunks[i].Start, Chunks[i].Length, Chunks[i].Kind);
639+
}
640+
641+
int reflectAsyncTask(SwiftReflectionContextRef RC,
642+
const PipeMemoryReader Pipe) {
643+
uintptr_t AsyncTaskInstance = PipeMemoryReader_receiveInstanceAddress(&Pipe);
644+
printf("Async task %#" PRIx64 "\n", (uint64_t)AsyncTaskInstance);
645+
swift_reflection_iterateAsyncTaskAllocations(
646+
RC, AsyncTaskInstance, asyncTaskIterationCallback, NULL);
647+
648+
printf("\n\n");
649+
PipeMemoryReader_sendDoneMessage(&Pipe);
650+
fflush(stdout);
651+
return 1;
652+
}
653+
631654

632655
int doDumpHeapInstance(const char *BinaryFilename) {
633656
PipeMemoryReader Pipe = createPipeMemoryReader();
@@ -719,6 +742,12 @@ int doDumpHeapInstance(const char *BinaryFilename) {
719742
return EXIT_SUCCESS;
720743
break;
721744
}
745+
case AsyncTask: {
746+
printf("Reflecting an async task.\n");
747+
if (!reflectAsyncTask(RC, Pipe))
748+
return EXIT_SUCCESS;
749+
break;
750+
}
722751
case None:
723752
swift_reflection_destroyReflectionContext(RC);
724753
printf("Done.\n");

0 commit comments

Comments
 (0)