@@ -174,23 +174,31 @@ static void destroyJob(SWIFT_CONTEXT HeapObject *obj) {
174174 assert (false && " A non-task job should never be destroyed as heap metadata." );
175175}
176176
177- SWIFT_CC (swift)
178- static void destroyTask(SWIFT_CONTEXT HeapObject *obj) {
179- auto task = static_cast <AsyncTask*>(obj);
177+ AsyncTask::~AsyncTask () {
180178 // For a future, destroy the result.
181- if (task-> isFuture ()) {
182- task-> futureFragment ()->destroy ();
179+ if (isFuture ()) {
180+ futureFragment ()->destroy ();
183181 }
184182
185183 // Release any objects potentially held as task local values.
186- task->Local .destroy (task);
184+ Local.destroy (this );
185+ }
186+
187+ SWIFT_CC (swift)
188+ static void destroyTask(SWIFT_CONTEXT HeapObject *obj) {
189+ auto task = static_cast <AsyncTask*>(obj);
190+
191+ task->~AsyncTask ();
187192
188193 // The task execution itself should always hold a reference to it, so
189194 // if we get here, we know the task has finished running, which means
190195 // swift_task_complete should have been run, which will have torn down
191196 // the task-local allocator. There's actually nothing else to clean up
192197 // here.
193198
199+ #if SWIFT_TASK_PRINTF_DEBUG
200+ fprintf (stderr, " [%p] destroy task %p\n " , pthread_self (), task);
201+ #endif
194202 free (task);
195203}
196204
@@ -250,13 +258,9 @@ static FullMetadata<DispatchClassMetadata> taskHeapMetadata = {
250258const void *const swift::_swift_concurrency_debug_asyncTaskMetadata =
251259 static_cast <Metadata *>(&taskHeapMetadata);
252260
253- // / The function that we put in the context of a simple task
254- // / to handle the final return.
255- SWIFT_CC (swiftasync)
256- static void completeTask(SWIFT_ASYNC_CONTEXT AsyncContext *context,
257- SWIFT_CONTEXT SwiftError *error) {
258- // Set that there's no longer a running task in the current thread.
259- auto task = _swift_task_clearCurrent ();
261+ static void completeTaskImpl (AsyncTask *task,
262+ AsyncContext *context,
263+ SwiftError *error) {
260264 assert (task && " completing task, but there is no active task registered" );
261265
262266 // Store the error result.
@@ -277,15 +281,41 @@ static void completeTask(SWIFT_ASYNC_CONTEXT AsyncContext *context,
277281#endif
278282
279283 // Complete the future.
284+ // Warning: This deallocates the task in case it's an async let task.
285+ // The task must not be accessed afterwards.
280286 if (task->isFuture ()) {
281287 task->completeFuture (context);
282288 }
283289
284290 // TODO: set something in the status?
285- if (task->hasChildFragment ()) {
291+ // if (task->hasChildFragment()) {
286292 // TODO: notify the parent somehow?
287293 // TODO: remove this task from the child-task chain?
288- }
294+ // }
295+ }
296+
297+ // / The function that we put in the context of a simple task
298+ // / to handle the final return.
299+ SWIFT_CC (swiftasync)
300+ static void completeTask(SWIFT_ASYNC_CONTEXT AsyncContext *context,
301+ SWIFT_CONTEXT SwiftError *error) {
302+ // Set that there's no longer a running task in the current thread.
303+ auto task = _swift_task_clearCurrent ();
304+ assert (task && " completing task, but there is no active task registered" );
305+
306+ completeTaskImpl (task, context, error);
307+ }
308+
309+ // / The function that we put in the context of a simple task
310+ // / to handle the final return.
311+ SWIFT_CC (swiftasync)
312+ static void completeTaskAndRelease(SWIFT_ASYNC_CONTEXT AsyncContext *context,
313+ SWIFT_CONTEXT SwiftError *error) {
314+ // Set that there's no longer a running task in the current thread.
315+ auto task = _swift_task_clearCurrent ();
316+ assert (task && " completing task, but there is no active task registered" );
317+
318+ completeTaskImpl (task, context, error);
289319
290320 // Release the task, balancing the retain that a running task has on itself.
291321 // If it was a group child task, it will remain until the group returns it.
@@ -304,7 +334,7 @@ static void completeTaskWithClosure(SWIFT_ASYNC_CONTEXT AsyncContext *context,
304334 swift_release ((HeapObject *)asyncContextPrefix->closureContext );
305335
306336 // Clean up the rest of the task.
307- return completeTask (context, error);
337+ return completeTaskAndRelease (context, error);
308338}
309339
310340SWIFT_CC (swiftasync)
@@ -332,11 +362,16 @@ static void task_wait_throwing_resume_adapter(SWIFT_ASYNC_CONTEXT AsyncContext *
332362}
333363
334364// / All `swift_task_create*` variants funnel into this common implementation.
365+ // /
366+ // / If \p isAsyncLetTask is true, the \p closureContext is not heap allocated,
367+ // / but stack-allocated (and must not be ref-counted).
368+ // / Also, async-let tasks are not heap allcoated, but allcoated with the parent
369+ // / task's stack allocator.
335370static AsyncTaskAndContext swift_task_create_group_future_commonImpl (
336371 JobFlags flags, TaskGroup *group,
337372 const Metadata *futureResultType,
338373 FutureAsyncSignature::FunctionType *function,
339- void *closureContext, bool owningClosureContext ,
374+ void *closureContext, bool isAsyncLetTask ,
340375 size_t initialContextSize) {
341376 assert ((futureResultType != nullptr ) == flags.task_isFuture ());
342377 assert (!flags.task_isFuture () ||
@@ -378,10 +413,19 @@ static AsyncTaskAndContext swift_task_create_group_future_commonImpl(
378413
379414 assert (amountToAllocate % MaximumAlignment == 0 );
380415
381- // TODO: allow optionally passing in an allocation+sizeOfIt to reuse for the task
382- // if the necessary space is enough, we can initialize into it rather than malloc.
383- // this would allow us to stack-allocate async-let related tasks.
384- void *allocation = malloc (amountToAllocate);
416+ constexpr unsigned initialSlabSize = 512 ;
417+
418+ void *allocation = nullptr ;
419+ if (isAsyncLetTask) {
420+ assert (parent);
421+ allocation = _swift_task_alloc_specific (parent,
422+ amountToAllocate + initialSlabSize);
423+ } else {
424+ allocation = malloc (amountToAllocate);
425+ }
426+ #if SWIFT_TASK_PRINTF_DEBUG
427+ fprintf (stderr, " [%p] allocate task %p, parent = %p\n " , pthread_self (), allocation, parent);
428+ #endif
385429
386430 AsyncContext *initialContext =
387431 reinterpret_cast <AsyncContext*>(
@@ -417,9 +461,17 @@ static AsyncTaskAndContext swift_task_create_group_future_commonImpl(
417461
418462 // Initialize the task so that resuming it will run the given
419463 // function on the initial context.
420- AsyncTask *task =
421- new (allocation) AsyncTask (&taskHeapMetadata, flags,
422- function, initialContext);
464+ AsyncTask *task = nullptr ;
465+ if (isAsyncLetTask) {
466+ // Initialize the refcount bits to "immortal", so that
467+ // ARC operations don't have any effect on the task.
468+ task = new (allocation) AsyncTask (&taskHeapMetadata,
469+ InlineRefCounts::Immortal, flags,
470+ function, initialContext);
471+ } else {
472+ task = new (allocation) AsyncTask (&taskHeapMetadata, flags,
473+ function, initialContext);
474+ }
423475
424476 // Initialize the child fragment if applicable.
425477 if (parent) {
@@ -471,15 +523,21 @@ static AsyncTaskAndContext swift_task_create_group_future_commonImpl(
471523 // as if they might be null, even though the only time they ever might
472524 // be is the final hop. Store a signed null instead.
473525 initialContext->Parent = nullptr ;
474- initialContext->ResumeParent = reinterpret_cast <TaskContinuationFunction *>(
475- (closureContext && owningClosureContext) ? &completeTaskWithClosure :
476- &completeTask);
477526 initialContext->Flags = AsyncContextKind::Ordinary;
478527 initialContext->Flags .setShouldNotDeallocateInCallee (true );
479528
480529 // Initialize the task-local allocator.
481- // TODO: consider providing an initial pre-allocated first slab to the allocator.
482- _swift_task_alloc_initialize (task);
530+ if (isAsyncLetTask) {
531+ initialContext->ResumeParent = reinterpret_cast <TaskContinuationFunction *>(
532+ &completeTask);
533+ assert (parent);
534+ void *initialSlab = (char *)allocation + amountToAllocate;
535+ _swift_task_alloc_initialize_with_slab (task, initialSlab, initialSlabSize);
536+ } else {
537+ initialContext->ResumeParent = reinterpret_cast <TaskContinuationFunction *>(
538+ closureContext ? &completeTaskWithClosure : &completeTaskAndRelease);
539+ _swift_task_alloc_initialize (task);
540+ }
483541
484542 // TODO: if the allocator would be prepared earlier we could do this in some
485543 // other existing if-parent if rather than adding another one here.
@@ -494,7 +552,7 @@ static AsyncTaskAndContext swift_task_create_group_future_commonImpl(
494552static AsyncTaskAndContext swift_task_create_group_future_common (
495553 JobFlags flags, TaskGroup *group, const Metadata *futureResultType,
496554 FutureAsyncSignature::FunctionType *function,
497- void *closureContext, bool owningClosureContext ,
555+ void *closureContext, bool isAsyncLetTask ,
498556 size_t initialContextSize);
499557
500558AsyncTaskAndContext
@@ -524,7 +582,7 @@ AsyncTaskAndContext swift::swift_task_create_group_future_f(
524582 return swift_task_create_group_future_common (flags, group,
525583 futureResultType,
526584 function, nullptr ,
527- /* owningClosureContext */ false ,
585+ /* isAsyncLetTask */ false ,
528586 initialContextSize);
529587}
530588
@@ -560,11 +618,11 @@ AsyncTaskAndContext swift::swift_task_create_future(JobFlags flags,
560618 return swift_task_create_group_future_common (
561619 flags, nullptr , futureResultType,
562620 taskEntry, closureContext,
563- /* owningClosureContext */ true ,
621+ /* isAsyncLetTask */ false ,
564622 initialContextSize);
565623}
566624
567- AsyncTaskAndContext swift::swift_task_create_future_no_escaping (JobFlags flags,
625+ AsyncTaskAndContext swift::swift_task_create_async_let_future (JobFlags flags,
568626 const Metadata *futureResultType,
569627 void *closureEntry,
570628 void *closureContext) {
@@ -579,7 +637,7 @@ AsyncTaskAndContext swift::swift_task_create_future_no_escaping(JobFlags flags,
579637 return swift_task_create_group_future_common (
580638 flags, nullptr , futureResultType,
581639 taskEntry, closureContext,
582- /* owningClosureContext */ false ,
640+ /* isAsyncLetTask */ true ,
583641 initialContextSize);
584642}
585643
@@ -599,7 +657,7 @@ swift::swift_task_create_group_future(
599657 return swift_task_create_group_future_common (
600658 flags, group, futureResultType,
601659 taskEntry, closureContext,
602- /* owningClosureContext */ true ,
660+ /* isAsyncLetTask */ false ,
603661 initialContextSize);
604662}
605663
0 commit comments