Skip to content

Commit 30b4769

Browse files
authored
Merge pull request #36621 from rjmccall/continuation-abi
Revise the ABI for interacting with unsafe continuations
2 parents 22506f9 + 98711fd commit 30b4769

39 files changed

+696
-285
lines changed

docs/ABI/Mangling.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,7 @@ Types
517517
type ::= 'BB' // Builtin.UnsafeValueBuffer
518518
type ::= 'Bc' // Builtin.RawUnsafeContinuation
519519
type ::= 'BD' // Builtin.DefaultActorStorage
520+
type ::= 'Be' // Builtin.ExecutorRef
520521
type ::= 'Bf' NATURAL '_' // Builtin.Float<n>
521522
type ::= 'Bi' NATURAL '_' // Builtin.Int<n>
522523
type ::= 'BI' // Builtin.IntLiteral

include/swift/ABI/MetadataValues.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2052,6 +2052,9 @@ enum class AsyncContextKind {
20522052
/// A context which can yield to its caller.
20532053
Yielding = 1,
20542054

2055+
/// A continuation context.
2056+
Continuation = 2,
2057+
20552058
// Other kinds are reserved for interesting special
20562059
// intermediate contexts.
20572060

@@ -2096,6 +2099,55 @@ class AsyncContextFlags : public FlagSet<uint32_t> {
20962099
setShouldNotDeallocateInCallee)
20972100
};
20982101

2102+
/// Flags passed to swift_continuation_init.
2103+
class AsyncContinuationFlags : public FlagSet<size_t> {
2104+
public:
2105+
enum {
2106+
CanThrow = 0,
2107+
HasExecutorOverride = 1,
2108+
IsPreawaited = 2,
2109+
};
2110+
2111+
explicit AsyncContinuationFlags(size_t bits) : FlagSet(bits) {}
2112+
constexpr AsyncContinuationFlags() {}
2113+
2114+
/// Whether the continuation is permitted to throw.
2115+
FLAGSET_DEFINE_FLAG_ACCESSORS(CanThrow, canThrow, setCanThrow)
2116+
2117+
/// Whether the continuation should be resumed on a different
2118+
/// executor than the current one. swift_continuation_init
2119+
/// will not initialize ResumeToExecutor if this is set.
2120+
FLAGSET_DEFINE_FLAG_ACCESSORS(HasExecutorOverride,
2121+
hasExecutorOverride,
2122+
setHasExecutorOverride)
2123+
2124+
/// Whether the continuation is "pre-awaited". If so, it should
2125+
/// be set up in the already-awaited state, and so resumptions
2126+
/// will immediately schedule the continuation to begin
2127+
/// asynchronously.
2128+
FLAGSET_DEFINE_FLAG_ACCESSORS(IsPreawaited,
2129+
isPreawaited,
2130+
setIsPreawaited)
2131+
};
2132+
2133+
/// Status values for a continuation. Note that the "not yet"s in
2134+
/// the description below aren't quite right because the system
2135+
/// does not actually promise to update the status before scheduling
2136+
/// the task. This is because the continuation context is immediately
2137+
/// invalidated once the task starts running again, so the window in
2138+
/// which we can usefully protect against (say) double-resumption may
2139+
/// be very small.
2140+
enum class ContinuationStatus : size_t {
2141+
/// The continuation has not yet been awaited or resumed.
2142+
Pending = 0,
2143+
2144+
/// The continuation has already been awaited, but not yet resumed.
2145+
Awaited = 1,
2146+
2147+
/// The continuation has already been resumed, but not yet awaited.
2148+
Resumed = 2
2149+
};
2150+
20992151
} // end namespace swift
21002152

21012153
#endif // SWIFT_ABI_METADATAVALUES_H

include/swift/ABI/Task.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,31 @@ class YieldingAsyncContext : public AsyncContext {
536536
}
537537
};
538538

539+
/// An async context that can be resumed as a continuation.
540+
class ContinuationAsyncContext : public AsyncContext {
541+
public:
542+
/// An atomic object used to ensure that a continuation is not
543+
/// scheduled immediately during a resume if it hasn't yet been
544+
/// awaited by the function which set it up.
545+
std::atomic<ContinuationStatus> AwaitSynchronization;
546+
547+
/// The error result value of the continuation.
548+
/// This should be null-initialized when setting up the continuation.
549+
/// Throwing resumers must overwrite this with a non-null value.
550+
SwiftError *ErrorResult;
551+
552+
/// A pointer to the normal result value of the continuation.
553+
/// Normal resumers must initialize this before resuming.
554+
OpaqueValue *NormalResult;
555+
556+
/// The executor that should be resumed to.
557+
ExecutorRef ResumeToExecutor;
558+
559+
static bool classof(const AsyncContext *context) {
560+
return context->Flags.getKind() == AsyncContextKind::Continuation;
561+
}
562+
};
563+
539564
/// An asynchronous context within a task that describes a general "Future".
540565
/// task.
541566
///

