1717#ifndef SWIFT_ABI_TASK_H
1818#define SWIFT_ABI_TASK_H
1919
20+ #include " swift/Basic/RelativePointer.h"
2021#include " swift/ABI/HeapObject.h"
2122#include " swift/ABI/MetadataValues.h"
2223#include " swift/Runtime/Config.h"
@@ -32,7 +33,21 @@ class TaskStatusRecord;
3233
3334// / An ExecutorRef isn't necessarily just a pointer to an executor
3435// / object; it may have other bits set.
35- using ExecutorRef = Executor *;
36+ struct ExecutorRef {
37+ Executor *Pointer;
38+
39+ // / Get an executor ref that represents a lack of preference about
40+ // / where execution resumes. This is only valid in continuations,
41+ // / return contexts, and so on; it is not generally passed to
42+ // / executing functions.
43+ static ExecutorRef noPreference () {
44+ return { nullptr };
45+ }
46+
47+ bool operator ==(ExecutorRef other) const {
48+ return Pointer == other.Pointer ;
49+ }
50+ };
3651
3752using JobInvokeFunction =
3853 SWIFT_CC (swift)
@@ -42,6 +57,33 @@ using TaskContinuationFunction =
4257 SWIFT_CC (swift)
4358 void (AsyncTask *, ExecutorRef, AsyncContext *);
4459
60+ template <class Fn >
61+ struct AsyncFunctionTypeImpl ;
62+ template <class Result , class ... Params>
63+ struct AsyncFunctionTypeImpl <Result(Params...)> {
64+ // TODO: expand and include the arguments in the parameters.
65+ using type = TaskContinuationFunction;
66+ };
67+
68+ template <class Fn >
69+ using AsyncFunctionType = typename AsyncFunctionTypeImpl<Fn>::type;
70+
71+ // / A "function pointer" for an async function.
72+ // /
73+ // / Eventually, this will always be signed with the data key
74+ // / using a type-specific discriminator.
75+ template <class FnType >
76+ class AsyncFunctionPointer {
77+ public:
78+ // / The function to run.
79+ RelativeDirectPointer<AsyncFunctionType<FnType>,
80+ /* nullable*/ false ,
81+ int32_t > Function;
82+
83+ // / The expected size of the context.
84+ uint32_t ExpectedContextSize;
85+ };
86+
4587// / A schedulable job.
4688class alignas (2 * alignof (void *)) Job {
4789public:
@@ -76,7 +118,7 @@ class alignas(2 * alignof(void*)) Job {
76118 }
77119
78120 // / Run this job.
79- void run (Executor * currentExecutor);
121+ void run (ExecutorRef currentExecutor);
80122};
81123
82124// The compiler will eventually assume these.
@@ -128,7 +170,7 @@ class ActiveTaskStatus {
128170// / An asynchronous task. Tasks are the analogue of threads for
129171// / asynchronous functions: that is, they are a persistent identity
130172// / for the overall async computation.
131- class AsyncTask : public Job {
173+ class AsyncTask : public HeapObject , public Job {
132174public:
133175 // / The context for resuming the job. When a task is scheduled
134176 // / as a job, the next continuation should be installed as the
@@ -146,9 +188,10 @@ class AsyncTask : public Job {
146188 // / Reserved for the use of the task-local stack allocator.
147189 void *AllocatorPrivate[4 ];
148190
149- AsyncTask (JobFlags flags, TaskContinuationFunction *run,
191+ AsyncTask (const HeapMetadata *metadata, JobFlags flags,
192+ TaskContinuationFunction *run,
150193 AsyncContext *initialContext)
151- : Job(flags, run),
194+ : HeapObject(metadata), Job(flags, run),
152195 ResumeContext (initialContext),
153196 Status(ActiveTaskStatus()) {
154197 assert (flags.isAsyncTask ());
@@ -164,12 +207,6 @@ class AsyncTask : public Job {
164207 return Status.load (std::memory_order_relaxed).isCancelled ();
165208 }
166209
167- bool isHeapObject () const { return Flags.task_isHeapObject (); }
168- HeapObject *heapObjectHeader () {
169- assert (isHeapObject ());
170- return reinterpret_cast <HeapObject*>(this ) - 1 ;
171- }
172-
173210 // / A fragment of an async task structure that happens to be a child task.
174211 class ChildFragment {
175212 // / The parent task of this task.
@@ -182,6 +219,8 @@ class AsyncTask : public Job {
182219 AsyncTask *NextChild = nullptr ;
183220
184221 public:
222+ ChildFragment (AsyncTask *parent) : Parent(parent) {}
223+
185224 AsyncTask *getParent () const {
186225 return Parent;
187226 }
@@ -191,6 +230,8 @@ class AsyncTask : public Job {
191230 }
192231 };
193232
233+ bool isFuture () const { return Flags.task_isFuture (); }
234+
194235 bool hasChildFragment () const { return Flags.task_isChildTask (); }
195236 ChildFragment *childFragment () {
196237 assert (hasChildFragment ());
@@ -205,7 +246,7 @@ class AsyncTask : public Job {
205246};
206247
207248// The compiler will eventually assume these.
208- static_assert (sizeof (AsyncTask) == 10 * sizeof (void *),
249+ static_assert (sizeof (AsyncTask) == 12 * sizeof (void *),
209250 " AsyncTask size is wrong" );
210251static_assert (alignof (AsyncTask) == 2 * alignof (void *),
211252 "AsyncTask alignment is wrong");
@@ -237,6 +278,9 @@ class alignas(MaximumAlignment) AsyncContext {
237278 TaskContinuationFunction * __ptrauth_swift_async_context_resume
238279 ResumeParent;
239280
281+ // / The executor that the parent needs to be resumed on.
282+ ExecutorRef ResumeParentExecutor;
283+
240284 // / Flags describing this context.
241285 // /
242286 // / Note that this field is only 32 bits; any alignment padding
@@ -245,31 +289,44 @@ class alignas(MaximumAlignment) AsyncContext {
245289 // / is of course interrupted by the YieldToParent field.
246290 AsyncContextFlags Flags;
247291
248- // Fields following this point may not be valid in all instances
249- // of AsyncContext.
250-
251- // / The function to call to temporarily resume running in the
252- // / parent context temporarily. Generally this means a semantic
253- // / yield. Requires Flags.hasYieldFunction().
254- TaskContinuationFunction * __ptrauth_swift_async_context_yield
255- YieldToParent;
256-
257- AsyncContext (AsyncContextFlags flags,
258- TaskContinuationFunction *resumeParent,
259- AsyncContext *parent)
260- : Parent (parent), ResumeParent (resumeParent), Flags (flags) {}
261-
262292 AsyncContext (AsyncContextFlags flags,
263293 TaskContinuationFunction *resumeParent,
264- TaskContinuationFunction *yieldToParent ,
294+ ExecutorRef resumeParentExecutor ,
265295 AsyncContext *parent)
266- : Parent (parent), ResumeParent (resumeParent), Flags (flags),
267- YieldToParent (yieldToParent) {}
296+ : Parent (parent), ResumeParent (resumeParent),
297+ ResumeParentExecutor (resumeParentExecutor),
298+ Flags (flags) {}
268299
269300 AsyncContext (const AsyncContext &) = delete ;
270301 AsyncContext &operator =(const AsyncContext &) = delete ;
271302};
272303
304+ // / An async context that supports yielding.
305+ class YieldingAsyncContext : public AsyncContext {
306+ public:
307+ // / The function to call to temporarily resume running in the
308+ // / parent context. Generally this means a semantic yield.
309+ TaskContinuationFunction * __ptrauth_swift_async_context_yield
310+ YieldToParent;
311+
312+ // / The executor that the parent context needs to be yielded to on.
313+ ExecutorRef YieldToParentExecutor;
314+
315+ YieldingAsyncContext (AsyncContextFlags flags,
316+ TaskContinuationFunction *resumeParent,
317+ ExecutorRef resumeParentExecutor,
318+ TaskContinuationFunction *yieldToParent,
319+ ExecutorRef yieldToParentExecutor,
320+ AsyncContext *parent)
321+ : AsyncContext(flags, resumeParent, resumeParentExecutor, parent),
322+ YieldToParent (yieldToParent),
323+ YieldToParentExecutor(yieldToParentExecutor) {}
324+
325+ static bool classof (const AsyncContext *context) {
326+ return context->Flags .getKind () == AsyncContextKind::Yielding;
327+ }
328+ };
329+
273330} // end namespace swift
274331
275332#endif
0 commit comments