Skip to content

Commit d9798c0

Browse files
committed
Concurrency: Redo non-_f variants of swift_task_create to accept closures as is.
In their previous form, the non-`_f` variants of these entry points were unused, and IRGen lowered the `createAsyncTask` builtins to use the `_f` variants with a large amount of caller-side codegen to manually unpack closure values. Amid all this, it also failed to make anyone responsible for releasing the closure context after the task completed, causing every task creation to leak. Redo the `swift_task_create_*` entry points to accept the two words of an async closure value directly, and unpack the closure to get its invocation entry point and initial context size inside the runtime. (Also get rid of the non-future `swift_task_create` variant, since it's unused and it's subtly different in a lot of hairy ways from the future forms. Better to add it later when it's needed than to have a broken unexercised version now.)
1 parent 0164963 commit d9798c0

File tree

17 files changed

+213
-225
lines changed

17 files changed

+213
-225
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,8 @@ namespace SpecialPointerAuthDiscriminators {
11801180
const uint16_t AsyncContextYield = 0xe207; // = 57863
11811181
const uint16_t CancellationNotificationFunction = 0x1933; // = 6451
11821182
const uint16_t EscalationNotificationFunction = 0x5be4; // = 23524
1183+
const uint16_t AsyncThinNullaryFunction = 0x0f08; // = 3848
1184+
const uint16_t AsyncFutureFunction = 0x720f; // = 29199
11831185

11841186
/// Swift async context parameter stored in the extended frame info.
11851187
const uint16_t SwiftAsyncContextExtendedFrameEntry = 0xc31a; // = 49946

include/swift/ABI/Task.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,15 @@ class FutureAsyncContext : public AsyncContext {
553553
using AsyncContext::AsyncContext;
554554
};
555555

556+
/// An asynchronous context within a task that describes a general "Future"
557+
/// task that was started with a closure context.
558+
class FutureClosureAsyncContext : public FutureAsyncContext {
559+
public:
560+
HeapObject *closureContext;
561+
562+
using FutureAsyncContext::FutureAsyncContext;
563+
};
564+
556565
} // end namespace swift
557566

558567
#endif

include/swift/AST/Builtins.def

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -747,14 +747,6 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(GetCurrentAsyncTask, "getCurrentAsyncTask", "
747747
/// Cancel the given asynchronous task.
748748
BUILTIN_MISC_OPERATION_WITH_SILGEN(CancelAsyncTask, "cancelAsyncTask", "", Special)
749749

750-
/// createAsyncTask(): (
751-
/// Int, Builtin.NativeObject?, @escaping () async throws -> Void
752-
/// ) -> Builtin.NativeObject
753-
///
754-
/// Create a new asynchronous task, given flags, an (optional) parent task, and
755-
/// a function to execute.
756-
BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncTask, "createAsyncTask", "", Special)
757-
758750
/// createAsyncTaskFuture(): (
759751
/// Int, Builtin.NativeObject?, @escaping () async throws -> T
760752
/// ) -> Builtin.NativeObject

include/swift/AST/Builtins.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ llvm::AtomicOrdering decodeLLVMAtomicOrdering(StringRef O);
137137
bool canBuiltinBeOverloadedForType(BuiltinValueKind ID, Type Ty);
138138

139139
/// Retrieve the AST-level AsyncTaskAndContext type, used for the
140-
/// createAsyncTask builtin.
140+
/// createAsyncTask* builtins.
141141
Type getAsyncTaskAndContextType(ASTContext &ctx);
142142

143143
}

