Skip to content

Commit aca744b

Browse files
committed
Remove the Flags field from AsyncContext.
Generated code has never actually initialized this field, so we might as well remove it. Doing so mostly doesn't impact the ABI since we don't store anything for arguments or results in the context as part of the normal call sequence. We do need to adjust some of the hard-coded contexts, however, such as continuation contexts and the statically-sized context for special runtime async functions.
1 parent c9e3699 commit aca744b

File tree

12 files changed

+78
-134
lines changed

12 files changed

+78
-134
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2201,57 +2201,6 @@ class TaskOptionRecordFlags : public FlagSet<size_t> {
22012201
getKind, setKind)
22022202
};
22032203

2204-
/// Kinds of async context.
2205-
enum class AsyncContextKind {
2206-
/// An ordinary asynchronous function.
2207-
Ordinary = 0,
2208-
2209-
/// A context which can yield to its caller.
2210-
Yielding = 1,
2211-
2212-
/// A continuation context.
2213-
Continuation = 2,
2214-
2215-
// Other kinds are reserved for interesting special
2216-
// intermediate contexts.
2217-
2218-
// Kinds >= 192 are private to the implementation.
2219-
First_Reserved = 192
2220-
};
2221-
2222-
/// Flags for async contexts.
2223-
class AsyncContextFlags : public FlagSet<uint32_t> {
2224-
public:
2225-
enum {
2226-
Kind = 0,
2227-
Kind_width = 8,
2228-
2229-
CanThrow = 8,
2230-
2231-
// Kind-specific flags should grow down from 31.
2232-
2233-
Continuation_IsExecutorSwitchForced = 31,
2234-
};
2235-
2236-
explicit AsyncContextFlags(uint32_t bits) : FlagSet(bits) {}
2237-
constexpr AsyncContextFlags() {}
2238-
AsyncContextFlags(AsyncContextKind kind) {
2239-
setKind(kind);
2240-
}
2241-
2242-
/// The kind of context this represents.
2243-
FLAGSET_DEFINE_FIELD_ACCESSORS(Kind, Kind_width, AsyncContextKind,
2244-
getKind, setKind)
2245-
2246-
/// Whether this context is permitted to throw.
2247-
FLAGSET_DEFINE_FLAG_ACCESSORS(CanThrow, canThrow, setCanThrow)
2248-
2249-
/// See AsyncContinuationFlags::isExecutorSwitchForced.
2250-
FLAGSET_DEFINE_FLAG_ACCESSORS(Continuation_IsExecutorSwitchForced,
2251-
continuation_isExecutorSwitchForced,
2252-
continuation_setIsExecutorSwitchForced)
2253-
};
2254-
22552204
/// Flags passed to swift_continuation_init.
22562205
class AsyncContinuationFlags : public FlagSet<size_t> {
22572206
public:

include/swift/ABI/Task.h

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -631,19 +631,9 @@ class alignas(MaximumAlignment) AsyncContext {
631631
TaskContinuationFunction * __ptrauth_swift_async_context_resume
632632
ResumeParent;
633633

634-
/// Flags describing this context.
635-
///
636-
/// Note that this field is only 32 bits; any alignment padding
637-
/// following this on 64-bit platforms can be freely used by the
638-
/// function. If the function is a yielding function, that padding
639-
/// is of course interrupted by the YieldToParent field.
640-
AsyncContextFlags Flags;
641-
642-
AsyncContext(AsyncContextFlags flags,
643-
TaskContinuationFunction *resumeParent,
634+
AsyncContext(TaskContinuationFunction *resumeParent,
644635
AsyncContext *parent)
645-
: Parent(parent), ResumeParent(resumeParent),
646-
Flags(flags) {}
636+
: Parent(parent), ResumeParent(resumeParent) {}
647637

648638
AsyncContext(const AsyncContext &) = delete;
649639
AsyncContext &operator=(const AsyncContext &) = delete;
@@ -667,48 +657,66 @@ class YieldingAsyncContext : public AsyncContext {
667657
TaskContinuationFunction * __ptrauth_swift_async_context_yield
668658
YieldToParent;
669659

670-
YieldingAsyncContext(AsyncContextFlags flags,
671-
TaskContinuationFunction *resumeParent,
660+
YieldingAsyncContext(TaskContinuationFunction *resumeParent,
672661
TaskContinuationFunction *yieldToParent,
673662
AsyncContext *parent)
674-
: AsyncContext(flags, resumeParent, parent),
663+
: AsyncContext(resumeParent, parent),
675664
YieldToParent(yieldToParent) {}
676-
677-
static bool classof(const AsyncContext *context) {
678-
return context->Flags.getKind() == AsyncContextKind::Yielding;
679-
}
680665
};
681666

682667
/// An async context that can be resumed as a continuation.
683668
class ContinuationAsyncContext : public AsyncContext {
684669
public:
670+
class FlagsType : public FlagSet<size_t> {
671+
public:
672+
enum {
673+
CanThrow = 0,
674+
IsExecutorSwitchForced = 1,
675+
};
676+
677+
explicit FlagsType(size_t bits) : FlagSet(bits) {}
678+
constexpr FlagsType() {}
679+
680+
/// Whether this is a throwing continuation.
681+
FLAGSET_DEFINE_FLAG_ACCESSORS(CanThrow,
682+
canThrow,
683+
setCanThrow)
684+
685+
/// See AsyncContinuationFlags::isExecutorSwitchForced().
686+
FLAGSET_DEFINE_FLAG_ACCESSORS(IsExecutorSwitchForced,
687+
isExecutorSwitchForced,
688+
setIsExecutorSwitchForced)
689+
};
690+
691+
/// Flags for the continuation. Not public ABI.
692+
FlagsType Flags;
693+
685694
/// An atomic object used to ensure that a continuation is not
686695
/// scheduled immediately during a resume if it hasn't yet been
687-
/// awaited by the function which set it up.
696+
/// awaited by the function which set it up. Not public ABI.
688697
std::atomic<ContinuationStatus> AwaitSynchronization;
689698

690699
/// The error result value of the continuation.
691700
/// This should be null-initialized when setting up the continuation.
692701
/// Throwing resumers must overwrite this with a non-null value.
702+
/// Public ABI.
693703
SwiftError *ErrorResult;
694704

695705
/// A pointer to the normal result value of the continuation.
696706
/// Normal resumers must initialize this before resuming.
707+
/// Public ABI.
697708
OpaqueValue *NormalResult;
698709

699710
/// The executor that should be resumed to.
711+
/// Public ABI.
700712
ExecutorRef ResumeToExecutor;
701713

702714
void setErrorResult(SwiftError *error) {
703715
ErrorResult = error;
704716
}
705717

706718
bool isExecutorSwitchForced() const {
707-
return Flags.continuation_isExecutorSwitchForced();
708-
}
709-
710-
static bool classof(const AsyncContext *context) {
711-
return context->Flags.getKind() == AsyncContextKind::Continuation;
719+
return Flags.isExecutorSwitchForced();
712720
}
713721
};
714722

include/swift/Reflection/RuntimeInternals.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ template <typename Runtime>
131131
struct AsyncContext {
132132
typename Runtime::StoredSignedPointer Parent;
133133
typename Runtime::StoredSignedPointer ResumeParent;
134-
uint32_t Flags;
135134
};
136135

137136
template <typename Runtime>

lib/IRGen/GenCall.cpp

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ AsyncContextLayout irgen::getAsyncContextLayout(IRGenModule &IGM,
9393
}
9494

9595
static Size getAsyncContextHeaderSize(IRGenModule &IGM) {
96-
return 2 * IGM.getPointerSize() + Size(4);
96+
return 2 * IGM.getPointerSize();
9797
}
9898

9999
AsyncContextLayout irgen::getAsyncContextLayout(
@@ -123,19 +123,6 @@ AsyncContextLayout irgen::getAsyncContextLayout(
123123
typeInfos.push_back(&ti);
124124
}
125125

126-
// AsyncContextFlags Flags;
127-
// FIXME: this appears to be dead; we should adjust the layout of
128-
// the special async contexts that assume its existence and then
129-
// remove it.
130-
{
131-
auto ty = SILType::getPrimitiveObjectType(
132-
BuiltinIntegerType::get(32, IGM.IRGen.SIL.getASTContext())
133-
->getCanonicalType());
134-
const auto &ti = IGM.getTypeInfo(ty);
135-
valTypes.push_back(ty);
136-
typeInfos.push_back(&ti);
137-
}
138-
139126
return AsyncContextLayout(IGM, LayoutStrategy::Optimal, valTypes, typeInfos,
140127
originalType, substitutedType, substitutionMap);
141128
}
@@ -181,11 +168,7 @@ FunctionPointerKind::getStaticAsyncContextSize(IRGenModule &IGM) const {
181168
// If you add a new special runtime function, it is highly recommended
182169
// that you make calls to it allocate a little more memory than this!
183170
// These frames being this small is very arguably a mistake.
184-
//
185-
// FIXME: if we remove Flags in AsyncContextLayout (and thus from
186-
// headerSize), account for it here so that we continue to pass the
187-
// right amount of memory.
188-
return headerSize + 2 * IGM.getPointerSize();
171+
return headerSize + 3 * IGM.getPointerSize();
189172
}
190173
llvm_unreachable("covered switch");
191174
}

lib/IRGen/IRGenFunction.cpp

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,13 @@ static Address emitAddrOfContinuationNormalResultPointer(IRGenFunction &IGF,
575575
Address context) {
576576
assert(context.getType() == IGF.IGM.ContinuationAsyncContextPtrTy);
577577
auto offset = 5 * IGF.IGM.getPointerSize();
578+
return IGF.Builder.CreateStructGEP(context, 4, offset);
579+
}
580+
581+
static Address emitAddrOfContinuationErrorResultPointer(IRGenFunction &IGF,
582+
Address context) {
583+
assert(context.getType() == IGF.IGM.ContinuationAsyncContextPtrTy);
584+
auto offset = 4 * IGF.IGM.getPointerSize();
578585
return IGF.Builder.CreateStructGEP(context, 3, offset);
579586
}
580587

@@ -693,7 +700,8 @@ void IRGenFunction::emitAwaitAsyncContinuation(
693700
Explosion &outDirectResult, llvm::BasicBlock *&normalBB,
694701
llvm::PHINode *&optionalErrorResult, llvm::BasicBlock *&optionalErrorBB) {
695702
assert(AsyncCoroutineCurrentContinuationContext && "no active continuation");
696-
auto pointerAlignment = IGM.getPointerAlignment();
703+
Address continuationContext(AsyncCoroutineCurrentContinuationContext,
704+
IGM.getAsyncContextAlignment());
697705

698706
// Call swift_continuation_await to check whether the continuation
699707
// has already been resumed.
@@ -703,11 +711,9 @@ void IRGenFunction::emitAwaitAsyncContinuation(
703711
// swift_continuation_await, emit the old inline sequence. This can
704712
// be removed as soon as we're sure that such SDKs don't exist.
705713
if (!useContinuationAwait) {
706-
auto contAwaitSyncAddr = Builder.CreateStructGEP(
707-
AsyncCoroutineCurrentContinuationContext->getType()
708-
->getScalarType()
709-
->getPointerElementType(),
710-
AsyncCoroutineCurrentContinuationContext, 1);
714+
auto contAwaitSyncAddr =
715+
Builder.CreateStructGEP(continuationContext, 2,
716+
3 * IGM.getPointerSize()).getAddress();
711717

712718
auto pendingV = llvm::ConstantInt::get(
713719
contAwaitSyncAddr->getType()->getPointerElementType(),
@@ -759,11 +765,11 @@ void IRGenFunction::emitAwaitAsyncContinuation(
759765
Builder.CreateBitOrPointerCast(awaitFnPtr, IGM.Int8PtrTy));
760766

761767
if (useContinuationAwait) {
762-
arguments.push_back(AsyncCoroutineCurrentContinuationContext);
768+
arguments.push_back(continuationContext.getAddress());
763769
} else {
764770
arguments.push_back(AsyncCoroutineCurrentResume);
765771
arguments.push_back(Builder.CreateBitOrPointerCast(
766-
AsyncCoroutineCurrentContinuationContext, IGM.Int8PtrTy));
772+
continuationContext.getAddress(), IGM.Int8PtrTy));
767773
}
768774

769775
auto resultTy =
@@ -777,12 +783,7 @@ void IRGenFunction::emitAwaitAsyncContinuation(
777783
if (optionalErrorBB) {
778784
auto normalContBB = createBasicBlock("await.async.normal");
779785
auto contErrResultAddr =
780-
Address(Builder.CreateStructGEP(
781-
AsyncCoroutineCurrentContinuationContext->getType()
782-
->getScalarType()
783-
->getPointerElementType(),
784-
AsyncCoroutineCurrentContinuationContext, 2),
785-
pointerAlignment);
786+
emitAddrOfContinuationErrorResultPointer(*this, continuationContext);
786787
auto errorRes = Builder.CreateLoad(contErrResultAddr);
787788
auto nullError = llvm::Constant::getNullValue(errorRes->getType());
788789
auto hasError = Builder.CreateICmpNE(errorRes, nullError);
@@ -795,13 +796,10 @@ void IRGenFunction::emitAwaitAsyncContinuation(
795796
// result slot, load from the temporary we created during
796797
// get_async_continuation.
797798
if (!isIndirectResult) {
798-
auto contResultAddrAddr = Builder.CreateStructGEP(
799-
AsyncCoroutineCurrentContinuationContext->getType()
800-
->getScalarType()
801-
->getPointerElementType(),
802-
AsyncCoroutineCurrentContinuationContext, 3);
799+
auto contResultAddrAddr =
800+
emitAddrOfContinuationNormalResultPointer(*this, continuationContext);
803801
auto resultAddrVal =
804-
Builder.CreateLoad(Address(contResultAddrAddr, pointerAlignment));
802+
Builder.CreateLoad(contResultAddrAddr);
805803
// Take the result.
806804
auto &resumeTI = cast<LoadableTypeInfo>(getTypeInfo(resumeTy));
807805
auto resultStorageTy = resumeTI.getStorageType();

lib/IRGen/IRGenModule.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -662,9 +662,8 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
662662
TaskContinuationFunctionPtrTy = TaskContinuationFunctionTy->getPointerTo();
663663

664664
SwiftContextTy->setBody({
665-
SwiftContextPtrTy, // Parent
666-
TaskContinuationFunctionPtrTy, // ResumeParent,
667-
SizeTy, // Flags
665+
SwiftContextPtrTy, // Parent
666+
TaskContinuationFunctionPtrTy, // ResumeParent
668667
});
669668

670669
AsyncTaskAndContextTy = createStructType(
@@ -674,6 +673,7 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
674673
ContinuationAsyncContextTy = createStructType(
675674
*this, "swift.continuation_context",
676675
{SwiftContextTy, // AsyncContext header
676+
SizeTy, // flags
677677
SizeTy, // await synchronization
678678
ErrorPtrTy, // error result pointer
679679
OpaquePtrTy, // normal result address

stdlib/public/Concurrency/Task.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ void NullaryContinuationJob::process(Job *_job) {
165165

166166
_swift_task_dealloc_specific(task, job);
167167

168-
auto *context = cast<ContinuationAsyncContext>(continuation->ResumeContext);
168+
auto *context =
169+
static_cast<ContinuationAsyncContext*>(continuation->ResumeContext);
169170

170171
context->setErrorResult(nullptr);
171172
swift_continuation_resume(continuation);
@@ -825,7 +826,6 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
825826
// as if they might be null, even though the only time they ever might
826827
// be is the final hop. Store a signed null instead.
827828
initialContext->Parent = nullptr;
828-
initialContext->Flags = AsyncContextKind::Ordinary;
829829

830830
concurrency::trace::task_create(task, parent, group, asyncLet);
831831

@@ -1026,13 +1026,13 @@ swift_task_enqueueTaskOnExecutorImpl(AsyncTask *task, ExecutorRef executor)
10261026
SWIFT_CC(swift)
10271027
static AsyncTask *swift_continuation_initImpl(ContinuationAsyncContext *context,
10281028
AsyncContinuationFlags flags) {
1029-
context->Flags = AsyncContextKind::Continuation;
1029+
context->Flags = ContinuationAsyncContext::FlagsType();
10301030
if (flags.canThrow()) context->Flags.setCanThrow(true);
10311031
if (flags.isExecutorSwitchForced())
1032-
context->Flags.continuation_setIsExecutorSwitchForced(true);
1032+
context->Flags.setIsExecutorSwitchForced(true);
10331033
context->ErrorResult = nullptr;
10341034

1035-
// Set the current executor as the target executor unless there's
1035+
// Set the generic executor as the target executor unless there's
10361036
// an executor override.
10371037
if (!flags.hasExecutorOverride())
10381038
context->ResumeToExecutor = ExecutorRef::generic();
@@ -1156,21 +1156,21 @@ static void resumeTaskAfterContinuation(AsyncTask *task,
11561156

11571157
SWIFT_CC(swift)
11581158
static void swift_continuation_resumeImpl(AsyncTask *task) {
1159-
auto context = cast<ContinuationAsyncContext>(task->ResumeContext);
1159+
auto context = static_cast<ContinuationAsyncContext*>(task->ResumeContext);
11601160
resumeTaskAfterContinuation(task, context);
11611161
}
11621162

11631163
SWIFT_CC(swift)
11641164
static void swift_continuation_throwingResumeImpl(AsyncTask *task) {
1165-
auto context = cast<ContinuationAsyncContext>(task->ResumeContext);
1165+
auto context = static_cast<ContinuationAsyncContext*>(task->ResumeContext);
11661166
resumeTaskAfterContinuation(task, context);
11671167
}
11681168

11691169

11701170
SWIFT_CC(swift)
11711171
static void swift_continuation_throwingResumeWithErrorImpl(AsyncTask *task,
11721172
/* +1 */ SwiftError *error) {
1173-
auto context = cast<ContinuationAsyncContext>(task->ResumeContext);
1173+
auto context = static_cast<ContinuationAsyncContext*>(task->ResumeContext);
11741174
context->ErrorResult = error;
11751175
resumeTaskAfterContinuation(task, context);
11761176
}

stdlib/public/Concurrency/TaskPrivate.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,16 @@ namespace {
145145
///
146146
class TaskFutureWaitAsyncContext : public AsyncContext {
147147
public:
148+
// The ABI reserves three words of storage for these contexts, which
149+
// we currently use as follows. These fields are not accessed by
150+
// generated code; they're purely internal to the runtime, and only
151+
// when the calling task actually suspends.
152+
//
153+
// (If you think three words is an odd choice, one of them used to be
154+
// the context flags.)
148155
SwiftError *errorResult;
149-
150156
OpaqueValue *successResultPointer;
157+
void *_reserved;
151158

152159
void fillWithSuccess(AsyncTask::FutureFragment *future) {
153160
fillWithSuccess(future->getStoragePtr(), future->getResultType(),

0 commit comments

Comments
 (0)