include/swift/AST/ASTSynthesis.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@ enum SingletonTypeSynthesizer {
4141
_any,
4242
_bridgeObject,
4343
_error,
44+
_executor,
4445
_job,
4546
_nativeObject,
4647
_never,
4748
_rawPointer,
49+
_rawUnsafeContinuation,
4850
_void,
4951
_word,
5052
};
@@ -54,10 +56,12 @@ inline Type synthesizeType(SynthesisContext &SC,
5456
case _any: return SC.Context.TheAnyType;
5557
case _bridgeObject: return SC.Context.TheBridgeObjectType;
5658
case _error: return SC.Context.getExceptionType();
59+
case _executor: return SC.Context.TheExecutorType;
5760
case _job: return SC.Context.TheJobType;
5861
case _nativeObject: return SC.Context.TheNativeObjectType;
5962
case _never: return SC.Context.getNeverType();
6063
case _rawPointer: return SC.Context.TheRawPointerType;
64+
case _rawUnsafeContinuation: return SC.Context.TheRawUnsafeContinuationType;
6165
case _void: return SC.Context.TheEmptyTupleType;
6266
case _word: return BuiltinIntegerType::get(BuiltinIntegerWidth::pointer(),
6367
SC.Context);

include/swift/AST/Builtins.def

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,18 @@ BUILTIN_MISC_OPERATION(InitializeDefaultActor, "initializeDefaultActor", "", Spe
723723
/// Destroy the default-actor instance in a default actor object.
724724
BUILTIN_MISC_OPERATION(DestroyDefaultActor, "destroyDefaultActor", "", Special)
725725

726+
/// Resume a non-throwing continuation normally with the given result.
727+
BUILTIN_MISC_OPERATION(ResumeNonThrowingContinuationReturning,
728+
"resumeNonThrowingContinuationReturning", "", Special)
729+
730+
/// Resume a throwing continuation normally with the given result.
731+
BUILTIN_MISC_OPERATION(ResumeThrowingContinuationReturning,
732+
"resumeThrowingContinuationReturning", "", Special)
733+
734+
/// Resume a throwing continuation abnormally with the given error.
735+
BUILTIN_MISC_OPERATION(ResumeThrowingContinuationThrowing,
736+
"resumeThrowingContinuationThrowing", "", Special)
737+
726738
// BUILTIN_MISC_OPERATION_WITH_SILGEN - Miscellaneous operations that are
727739
// specially emitted during SIL generation.
728740
//
@@ -736,7 +748,7 @@ BUILTIN_MISC_OPERATION(DestroyDefaultActor, "destroyDefaultActor", "", Special)
736748
BUILTIN_MISC_OPERATION(Id, Name, Attrs, Overload)
737749
#endif
738750

739-
// getCurrentExecutor: () async -> Builtin.Word
751+
// getCurrentExecutor: () async -> Builtin.Executor
740752
//
741753
// Retrieve the ExecutorRef on which the current asynchronous
742754
// function is executing.

include/swift/AST/TypeNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ ABSTRACT_TYPE(Builtin, Type)
103103
BUILTIN_TYPE(BuiltinInteger, AnyBuiltinIntegerType)
104104
BUILTIN_TYPE(BuiltinIntegerLiteral, AnyBuiltinIntegerType)
105105
TYPE_RANGE(AnyBuiltinInteger, BuiltinInteger, BuiltinIntegerLiteral)
106+
BUILTIN_TYPE(BuiltinExecutor, BuiltinType)
106107
BUILTIN_TYPE(BuiltinFloat, BuiltinType)
107108
BUILTIN_TYPE(BuiltinJob, BuiltinType)
108109
BUILTIN_TYPE(BuiltinRawPointer, BuiltinType)
@@ -181,6 +182,7 @@ LAST_TYPE(Dictionary) // Sugared types are last to make isa<SugarType>() fast.
181182
#ifdef SINGLETON_TYPE
182183
SINGLETON_TYPE(IntegerLiteral, BuiltinIntegerLiteral)
183184
SINGLETON_TYPE(Job, BuiltinJob)
185+
SINGLETON_TYPE(Executor, BuiltinExecutor)
184186
SINGLETON_TYPE(RawPointer, BuiltinRawPointer)
185187
SINGLETON_TYPE(RawUnsafeContinuation, BuiltinRawUnsafeContinuation)
186188
SINGLETON_TYPE(NativeObject, BuiltinNativeObject)

include/swift/AST/Types.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,6 +1416,19 @@ class BuiltinRawUnsafeContinuationType : public BuiltinType {
14161416
};
14171417
DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinRawUnsafeContinuationType, BuiltinType);
14181418

1419+
/// BuiltinExecutorType - The builtin executor-ref type. In C, this
1420+
/// is the ExecutorRef struct type.
1421+
class BuiltinExecutorType : public BuiltinType {
1422+
friend class ASTContext;
1423+
BuiltinExecutorType(const ASTContext &C)
1424+
: BuiltinType(TypeKind::BuiltinExecutor, C) {}
1425+
public:
1426+
static bool classof(const TypeBase *T) {
1427+
return T->getKind() == TypeKind::BuiltinExecutor;
1428+
}
1429+
};
1430+
DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinExecutorType, BuiltinType);
1431+
14191432
/// BuiltinJobType - The builtin job type. In C, this is a
14201433
/// non-null Job*. This pointer is completely unmanaged (the unscheduled
14211434
/// job is self-owning), but has more spare bits than Builtin.RawPointer.