include/swift/Runtime/Concurrency.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ AsyncTaskAndContext swift_task_create_f(JobFlags flags,
4343
using FutureAsyncSignature =
4444
AsyncSignature<void(void*), /*throws*/ true>;
4545

46+
/// Create a task object with a future which will run the given
47+
/// closure.
48+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
49+
AsyncTaskAndContext swift_task_create_future(
50+
JobFlags flags, AsyncTask *parent, const Metadata *futureResultType,
51+
void *closureEntryPoint,
52+
HeapObject * /* +1 */ closureContext);
53+
4654
/// Create a task object with a future which will run the given
4755
/// function.
4856
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
@@ -51,6 +59,16 @@ AsyncTaskAndContext swift_task_create_future_f(
5159
FutureAsyncSignature::FunctionType *function,
5260
size_t initialContextSize);
5361

62+
/// Create a task object with a future which will run the given
63+
/// closure, and offer its result to the task group
64+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
65+
AsyncTaskAndContext swift_task_create_group_future(
66+
JobFlags flags,
67+
AsyncTask *parent, TaskGroup *group,
68+
const Metadata *futureResultType,
69+
void *closureEntryPoint,
70+
HeapObject * /* +1 */ closureContext);
71+
5472
/// Create a task object with a future which will run the given
5573
/// function, and offer its result to the task group
5674
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,6 +1513,18 @@ FUNCTION(TaskCreateFunc,
15131513
ARGS(SizeTy, SwiftTaskPtrTy, TaskContinuationFunctionPtrTy, SizeTy),
15141514
ATTRS(NoUnwind, ArgMemOnly))
15151515

1516+
// AsyncTaskAndContext swift_task_create_future(
1517+
// size_t flags, AsyncTask *task,
1518+
// const Metadata *futureResultType,
1519+
// void *closureEntry, HeapObject *closureContext);
1520+
FUNCTION(TaskCreateFuture,
1521+
swift_task_create_future, SwiftCC,
1522+
ConcurrencyAvailability,
1523+
RETURNS(AsyncTaskAndContextTy),
1524+
ARGS(SizeTy, SwiftTaskPtrTy, TypeMetadataPtrTy,
1525+
Int8PtrTy, RefCountedPtrTy),
1526+
ATTRS(NoUnwind, ArgMemOnly))
1527+
15161528
// AsyncTaskAndContext swift_task_create_future_f(
15171529
// size_t flags, AsyncTask *task,
15181530
// const Metadata *futureResultType,
@@ -1525,6 +1537,19 @@ FUNCTION(TaskCreateFutureFunc,
15251537
TaskContinuationFunctionPtrTy, SizeTy),
15261538
ATTRS(NoUnwind, ArgMemOnly))
15271539

1540+
// AsyncTaskAndContext swift_task_create_group_future(
1541+
// size_t flags, AsyncTask *task, TaskGroup *group,
1542+
// const Metadata *futureResultType,
1543+
// void *closureEntry, HeapObject *closureContext);
1544+
FUNCTION(TaskCreateGroupFuture,
1545+
swift_task_create_group_future, SwiftCC,
1546+
ConcurrencyAvailability,
1547+
RETURNS(AsyncTaskAndContextTy),
1548+
ARGS(SizeTy, SwiftTaskPtrTy, SwiftTaskGroupPtrTy,
1549+
TypeMetadataPtrTy,
1550+
Int8PtrTy, RefCountedPtrTy),
1551+
ATTRS(NoUnwind, ArgMemOnly))
1552+
15281553
// AsyncTaskAndContext swift_task_create_group_future_f(
15291554
// size_t flags, AsyncTask *task, TaskGroup *group,
15301555
// const Metadata *futureResultType,

lib/AST/Builtins.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,16 +1347,6 @@ Type swift::getAsyncTaskAndContextType(ASTContext &ctx) {
13471347
return TupleType::get(resultTupleElements, ctx);
13481348
}
13491349

