Skip to content

Commit b13c21c

Browse files
committed
Task Executors: Prepare for new TaskExecutor protocol & builtins
1 parent e19954f commit b13c21c

23 files changed

+260
-2
lines changed

include/swift/ABI/Executor.h

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ class AsyncTask;
2828
class DefaultActor;
2929
class Job;
3030
class SerialExecutorWitnessTable;
31+
class TaskExecutorWitnessTable;
3132

32-
/// An unmanaged reference to an executor.
33+
/// An unmanaged reference to an serial (!) executor.
3334
///
3435
/// This type corresponds to the type Optional<Builtin.Executor> in
3536
/// Swift. The representation of nil in Optional<Builtin.Executor>
@@ -182,6 +183,94 @@ class ExecutorRef {
182183
}
183184
};
184185

186+
class TaskExecutorRef {
187+
HeapObject *Identity; // Not necessarily Swift reference-countable
188+
uintptr_t Implementation;
189+
190+
// We future-proof the ABI here by masking the low bits off the
191+
// implementation pointer before using it as a witness table.
192+
//
193+
// We have 3 bits for future use remaining here.
194+
enum: uintptr_t {
195+
WitnessTableMask = ~uintptr_t(alignof(void*) - 1)
196+
};
197+
198+
/// The kind is stored in the free bits in the `Implementation` witness table reference.
199+
enum class TaskExecutorKind : uintptr_t {
200+
/// Ordinary executor.
201+
Ordinary = 0b00,
202+
};
203+
204+
static_assert(static_cast<uintptr_t>(TaskExecutorKind::Ordinary) == 0);
205+
206+
constexpr TaskExecutorRef(HeapObject *identity, uintptr_t implementation)
207+
: Identity(identity), Implementation(implementation) {}
208+
209+
public:
210+
211+
constexpr static TaskExecutorRef undefined() {
212+
return TaskExecutorRef(nullptr, 0);
213+
}
214+
215+
/// Given a pointer to a serial executor and its TaskExecutor
216+
/// conformance, return an executor reference for it.
217+
static TaskExecutorRef forOrdinary(HeapObject *identity,
218+
const SerialExecutorWitnessTable *witnessTable) {
219+
assert(identity);
220+
assert(witnessTable);
221+
auto wtable = reinterpret_cast<uintptr_t>(witnessTable) |
222+
static_cast<uintptr_t>(TaskExecutorKind::Ordinary);
223+
return TaskExecutorRef(identity, wtable);
224+
}
225+
226+
HeapObject *getIdentity() const {
227+
return Identity;
228+
}
229+
230+
/// Is this the generic executor reference?
231+
bool isUndefined() const {
232+
return Identity == 0;
233+
}
234+
235+
TaskExecutorKind getExecutorKind() const {
236+
return static_cast<TaskExecutorKind>(Implementation & ~WitnessTableMask);
237+
}
238+
239+
/// Is this an ordinary executor reference?
240+
/// These executor references are the default kind, and have no special treatment elsewhere in the system.
241+
bool isOrdinary() const {
242+
return getExecutorKind() == TaskExecutorKind::Ordinary;
243+
}
244+
245+
const SerialExecutorWitnessTable *getTaskExecutorWitnessTable() const {
246+
assert(!isUndefined());
247+
auto table = Implementation & WitnessTableMask;
248+
return reinterpret_cast<const SerialExecutorWitnessTable*>(table);
249+
}
250+
251+
// /// Do we have to do any work to start running as the requested
252+
// /// executor?
253+
// bool mustSwitchToRun(ExecutorRef newExecutor) const {
254+
// return Identity != newExecutor.Identity;
255+
// }
256+
257+
/// Get the raw value of the Implementation field, for tracing.
258+
uintptr_t getRawImplementation() const {
259+
return Implementation & WitnessTableMask;
260+
}
261+
262+
bool operator==(TaskExecutorRef other) const {
263+
return Identity == other.Identity;
264+
}
265+
bool operator!=(TaskExecutorRef other) const {
266+
return !(*this == other);
267+
}
268+
};
269+
270+
// Historically the 'ExecutorRef' was introduced initially, however it always has meant specifically
271+
// a SERIAL executor. This typedef fixes up this confusion and especially since now there is also a TaskExecutor.
272+
typedef ExecutorRef SerialExecutorRef;
273+
185274
using JobInvokeFunction =
186275
SWIFT_CC(swiftasync)
187276
void (Job *);

