Skip to content

Commit bedca5e

Browse files
authored
Merge pull request swiftlang#36139 from mikeash/async-task-dispatch-integration
[Concurrency] Make Job/AsyncTask minimally compatible with dispatch object layout
2 parents 4be2f3a + bd62fdb commit bedca5e

File tree

8 files changed

+71
-22
lines changed

8 files changed

+71
-22
lines changed

include/swift/ABI/Metadata.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,6 +1333,26 @@ struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
13331333
};
13341334
using ClassMetadata = TargetClassMetadata<InProcess>;
13351335

1336+
/// The structure of class metadata that's compatible with dispatch objects.
1337+
/// This includes Swift heap metadata, followed by the vtable entries that
1338+
/// dispatch expects to see, with padding to place them at the expected offsets.
1339+
template <typename Runtime>
1340+
struct TargetDispatchClassMetadata : public TargetHeapMetadata<Runtime> {
1341+
using DummyVTableCall = void (*)(void);
1342+
1343+
TargetDispatchClassMetadata(MetadataKind Kind,
1344+
DummyVTableCall DummyVTableEntry)
1345+
: TargetHeapMetadata<Runtime>(Kind), DummyVTableEntry(DummyVTableEntry) {}
1346+
1347+
TargetPointer<Runtime, void> Opaque;
1348+
#if SWIFT_OBJC_INTEROP
1349+
TargetPointer<Runtime, void> OpaqueObjC[3];
1350+
#endif
1351+
1352+
TargetSignedPointer<Runtime, DummyVTableCall> DummyVTableEntry;
1353+
};
1354+
using DispatchClassMetadata = TargetDispatchClassMetadata<InProcess>;
1355+
13361356
/// The structure of metadata for heap-allocated local variables.
13371357
/// This is non-type metadata.
13381358
template <typename Runtime>