1350-
static ValueDecl *getCreateAsyncTask(ASTContext &ctx, Identifier id) {
1351-
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows().build();
1352-
return getBuiltinFunction(
1353-
id,
1354-
{ ctx.getIntDecl()->getDeclaredInterfaceType(),
1355-
OptionalType::get(ctx.TheNativeObjectType),
1356-
FunctionType::get({ }, ctx.TheEmptyTupleType, extInfo) },
1357-
getAsyncTaskAndContextType(ctx));
1358-
}
1359-
13601350
static ValueDecl *getCreateAsyncTaskFuture(ASTContext &ctx, Identifier id) {
13611351
BuiltinFunctionBuilder builder(ctx);
13621352
auto genericParam = makeGenericParam().build(builder);
@@ -2558,9 +2548,6 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
25582548
case BuiltinValueKind::CancelAsyncTask:
25592549
return getCancelAsyncTask(Context, Id);
25602550

2561-
case BuiltinValueKind::CreateAsyncTask:
2562-
return getCreateAsyncTask(Context, Id);
2563-
25642551
case BuiltinValueKind::CreateAsyncTaskFuture:
25652552
return getCreateAsyncTaskFuture(Context, Id);
25662553

lib/IRGen/GenBuiltin.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,7 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
226226
return;
227227
}
228228