include/swift/AST/ASTSynthesis.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ enum SingletonTypeSynthesizer {
5050
_void,
5151
_word,
5252
_serialExecutor,
53+
_taskExecutor,
5354
};
5455
inline Type synthesizeType(SynthesisContext &SC,
5556
SingletonTypeSynthesizer kind) {
@@ -69,6 +70,9 @@ inline Type synthesizeType(SynthesisContext &SC,
6970
case _serialExecutor:
7071
return SC.Context.getProtocol(KnownProtocolKind::SerialExecutor)
7172
->getDeclaredInterfaceType();
73+
case _taskExecutor:
74+
return SC.Context.getProtocol(KnownProtocolKind::TaskExecutor)
75+
->getDeclaredInterfaceType();
7276
}
7377
}
7478

include/swift/AST/Builtins.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,11 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(AutoDiffAllocateSubcontextWithType, "autoDiff
10041004
BUILTIN_MISC_OPERATION_WITH_SILGEN(BuildOrdinarySerialExecutorRef,
10051005
"buildOrdinarySerialExecutorRef", "n", Special)
10061006

1007+
/// Build a Builtin.Executor value from an "ordinary" task executor
1008+
/// reference.
1009+
BUILTIN_MISC_OPERATION_WITH_SILGEN(BuildOrdinaryTaskExecutorRef,
1010+
"buildOrdinaryTaskExecutorRef", "n", Special)
1011+
10071012
/// Build a Builtin.Executor value from an "complex equality" serial executor
10081013
/// reference.
10091014
BUILTIN_MISC_OPERATION_WITH_SILGEN(BuildComplexEqualitySerialExecutorRef,

include/swift/AST/KnownProtocols.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ PROTOCOL(FixedWidthInteger)
8686
PROTOCOL(RangeReplaceableCollection)
8787
PROTOCOL(Executor)
8888
PROTOCOL(SerialExecutor)
89+
PROTOCOL(TaskExecutor)
8990
PROTOCOL(GlobalActor)
9091

9192
PROTOCOL_(BridgedNSError)

include/swift/AST/KnownSDKTypes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ KNOWN_SDK_TYPE_DECL(Concurrency, Job, StructDecl, 0) // TODO: remove in favor of
4444
KNOWN_SDK_TYPE_DECL(Concurrency, ExecutorJob, StructDecl, 0)
4545
KNOWN_SDK_TYPE_DECL(Concurrency, UnownedJob, StructDecl, 0)
4646
KNOWN_SDK_TYPE_DECL(Concurrency, Executor, NominalTypeDecl, 0)
47+
KNOWN_SDK_TYPE_DECL(Concurrency, TaskExecutor, NominalTypeDecl, 0)
4748
KNOWN_SDK_TYPE_DECL(Concurrency, SerialExecutor, NominalTypeDecl, 0)
4849
KNOWN_SDK_TYPE_DECL(Concurrency, UnownedSerialExecutor, NominalTypeDecl, 0)
4950

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ LANGUAGE_FEATURE(BuiltinTaskGroupWithArgument, 0, "TaskGroup builtins", true)
8383
LANGUAGE_FEATURE(InheritActorContext, 0, "@_inheritActorContext attribute", true)
8484
LANGUAGE_FEATURE(ImplicitSelfCapture, 0, "@_implicitSelfCapture attribute", true)
8585
LANGUAGE_FEATURE(BuiltinBuildExecutor, 0, "Executor-building builtins", true)
86+
LANGUAGE_FEATURE(BuiltinBuildTaskExecutor, 0, "TaskExecutor-building builtins", true)
8687
LANGUAGE_FEATURE(BuiltinBuildComplexEqualityExecutor, 0, "Executor-building for 'complexEquality executor' builtins", true)
8788
LANGUAGE_FEATURE(BuiltinBuildMainExecutor, 0, "MainActor executor building builtin", true)
8889
LANGUAGE_FEATURE(BuiltinCreateAsyncTaskInGroup, 0, "MainActor executor building builtin", true)

include/swift/Demangling/StandardTypesMangling.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ STANDARD_TYPE_CONCURRENCY(Protocol, F, Executor)
8888
STANDARD_TYPE_CONCURRENCY(Protocol, f, SerialExecutor)
8989
STANDARD_TYPE_CONCURRENCY(Structure, G, TaskGroup)
9090
STANDARD_TYPE_CONCURRENCY(Structure, g, ThrowingTaskGroup)
91+
STANDARD_TYPE_CONCURRENCY(Protocol, h, TaskExecutor)
9192
STANDARD_TYPE_CONCURRENCY(Protocol, I, AsyncIteratorProtocol)
9293
STANDARD_TYPE_CONCURRENCY(Protocol, i, AsyncSequence)
9394
STANDARD_TYPE_CONCURRENCY(Structure, J, UnownedJob)

lib/AST/ASTContext.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,6 +1140,7 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
11401140
case KnownProtocolKind::AsyncSequence:
11411141
case KnownProtocolKind::AsyncIteratorProtocol:
11421142
case KnownProtocolKind::Executor:
1143+
case KnownProtocolKind::TaskExecutor:
11431144
case KnownProtocolKind::SerialExecutor:
11441145
M = getLoadedModule(Id_Concurrency);
11451146
break;

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3086,6 +3086,10 @@ static bool usesFeatureBuiltinExecutor(Decl *decl) {
30863086
return usesBuiltinType(decl, BuiltinTypeKind::BuiltinExecutor);
30873087
}
30883088

3089+
static bool usesFeatureBuiltinBuildTaskExecutor(Decl *decl) {
3090+
return false;
3091+
}
3092+
30893093
static bool usesFeatureBuiltinBuildExecutor(Decl *decl) {
30903094
return false;
30913095
}

lib/AST/Builtins.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1610,6 +1610,16 @@ static ValueDecl *getTargetOSVersionAtLeast(ASTContext &Context,
16101610
return getBuiltinFunction(Id, {int32Type, int32Type, int32Type}, int32Type);
16111611
}
16121612

1613+
static ValueDecl *getBuildOrdinaryTaskExecutorRef(ASTContext &ctx,
1614+
Identifier id) {
1615+
return getBuiltinFunction(ctx, id, _thin,
1616+
_generics(_unrestricted,
1617+
_conformsTo(_typeparam(0), _taskExecutor)),
1618+
_parameters(_typeparam(0)),
1619+
_executor);
1620+
}
1621+
1622+
16131623
static ValueDecl *getBuildOrdinarySerialExecutorRef(ASTContext &ctx,
16141624
Identifier id) {
16151625
return getBuiltinFunction(ctx, id, _thin,
@@ -2919,6 +2929,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
29192929
case BuiltinValueKind::BuildComplexEqualitySerialExecutorRef:
29202930
return getBuildComplexEqualitySerialExecutorRef(Context, Id);
29212931

2932+
case BuiltinValueKind::BuildOrdinaryTaskExecutorRef:
2933+
return getBuildOrdinaryTaskExecutorRef(Context, Id);
2934+
29222935
case BuiltinValueKind::PoundAssert:
29232936
return getPoundAssert(Context, Id);
29242937

lib/IRGen/GenBuiltin.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,13 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
426426
emitBuildOrdinarySerialExecutorRef(IGF, actor, type, conf, out);
427427
return;
428428
}
429+
if (Builtin.ID == BuiltinValueKind::BuildOrdinaryTaskExecutorRef) {
430+
auto actor = args.claimNext();
431+
auto type = substitutions.getReplacementTypes()[0]->getCanonicalType();
432+
auto conf = substitutions.getConformances()[0];
433+
emitBuildOrdinaryTaskExecutorRef(IGF, actor, type, conf, out);
434+
return;
435+
}
429436
if (Builtin.ID == BuiltinValueKind::BuildComplexEqualitySerialExecutorRef) {
430437
auto actor = args.claimNext();
431438
auto type = substitutions.getReplacementTypes()[0]->getCanonicalType();

lib/IRGen/GenConcurrency.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,23 @@ void irgen::emitBuildOrdinarySerialExecutorRef(IRGenFunction &IGF,
174174
out.add(impl);
175175
}
176176

177+
void irgen::emitBuildOrdinaryTaskExecutorRef(IRGenFunction &IGF,
178+
llvm::Value *executor,
179+
CanType executorType,
180+
ProtocolConformanceRef executorConf,
181+
Explosion &out) {
182+
// The implementation word of an "ordinary" task executor is
183+
// just the witness table pointer with no flags set.
184+
llvm::Value *identity =
185+
IGF.Builder.CreatePtrToInt(executor, IGF.IGM.ExecutorFirstTy);
186+
llvm::Value *impl =
187+
emitWitnessTableRef(IGF, executorType, executorConf);
188+
impl = IGF.Builder.CreatePtrToInt(impl, IGF.IGM.ExecutorSecondTy);
189+
190+
out.add(identity);
191+
out.add(impl);
192+
}
193+
177194
void irgen::emitBuildComplexEqualitySerialExecutorRef(IRGenFunction &IGF,
178195
llvm::Value *executor,
179196
CanType executorType,

lib/IRGen/GenConcurrency.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ void emitBuildOrdinarySerialExecutorRef(IRGenFunction &IGF,
5454
ProtocolConformanceRef executorConformance,
5555
Explosion &out);
5656

57+
/// Emit the buildOrdinaryTaskExecutorRef builtin.
58+
void emitBuildOrdinaryTaskExecutorRef(IRGenFunction &IGF,
59+
llvm::Value *executor,
60+
CanType executorType,
61+
ProtocolConformanceRef executorConformance,
62+
Explosion &out);
63+
5764
/// Emit the buildComplexEqualitySerialExecutorRef builtin.
5865
void emitBuildComplexEqualitySerialExecutorRef(IRGenFunction &IGF,
5966
llvm::Value *executor,

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6561,6 +6561,7 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) {
65616561
case KnownProtocolKind::UnsafeCxxMutableRandomAccessIterator:
65626562
case KnownProtocolKind::Executor:
65636563
case KnownProtocolKind::SerialExecutor:
6564+
case KnownProtocolKind::TaskExecutor:
65646565
case KnownProtocolKind::Sendable:
65656566
case KnownProtocolKind::UnsafeSendable:
65666567
case KnownProtocolKind::RangeReplaceableCollection:

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,7 @@ BUILTIN_OPERAND_OWNERSHIP(PointerEscape, AutoDiffProjectTopLevelSubcontext)
959959
// ownership should be 'TrivialUse'.
960960
BUILTIN_OPERAND_OWNERSHIP(ForwardingConsume, ConvertTaskToJob)
961961

962+
BUILTIN_OPERAND_OWNERSHIP(BitwiseEscape, BuildOrdinaryTaskExecutorRef)
962963
BUILTIN_OPERAND_OWNERSHIP(BitwiseEscape, BuildOrdinarySerialExecutorRef)
963964
BUILTIN_OPERAND_OWNERSHIP(BitwiseEscape, BuildComplexEqualitySerialExecutorRef)
964965
BUILTIN_OPERAND_OWNERSHIP(BitwiseEscape, BuildDefaultActorExecutorRef)

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, GetCurrentExecutor)
581581
CONSTANT_OWNERSHIP_BUILTIN(None, ResumeNonThrowingContinuationReturning)
582582
CONSTANT_OWNERSHIP_BUILTIN(None, ResumeThrowingContinuationReturning)
583583
CONSTANT_OWNERSHIP_BUILTIN(None, ResumeThrowingContinuationThrowing)
584+
CONSTANT_OWNERSHIP_BUILTIN(None, BuildOrdinaryTaskExecutorRef)
584585
CONSTANT_OWNERSHIP_BUILTIN(None, BuildOrdinarySerialExecutorRef)
585586
CONSTANT_OWNERSHIP_BUILTIN(None, BuildComplexEqualitySerialExecutorRef)
586587
CONSTANT_OWNERSHIP_BUILTIN(None, BuildDefaultActorExecutorRef)

lib/SIL/Utils/InstructionUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,7 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType)
988988
return RuntimeEffect::RefCounting | RuntimeEffect::Deallocating;
989989
case BuiltinValueKind::Swift3ImplicitObjCEntrypoint:
990990
return RuntimeEffect::ObjectiveC | RuntimeEffect::Allocating;
991+
case BuiltinValueKind::BuildOrdinaryTaskExecutorRef:
991992
case BuiltinValueKind::BuildOrdinarySerialExecutorRef:
992993
case BuiltinValueKind::BuildComplexEqualitySerialExecutorRef:
993994
case BuiltinValueKind::BuildDefaultActorExecutorRef:

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2112,6 +2112,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
21122112
}
21132113

21142114
if (builtinKind == BuiltinValueKind::BuildOrdinarySerialExecutorRef ||
2115+
builtinKind == BuiltinValueKind::BuildOrdinaryTaskExecutorRef ||
21152116
builtinKind == BuiltinValueKind::BuildComplexEqualitySerialExecutorRef ||
21162117
builtinKind == BuiltinValueKind::BuildDefaultActorExecutorRef) {
21172118
require(arguments.size() == 1,

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1780,6 +1780,12 @@ static ManagedValue emitBuildExecutorRef(SILGenFunction &SGF, SILLocation loc,
17801780
subs, argValues);
17811781
return ManagedValue::forObjectRValueWithoutOwnership(builtinApply);
17821782
}
1783+
static ManagedValue emitBuiltinBuildOrdinaryTaskExecutorRef(
1784+
SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs,
1785+
ArrayRef<ManagedValue> args, SGFContext C) {
1786+
return emitBuildExecutorRef(SGF, loc, subs, args,
1787+
BuiltinValueKind::BuildOrdinaryTaskExecutorRef);
1788+
}
17831789
static ManagedValue emitBuiltinBuildOrdinarySerialExecutorRef(
17841790
SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs,
17851791
ArrayRef<ManagedValue> args, SGFContext C) {

lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ static bool isBarrier(SILInstruction *inst) {
191191
case BuiltinValueKind::DestroyDefaultActor:
192192
case BuiltinValueKind::InitializeDistributedRemoteActor:
193193
case BuiltinValueKind::InitializeNonDefaultDistributedActor:
194+
case BuiltinValueKind::BuildOrdinaryTaskExecutorRef:
194195
case BuiltinValueKind::BuildOrdinarySerialExecutorRef:
195196
case BuiltinValueKind::BuildComplexEqualitySerialExecutorRef:
196197
case BuiltinValueKind::BuildDefaultActorExecutorRef:

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1338,7 +1338,8 @@ void swift::tryDiagnoseExecutorConformance(ASTContext &C,
13381338
const NominalTypeDecl *nominal,
13391339
ProtocolDecl *proto) {
13401340
assert(proto->isSpecificProtocol(KnownProtocolKind::Executor) ||
1341-
proto->isSpecificProtocol(KnownProtocolKind::SerialExecutor));
1341+
proto->isSpecificProtocol(KnownProtocolKind::SerialExecutor) ||
1342+
proto->isSpecificProtocol(KnownProtocolKind::TaskExecutor));
13421343

13431344
auto &diags = C.Diags;
13441345
auto module = nominal->getParentModule();

0 commit comments

Comments
 (0)