include/swift/ABI/MetadataKind.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ METADATAKIND(ErrorObject,
8989
METADATAKIND(Task,
9090
2 | MetadataKindIsNonType | MetadataKindIsRuntimePrivate)
9191

92+
/// A non-task async job.
93+
METADATAKIND(Job,
94+
3 | MetadataKindIsNonType | MetadataKindIsRuntimePrivate)
95+
9296
// getEnumeratedMetadataKind assumes that all the enumerated values here
9397
// will be <= LastEnumeratedMetadataKind.
9498

include/swift/ABI/Task.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ struct SwiftError;
3636
class TaskStatusRecord;
3737
class TaskGroup;
3838

39+
extern FullMetadata<DispatchClassMetadata> jobHeapMetadata;
40+
3941
/// A schedulable job.
40-
class alignas(2 * alignof(void*)) Job {
42+
class alignas(2 * alignof(void*)) Job : public HeapObject {
4143
protected:
4244
// Indices into SchedulerPrivate, for use by the runtime.
4345
enum {
@@ -62,13 +64,15 @@ class alignas(2 * alignof(void*)) Job {
6264
TaskContinuationFunction * __ptrauth_swift_task_resume_function ResumeTask;
6365
};
6466

65-
Job(JobFlags flags, JobInvokeFunction *invoke)
66-
: Flags(flags), RunJob(invoke) {
67+
Job(JobFlags flags, JobInvokeFunction *invoke,
68+
const HeapMetadata *metadata = &jobHeapMetadata)
69+
: HeapObject(metadata), Flags(flags), RunJob(invoke) {
6770
assert(!isAsyncTask() && "wrong constructor for a task");
6871
}
6972

70-
Job(JobFlags flags, TaskContinuationFunction *invoke)
71-
: Flags(flags), ResumeTask(invoke) {
73+
Job(JobFlags flags, TaskContinuationFunction *invoke,
74+
const HeapMetadata *metadata = &jobHeapMetadata)
75+
: HeapObject(metadata), Flags(flags), ResumeTask(invoke) {
7276
assert(isAsyncTask() && "wrong constructor for a non-task job");
7377
}
7478

@@ -94,7 +98,7 @@ class alignas(2 * alignof(void*)) Job {
9498
};
9599

96100
// The compiler will eventually assume these.
97-
static_assert(sizeof(Job) == 4 * sizeof(void*),
101+
static_assert(sizeof(Job) == 6 * sizeof(void*),
98102
"Job size is wrong");
99103
static_assert(alignof(Job) == 2 * alignof(void*),
100104
"Job alignment is wrong");
@@ -154,7 +158,7 @@ class ActiveTaskStatus {
154158
///
155159
/// * The future fragment is dynamic in size, based on the future result type
156160
/// it can hold, and thus must be the *last* fragment.
157-
class AsyncTask : public HeapObject, public Job {
161+
class AsyncTask : public Job {
158162
public:
159163
/// The context for resuming the job. When a task is scheduled
160164
/// as a job, the next continuation should be installed as the
@@ -178,7 +182,7 @@ class AsyncTask : public HeapObject, public Job {
178182
AsyncTask(const HeapMetadata *metadata, JobFlags flags,
179183
TaskContinuationFunction *run,
180184
AsyncContext *initialContext)
181-
: HeapObject(metadata), Job(flags, run),
185+
: Job(flags, run, metadata),
182186
ResumeContext(initialContext),
183187
Status(ActiveTaskStatus()),
184188
Local(TaskLocal::Storage()) {
@@ -444,7 +448,6 @@ class AsyncTask : public HeapObject, public Job {
444448
return reinterpret_cast<AsyncTask *&>(
445449
SchedulerPrivate[NextWaitingTaskIndex]);
446450
}
447-
448451
};
449452

450453
// The compiler will eventually assume these.

lib/IRGen/GenBuiltin.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,11 +259,8 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
259259

260260
if (Builtin.ID == BuiltinValueKind::ConvertTaskToJob) {
261261
auto task = args.claimNext();
262-
// The job object starts immediately past the heap-object header.
263-
auto bytes = IGF.Builder.CreateBitCast(task, IGF.IGM.Int8PtrTy);
264-
auto offset = IGF.IGM.RefCountedStructSize;
265-
bytes = IGF.Builder.CreateInBoundsGEP(bytes, IGF.IGM.getSize(offset));
266-
auto job = IGF.Builder.CreateBitCast(bytes, IGF.IGM.SwiftJobPtrTy);
262+
// The job object starts at the beginning of the task.
263+
auto job = IGF.Builder.CreateBitCast(task, IGF.IGM.SwiftJobPtrTy);
267264
out.add(job);
268265
return;
269266
}

lib/IRGen/IRGenModule.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,8 +623,10 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
623623
SwiftTaskGroupPtrTy = Int8PtrTy; // we pass it opaquely (TaskGroup*)
624624
SwiftExecutorPtrTy = SwiftExecutorTy->getPointerTo(DefaultAS);
625625
SwiftJobTy = createStructType(*this, "swift.job", {
626+
RefCountedStructTy, // object header
627+
Int8PtrTy, Int8PtrTy, // SchedulerPrivate
626628
SizeTy, // flags
627-
Int8PtrTy // execution function pointer
629+
FunctionPtrTy, // RunJob/ResumeTask
628630
});
629631
SwiftJobPtrTy = SwiftJobTy->getPointerTo();
630632

stdlib/public/Concurrency/GlobalExecutor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ static DelayedJob *DelayedJobQueue = nullptr;
8686

8787
/// Get the next-in-queue storage slot.
8888
static Job *&nextInQueue(Job *cur) {
89-
return reinterpret_cast<Job*&>(cur->SchedulerPrivate);
89+
return reinterpret_cast<Job*&>(&cur->SchedulerPrivate[NextWaitingTaskIndex]);
9090
}
9191

9292
/// Insert a job into the cooperative global queue.

stdlib/public/Concurrency/Task.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ void AsyncTask::completeFuture(AsyncContext *context, ExecutorRef executor) {
144144
}
145145
}
146146

147+
SWIFT_CC(swift)
148+
static void destroyJob(SWIFT_CONTEXT HeapObject *obj) {
149+
assert(false && "A non-task job should never be destroyed as heap metadata.");
150+
}
151+
147152
SWIFT_CC(swift)
148153
static void destroyTask(SWIFT_CONTEXT HeapObject *obj) {
149154
auto task = static_cast<AsyncTask*>(obj);
@@ -165,8 +170,27 @@ static void destroyTask(SWIFT_CONTEXT HeapObject *obj) {
165170
free(task);
166171
}
167172

173+
static void dummyVTableFunction(void) {
174+
abort();
175+
}
176+
177+
FullMetadata<DispatchClassMetadata> swift::jobHeapMetadata = {
178+
{
179+
{
180+
&destroyJob
181+
},
182+
{
183+
/*value witness table*/ nullptr
184+
}
185+
},
186+
{
187+
MetadataKind::Job,
188+
dummyVTableFunction
189+
}
190+
};
191+
168192
/// Heap metadata for an asynchronous task.
169-
static FullMetadata<HeapMetadata> taskHeapMetadata = {
193+
static FullMetadata<DispatchClassMetadata> taskHeapMetadata = {
170194
{
171195
{
172196
&destroyTask
@@ -176,7 +200,8 @@ static FullMetadata<HeapMetadata> taskHeapMetadata = {
176200
}
177201
},
178202
{
179-
MetadataKind::Task
203+
MetadataKind::Task,
204+
dummyVTableFunction
180205
}
181206
};
182207

test/IRGen/builtins.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -853,10 +853,8 @@ func globalStringTablePointerUse(_ str: String) -> Builtin.RawPointer {
853853

854854
// CHECK-LABEL: define {{.*}}convertTaskToJob
855855
// CHECK: call %swift.refcounted* @swift_retain(%swift.refcounted* returned %0)
856-
// CHECK-NEXT: [[T0:%.*]] = bitcast %swift.refcounted* %0 to i8*
857-
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8, i8* [[T0]], i64 16
858-
// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to %swift.job*
859-
// CHECK-NEXT: ret %swift.job* [[T2]]
856+
// CHECK-NEXT: [[T0:%.*]] = bitcast %swift.refcounted* %0 to %swift.job*
857+
// CHECK-NEXT: ret %swift.job* [[T0]]
860858
func convertTaskToJob(_ task: Builtin.NativeObject) -> Builtin.Job {
861859
return Builtin.convertTaskToJob(task)
862860
}

0 commit comments

Comments
 (0)