229-
if (Builtin.ID == BuiltinValueKind::CreateAsyncTask ||
230-
Builtin.ID == BuiltinValueKind::CreateAsyncTaskFuture ||
229+
if (Builtin.ID == BuiltinValueKind::CreateAsyncTaskFuture ||
231230
Builtin.ID == BuiltinValueKind::CreateAsyncTaskGroupFuture) {
232231

233232
auto flags = args.claimNext();

lib/IRGen/GenCall.cpp

Lines changed: 6 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3766,86 +3766,24 @@ llvm::Value *irgen::emitTaskCreate(
37663766
parentTask = IGF.Builder.CreateBitOrPointerCast(
37673767
parentTask, IGF.IGM.SwiftTaskPtrTy);
37683768

3769-
// Determine the size of the async context for the closure.
3770-
ASTContext &ctx = IGF.IGM.IRGen.SIL.getASTContext();
3771-
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows().build();
3772-
CanSILFunctionType taskFunctionType;
3773-
CanSILFunctionType substTaskFunctionType;
3774-
if (futureResultType) {
3775-
auto genericParam = GenericTypeParamType::get(0, 0, ctx);
3776-
auto genericSig = GenericSignature::get({genericParam}, {});
3777-
auto *ty = GenericFunctionType::get(genericSig, { }, genericParam, extInfo);
3778-
3779-
taskFunctionType = IGF.IGM.getLoweredType(ty).castTo<SILFunctionType>();
3780-
substTaskFunctionType = taskFunctionType->withInvocationSubstitutions(subs);
3781-
} else {
3782-
auto *ty = FunctionType::get({ }, ctx.TheEmptyTupleType, extInfo);
3783-
taskFunctionType = IGF.IGM.getLoweredType(ty).castTo<SILFunctionType>();
3784-
substTaskFunctionType = taskFunctionType;
3785-
}
3786-
auto layout = getAsyncContextLayout(
3787-
IGF.IGM, taskFunctionType, substTaskFunctionType, subs,
3788-
/*suppress generics*/ false);
3789-
3790-
CanSILFunctionType taskContinuationFunctionTy = [&]() {
3791-
ASTContext &ctx = IGF.IGM.IRGen.SIL.getASTContext();
3792-
auto extInfo =
3793-
ASTExtInfoBuilder()
3794-
.withRepresentation(FunctionTypeRepresentation::CFunctionPointer)
3795-
.build();
3796-
// FIXME: Use the appropriate signature for TaskContinuationFunction:
3797-
//
3798-
// using TaskContinuationFunction =
3799-
// SWIFT_CC(swift)
3800-
// void (AsyncTask *, ExecutorRef, AsyncContext *);
3801-
auto ty = FunctionType::get({}, ctx.TheEmptyTupleType, extInfo);
3802-
return IGF.IGM.getLoweredType(ty).castTo<SILFunctionType>();
3803-
}();
3804-
3805-
// Call the function.
38063769
llvm::CallInst *result;
3807-
llvm::Value *theSize, *theFunction;
3808-
auto taskFunctionPointer = FunctionPointer::forExplosionValue(
3809-
IGF, taskFunction, substTaskFunctionType);
3810-
std::tie(theFunction, theSize) =
3811-
getAsyncFunctionAndSize(IGF, SILFunctionTypeRepresentation::Thick,
3812-
taskFunctionPointer, localContextInfo);
3813-
if (auto authInfo = PointerAuthInfo::forFunctionPointer(
3814-
IGF.IGM, taskContinuationFunctionTy)) {
3815-
theFunction = emitPointerAuthResign(
3816-
IGF, theFunction, taskFunctionPointer.getAuthInfo(), authInfo);
3817-
}
3818-
theFunction = IGF.Builder.CreateBitOrPointerCast(
3819-
theFunction, IGF.IGM.TaskContinuationFunctionPtrTy);
3820-
theSize = IGF.Builder.CreateZExtOrBitCast(theSize, IGF.IGM.SizeTy);
38213770
if (taskGroup && futureResultType) {
38223771
taskGroup = IGF.Builder.CreateBitOrPointerCast(
38233772
taskGroup, IGF.IGM.SwiftTaskGroupPtrTy);
38243773
result = IGF.Builder.CreateCall(
3825-
IGF.IGM.getTaskCreateGroupFutureFuncFn(),
3826-
{flags, parentTask, taskGroup, futureResultType, theFunction, theSize});
3774+
IGF.IGM.getTaskCreateGroupFutureFn(),
3775+
{flags, parentTask, taskGroup, futureResultType,
3776+
taskFunction, localContextInfo});
38273777
} else if (futureResultType) {
38283778
result = IGF.Builder.CreateCall(
3829-
IGF.IGM.getTaskCreateFutureFuncFn(),
3830-
{ flags, parentTask, futureResultType, theFunction, theSize });
3779+
IGF.IGM.getTaskCreateFutureFn(),
3780+
{flags, parentTask, futureResultType, taskFunction, localContextInfo});
38313781
} else {
3832-
result = IGF.Builder.CreateCall(IGF.IGM.getTaskCreateFuncFn(),
3833-
{flags, parentTask, theFunction, theSize});
3782+
llvm_unreachable("no future?!");
38343783
}
38353784
result->setDoesNotThrow();
38363785
result->setCallingConv(IGF.IGM.SwiftCC);
38373786

3838-
// Write the local context information into the initial context for the task.
3839-
assert(layout.hasLocalContext());
3840-
// Dig out the initial context returned from task creation.
3841-
auto initialContext = IGF.Builder.CreateExtractValue(result, {1});
3842-
Address initialContextAddr = layout.emitCastTo(IGF, initialContext);
3843-
3844-
auto localContextLayout = layout.getLocalContextLayout();
3845-
auto localContextAddr =
3846-
localContextLayout.project(IGF, initialContextAddr, llvm::None);
3847-
IGF.Builder.CreateStore(localContextInfo, localContextAddr);
3848-
38493787
return result;
38503788
}
38513789

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -747,20 +747,6 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, IntInstrprofIncrement)
747747
BUILTIN_OPERAND_OWNERSHIP(ForwardingConsume, COWBufferForReading)
748748
BUILTIN_OPERAND_OWNERSHIP(ForwardingConsume, UnsafeGuaranteed)
749749

750-
OperandOwnership
751-
OperandOwnershipBuiltinClassifier::visitCreateAsyncTask(BuiltinInst *bi,
752-
StringRef attr) {
753-
// The function operand is consumed by the new task.
754-
if (&op == &bi->getOperandRef(2))
755-
return OperandOwnership::DestroyingConsume;
756-
757-
// FIXME: These are considered InteriorPointer because they may propagate a
758-
// pointer into a borrowed values. If they do not propagate an interior pointer,
759-
// then they should be InstantaneousUse instead and should not require a
760-
// guaranteed value.
761-
return OperandOwnership::InteriorPointer;
762-
}
763-
764750
OperandOwnership
765751
OperandOwnershipBuiltinClassifier::visitCreateAsyncTaskFuture(BuiltinInst *bi,
766752
StringRef attr) {

0 commit comments

Comments
 (0)