include/swift/Runtime/Concurrency.h

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -523,23 +523,35 @@ void swift_defaultActor_destroy(DefaultActor *actor);
523523
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
524524
void swift_defaultActor_enqueue(Job *job, DefaultActor *actor);
525525

526-
/// Resume a task from its continuation, given a normal result value.
526+
/// Prepare a continuation in the current task.
527+
///
528+
/// The caller should initialize the Parent, ResumeParent,
529+
/// and NormalResult fields. This function will initialize the other
530+
/// fields with appropriate defaaults; the caller may then overwrite
531+
/// them if desired.
532+
///
533+
/// This function is provided as a code-size and runtime-usage
534+
/// optimization; calling it is not required if code is willing to
535+
/// do all its work inline.
536+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
537+
AsyncTask *swift_continuation_init(ContinuationAsyncContext *context,
538+
AsyncContinuationFlags flags);
539+
540+
/// Resume a task from a non-throwing continuation, given a normal
541+
/// result which has already been stored into the continuation.
527542
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
528-
void swift_continuation_resume(/* +1 */ OpaqueValue *result,
529-
void *continuation,
530-
const Metadata *resumeType);
543+
void swift_continuation_resume(AsyncTask *continuation);
531544

532-
/// Resume a task from its throwing continuation, given a normal result value.
545+
/// Resume a task from a potentially-throwing continuation, given a
546+
/// normal result which has already been stored into the continuation.
533547
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
534-
void swift_continuation_throwingResume(/* +1 */ OpaqueValue *result,
535-
void *continuation,
536-
const Metadata *resumeType);
548+
void swift_continuation_throwingResume(AsyncTask *continuation);
537549

538-
/// Resume a task from its throwing continuation by throwing an error.
550+
/// Resume a task from a potentially-throwing continuation by throwing
551+
/// an error.
539552
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
540-
void swift_continuation_throwingResumeWithError(/* +1 */ SwiftError *error,
541-
void *continuation,
542-
const Metadata *resumeType);
553+
void swift_continuation_throwingResumeWithError(AsyncTask *continuation,
554+
/* +1 */ SwiftError *error);
543555

544556
/// SPI helper to log a misuse of a `CheckedContinuation` to the appropriate places in the OS.
545557
extern "C" SWIFT_CC(swift)

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,6 +1581,40 @@ FUNCTION(TaskSwitchFunc,
15811581
ARGS(SwiftContextPtrTy, Int8PtrTy, SwiftExecutorPtrTy),
15821582
ATTRS(NoUnwind))
15831583

1584+
// AsyncTask *swift_continuation_init(AsyncContext *continuationContext,
1585+
// AsyncContinuationFlags);
1586+
FUNCTION(ContinuationInit,
1587+
swift_continuation_init, SwiftCC,
1588+
ConcurrencyAvailability,
1589+
RETURNS(SwiftTaskPtrTy),
1590+
ARGS(ContinuationAsyncContextPtrTy, SizeTy),
1591+
ATTRS(NoUnwind))
1592+
1593+
// void swift_continuation_resume(AsyncTask *continuation);
1594+
FUNCTION(ContinuationResume,
1595+
swift_continuation_resume, SwiftCC,
1596+
ConcurrencyAvailability,
1597+
RETURNS(VoidTy),
1598+
ARGS(SwiftTaskPtrTy),
1599+
ATTRS(NoUnwind))
1600+
1601+
// void swift_continuation_throwingResume(AsyncTask *continuation);
1602+
FUNCTION(ContinuationThrowingResume,
1603+
swift_continuation_throwingResume, SwiftCC,
1604+
ConcurrencyAvailability,
1605+
RETURNS(VoidTy),
1606+
ARGS(SwiftTaskPtrTy),
1607+
ATTRS(NoUnwind))
1608+
1609+
// void swift_continuation_throwingResumeWithError(AsyncTask *continuation,
1610+
// SwiftError *error);
1611+
FUNCTION(ContinuationThrowingResumeWithError,
1612+
swift_continuation_throwingResumeWithError, SwiftCC,
1613+
ConcurrencyAvailability,
1614+
RETURNS(VoidTy),
1615+
ARGS(SwiftTaskPtrTy, ErrorPtrTy),
1616+
ATTRS(NoUnwind))
1617+
15841618
// ExecutorRef swift_task_getCurrentExecutor();
15851619
FUNCTION(TaskGetCurrentExecutor,
15861620
swift_task_getCurrentExecutor, SwiftCC,

include/swift/Strings.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ constexpr static BuiltinNameStringLiteral BUILTIN_TYPE_NAME_UNSAFEVALUEBUFFER =
122122
/// The name of the Builtin type for Job
123123
constexpr static BuiltinNameStringLiteral BUILTIN_TYPE_NAME_JOB = {
124124
"Builtin.Job"};
125+
/// The name of the Builtin type for ExecutorRef
126+
constexpr static BuiltinNameStringLiteral BUILTIN_TYPE_NAME_EXECUTOR = {
127+
"Builtin.ExecutorRef"};
125128
/// The name of the Builtin type for DefaultActorStorage
126129
constexpr static BuiltinNameStringLiteral BUILTIN_TYPE_NAME_DEFAULTACTORSTORAGE = {
127130
"Builtin.DefaultActorStorage"};

lib/AST/ASTDumper.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3577,6 +3577,7 @@ namespace {
35773577

35783578
TRIVIAL_TYPE_PRINTER(BuiltinIntegerLiteral, builtin_integer_literal)
35793579
TRIVIAL_TYPE_PRINTER(BuiltinJob, builtin_job)
3580+
TRIVIAL_TYPE_PRINTER(BuiltinExecutor, builtin_executor_ref)
35803581
TRIVIAL_TYPE_PRINTER(BuiltinDefaultActorStorage, builtin_default_actor_storage)
35813582
TRIVIAL_TYPE_PRINTER(BuiltinRawPointer, builtin_raw_pointer)
35823583
TRIVIAL_TYPE_PRINTER(BuiltinRawUnsafeContinuation, builtin_raw_unsafe_continuation)

lib/AST/ASTMangler.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,8 @@ void ASTMangler::appendType(Type type, const ValueDecl *forDecl) {
10471047
return appendOperator("BI");
10481048
case TypeKind::BuiltinJob:
10491049
return appendOperator("Bj");
1050+
case TypeKind::BuiltinExecutor:
1051+
return appendOperator("Be");
10501052
case TypeKind::BuiltinDefaultActorStorage:
10511053
return appendOperator("BD");
10521054
case TypeKind::BuiltinRawPointer:

lib/AST/ASTPrinter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4407,6 +4407,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
44074407
ASTPRINTER_PRINT_BUILTINTYPE(BuiltinRawPointerType)
44084408
ASTPRINTER_PRINT_BUILTINTYPE(BuiltinRawUnsafeContinuationType)
44094409
ASTPRINTER_PRINT_BUILTINTYPE(BuiltinJobType)
4410+
ASTPRINTER_PRINT_BUILTINTYPE(BuiltinExecutorType)
44104411
ASTPRINTER_PRINT_BUILTINTYPE(BuiltinDefaultActorStorageType)
44114412
ASTPRINTER_PRINT_BUILTINTYPE(BuiltinNativeObjectType)
44124413
ASTPRINTER_PRINT_BUILTINTYPE(BuiltinBridgeObjectType)

lib/AST/Builtins.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,10 +1351,9 @@ static ValueDecl *getGetCurrentAsyncTask(ASTContext &ctx, Identifier id) {
13511351
}
13521352

13531353
static ValueDecl *getGetCurrentExecutor(ASTContext &ctx, Identifier id) {
1354-
BuiltinFunctionBuilder builder(ctx);
1355-
builder.setResult(makeConcrete(BuiltinIntegerType::getWordType(ctx)));
1356-
builder.setAsync();
1357-
return builder.build(id);
1354+
return getBuiltinFunction(ctx, id, _async(_thin),
1355+
_parameters(),
1356+
_executor);
13581357
}
13591358

13601359
static ValueDecl *getCancelAsyncTask(ASTContext &ctx, Identifier id) {
@@ -1411,6 +1410,23 @@ static ValueDecl *getDefaultActorInitDestroy(ASTContext &ctx,
14111410
_void);
14121411
}
14131412

1413+
static ValueDecl *getResumeContinuationReturning(ASTContext &ctx,
1414+
Identifier id) {
1415+
return getBuiltinFunction(ctx, id, _thin,
1416+
_generics(_unrestricted),
1417+
_parameters(_rawUnsafeContinuation,
1418+
_owned(_typeparam(0))),
1419+
_void);
1420+
}
1421+
1422+
static ValueDecl *getResumeContinuationThrowing(ASTContext &ctx,
1423+
Identifier id) {
1424+
return getBuiltinFunction(ctx, id, _thin,
1425+
_parameters(_rawUnsafeContinuation,
1426+
_owned(_error)),
1427+
_void);
1428+
}
1429+
14141430
static ValueDecl *getAutoDiffCreateLinearMapContext(ASTContext &ctx,
14151431
Identifier id) {
14161432
return getBuiltinFunction(
@@ -2621,6 +2637,13 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
26212637
case BuiltinValueKind::DestroyDefaultActor:
26222638
return getDefaultActorInitDestroy(Context, Id);
26232639

2640+
case BuiltinValueKind::ResumeNonThrowingContinuationReturning:
2641+
case BuiltinValueKind::ResumeThrowingContinuationReturning:
2642+
return getResumeContinuationReturning(Context, Id);
2643+
2644+
case BuiltinValueKind::ResumeThrowingContinuationThrowing:
2645+
return getResumeContinuationThrowing(Context, Id);
2646+
26242647
case BuiltinValueKind::WithUnsafeContinuation:
26252648
return getWithUnsafeContinuation(Context, Id, /*throws=*/false);
26262649

@@ -2692,6 +2715,9 @@ StringRef BuiltinType::getTypeName(SmallVectorImpl<char> &result,
26922715
case BuiltinTypeKind::BuiltinJob:
26932716
printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_JOB);
26942717
break;
2718+
case BuiltinTypeKind::BuiltinExecutor:
2719+
printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_EXECUTOR);
2720+
break;
26952721
case BuiltinTypeKind::BuiltinDefaultActorStorage:
26962722
printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_DEFAULTACTORSTORAGE);
26972723
break;

lib/AST/Type.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ bool CanType::isReferenceTypeImpl(CanType type, const GenericSignatureImpl *sig,
212212
case TypeKind::BuiltinRawPointer:
213213
case TypeKind::BuiltinRawUnsafeContinuation:
214214
case TypeKind::BuiltinJob:
215+
case TypeKind::BuiltinExecutor:
215216
case TypeKind::BuiltinDefaultActorStorage:
216217
case TypeKind::BuiltinUnsafeValueBuffer:
217218
case TypeKind::BuiltinVector:
@@ -5097,6 +5098,7 @@ ReferenceCounting TypeBase::getReferenceCounting() {
50975098
case TypeKind::BuiltinRawPointer:
50985099
case TypeKind::BuiltinRawUnsafeContinuation:
50995100
case TypeKind::BuiltinJob:
5101+
case TypeKind::BuiltinExecutor:
51005102
case TypeKind::BuiltinDefaultActorStorage:
51015103
case TypeKind::BuiltinUnsafeValueBuffer:
51025104
case TypeKind::BuiltinVector:

0 commit comments

Comments
 (0)