Skip to content

Commit 186c530

Browse files
committed
Introduce basic support for custom executors.
- Introduce an UnownedSerialExecutor type into the concurrency library. - Create a SerialExecutor protocol which allows an executor type to change how it executes jobs. - Add an unownedExecutor requirement to the Actor protocol. - Change the ABI for ExecutorRef so that it stores a SerialExecutor witness table pointer in the implementation field. This effectively makes ExecutorRef an `unowned(unsafe) SerialExecutor`, except that default actors are represented without a witness table pointer (just a bit-pattern). - Synthesize the unownedExecutor method for default actors (i.e. actors that don't provide an unownedExecutor property). - Make synthesized unownedExecutor properties `final`, and give them a semantics attribute specifying that they're for default actors. - Split `Builtin.buildSerialExecutorRef` into a few more precise builtins. We're not using the main-actor one yet, though. Pitch thread: https://forums.swift.org/t/support-custom-executors-in-swift-concurrency/44425
1 parent 769c2e7 commit 186c530

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+851
-205
lines changed

include/swift/ABI/Executor.h

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class AsyncContext;
2727
class AsyncTask;
2828
class DefaultActor;
2929
class Job;
30+
class SerialExecutorWitnessTable;
3031

3132
/// FIXME: only exists for the quick-and-dirty MainActor implementation.
3233
SWIFT_EXPORT_FROM(swift_Concurrency)
@@ -46,6 +47,10 @@ class ExecutorRef {
4647
HeapObject *Identity; // Not necessarily Swift reference-countable
4748
uintptr_t Implementation;
4849

50+
enum: uintptr_t {
51+
WitnessTableMask = ~uintptr_t(alignof(void*) - 1)
52+
};
53+
4954
constexpr ExecutorRef(HeapObject *identity, uintptr_t implementation)
5055
: Identity(identity), Implementation(implementation) {}
5156

@@ -58,18 +63,6 @@ class ExecutorRef {
5863
return ExecutorRef(nullptr, 0);
5964
}
6065

61-
/// FIXME: only exists for the quick-and-dirty MainActor implementation.
62-
/// NOTE: I didn't go with Executor::forMainActor(DefaultActor*) because
63-
/// __swift_run_job_main_executor can't take more than one argument.
64-
static ExecutorRef mainExecutor() {
65-
auto identity = getMainActorIdentity();
66-
return ExecutorRef(identity, 0);
67-
}
68-
static HeapObject *getMainActorIdentity() {
69-
return reinterpret_cast<HeapObject*>(
70-
ExecutorRefFlags::MainActorIdentity);
71-
}
72-
7366
/// Given a pointer to a default actor, return an executor reference
7467
/// for it.
7568
static ExecutorRef forDefaultActor(DefaultActor *actor) {
@@ -86,18 +79,6 @@ class ExecutorRef {
8679
return Identity == 0;
8780
}
8881

89-
/// FIXME: only exists for the quick-and-dirty MainActor implementation.
90-
bool isMainExecutor() const {
91-
if (Identity == getMainActorIdentity())
92-
return true;
93-
94-
if (Identity == nullptr || MainActorMetadata == nullptr)
95-
return false;
96-
97-
Metadata const* metadata = swift_getObjectType(Identity);
98-
return metadata == MainActorMetadata;
99-
}
100-
10182
/// Is this a default-actor executor reference?
10283
bool isDefaultActor() const {
10384
return Implementation & unsigned(ExecutorRefFlags::DefaultActor);
@@ -107,16 +88,20 @@ class ExecutorRef {
10788
return reinterpret_cast<DefaultActor*>(Identity);
10889
}
10990

91+
const SerialExecutorWitnessTable *getSerialExecutorWitnessTable() const {
92+
assert(!isGeneric() && !isDefaultActor());
93+
auto table = Implementation & WitnessTableMask;
94+
return reinterpret_cast<const SerialExecutorWitnessTable*>(table);
95+
}
96+
11097
/// Do we have to do any work to start running as the requested
11198
/// executor?
11299
bool mustSwitchToRun(ExecutorRef newExecutor) const {
113100
return Identity != newExecutor.Identity;
114101
}
115102

116103
bool operator==(ExecutorRef other) const {
117-
return Identity == other.Identity
118-
/// FIXME: only exists for the quick-and-dirty MainActor implementation.
119-
|| (isMainExecutor() && other.isMainExecutor());
104+
return Identity == other.Identity;
120105
}
121106
bool operator!=(ExecutorRef other) const {
122107
return !(*this == other);

include/swift/ABI/MetadataValues.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2195,10 +2195,7 @@ enum class ExecutorRefFlags : size_t {
21952195
// pointer
21962196

21972197
/// The executor is a default actor.
2198-
DefaultActor = 0x1,
2199-
2200-
/// TODO: remove this
2201-
MainActorIdentity = 0x2,
2198+
DefaultActor = 0x1
22022199
};
22032200

22042201
} // end namespace swift

include/swift/AST/ASTSynthesis.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ enum SingletonTypeSynthesizer {
4949
_rawUnsafeContinuation,
5050
_void,
5151
_word,
52+
_serialExecutor,
5253
};
5354
inline Type synthesizeType(SynthesisContext &SC,
5455
SingletonTypeSynthesizer kind) {
@@ -65,6 +66,9 @@ inline Type synthesizeType(SynthesisContext &SC,
6566
case _void: return SC.Context.TheEmptyTupleType;
6667
case _word: return BuiltinIntegerType::get(BuiltinIntegerWidth::pointer(),
6768
SC.Context);
69+
case _serialExecutor:
70+
return SC.Context.getProtocol(KnownProtocolKind::SerialExecutor)
71+
->getDeclaredInterfaceType();
6872
}
6973
}
7074

include/swift/AST/Builtins.def

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -736,10 +736,6 @@ BUILTIN_MISC_OPERATION(ResumeThrowingContinuationReturning,
736736
BUILTIN_MISC_OPERATION(ResumeThrowingContinuationThrowing,
737737
"resumeThrowingContinuationThrowing", "", Special)
738738

739-
/// Build a Builtin.Executor value from the given serial executor reference.
740-
BUILTIN_MISC_OPERATION(BuildSerialExecutorRef,
741-
"buildSerialExecutorRef", "", Special)
742-
743739
/// Create a task group.
744740
BUILTIN_MISC_OPERATION(CreateTaskGroup,
745741
"createTaskGroup", "", Special)
@@ -835,6 +831,19 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(AutoDiffProjectTopLevelSubcontext, "autoDiffP
835831
// autoDiffAllocateSubcontext: (Builtin.NativeObject, Builtin.Word) -> Builtin.RawPointer
836832
BUILTIN_MISC_OPERATION_WITH_SILGEN(AutoDiffAllocateSubcontext, "autoDiffAllocateSubcontext", "", Special)
837833

834+
/// Build a Builtin.Executor value from an "ordinary" serial executor
835+
/// reference.
836+
BUILTIN_MISC_OPERATION_WITH_SILGEN(BuildOrdinarySerialExecutorRef,
837+
"buildOrdinarySerialExecutorRef", "n", Special)
838+
839+
/// Build a Builtin.Executor value from a default actor reference.
840+
BUILTIN_MISC_OPERATION_WITH_SILGEN(BuildDefaultActorExecutorRef,
841+
"buildDefaultActorExecutorRef", "n", Special)
842+
843+
/// Build a Builtin.Executor value for the main actor.
844+
BUILTIN_MISC_OPERATION_WITH_SILGEN(BuildMainActorExecutorRef,
845+
"buildMainActorExecutorRef", "n", Special)
846+
838847
#undef BUILTIN_MISC_OPERATION_WITH_SILGEN
839848

840849
#undef BUILTIN_MISC_OPERATION

include/swift/AST/Decl.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3778,9 +3778,8 @@ class ClassDecl final : public NominalTypeDecl {
37783778
/// Get the closest-to-root superclass that's an actor class.
37793779
const ClassDecl *getRootActorClass() const;
37803780

3781-
/// Does this class explicitly declare any of the methods that
3782-
/// would prevent it from being a default actor?
3783-
bool hasExplicitCustomActorMethods() const;
3781+
/// Fetch this class's unownedExecutor property, if it has one.
3782+
const VarDecl *getUnownedExecutorProperty() const;
37843783

37853784
/// Is this the NSObject class type?
37863785
bool isNSObject() const;
@@ -4006,6 +4005,7 @@ enum class KnownDerivableProtocolKind : uint8_t {
40064005
Decodable,
40074006
AdditiveArithmetic,
40084007
Differentiable,
4008+
Actor,
40094009
};
40104010

40114011
/// ProtocolDecl - A declaration of a protocol, for example:

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4354,6 +4354,13 @@ ERROR(async_objc_dynamic_self,none,
43544354
ERROR(actor_inheritance,none,
43554355
"actor types do not support inheritance", ())
43564356

4357+
ERROR(unowned_executor_outside_actor,none,
4358+
"'unownedExecutor' can only be implemented within the main "
4359+
"definition of an actor", ())
4360+
ERROR(override_implicit_unowned_executor,none,
4361+
"cannot override an actor's 'unownedExecutor' property that wasn't "
4362+
"explicitly defined", ())
4363+
43574364
ERROR(actor_isolated_non_self_reference,none,
43584365
"actor-isolated %0 %1 can only be %select{referenced|mutated|used 'inout'}3 "
43594366
"%select{from inside the actor|on 'self'}2",

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ IDENTIFIER(className)
218218

219219
IDENTIFIER(_defaultActorInitialize)
220220
IDENTIFIER(_defaultActorDestroy)
221+
IDENTIFIER(unownedExecutor)
221222

222223
IDENTIFIER_(ErrorType)
223224
IDENTIFIER(Code)

include/swift/AST/KnownProtocols.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ PROTOCOL(CaseIterable)
7272
PROTOCOL(SIMDScalar)
7373
PROTOCOL(BinaryInteger)
7474
PROTOCOL(RangeReplaceableCollection)
75+
PROTOCOL(SerialExecutor)
7576

7677
PROTOCOL_(BridgedNSError)
7778
PROTOCOL_(BridgedStoredNSError)

include/swift/AST/KnownSDKTypes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ KNOWN_SDK_TYPE_DECL(ObjectiveC, ObjCBool, StructDecl, 0)
3939
// standardized
4040
KNOWN_SDK_TYPE_DECL(Concurrency, UnsafeContinuation, NominalTypeDecl, 2)
4141
KNOWN_SDK_TYPE_DECL(Concurrency, MainActor, NominalTypeDecl, 0)
42+
KNOWN_SDK_TYPE_DECL(Concurrency, UnownedSerialExecutor, NominalTypeDecl, 0)
4243

4344
KNOWN_SDK_TYPE_DECL(Concurrency, TaskLocal, ClassDecl, 1)
4445

include/swift/Basic/Features.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ LANGUAGE_FEATURE(RethrowsProtocol, 0, "@rethrows protocol", true)
4343
LANGUAGE_FEATURE(GlobalActors, 0, "Global actors", langOpts.EnableExperimentalConcurrency)
4444
LANGUAGE_FEATURE(BuiltinJob, 0, "Builtin.Job type", true)
4545
LANGUAGE_FEATURE(Sendable, 0, "Sendable and @Sendable", true)
46-
LANGUAGE_FEATURE(BuiltinExecutor, 0, "Executor builtins", true)
46+
LANGUAGE_FEATURE(BuiltinExecutor, 0, "Builtin.Executor type", true)
4747
LANGUAGE_FEATURE(BuiltinContinuation, 0, "Continuation builtins", true)
4848
LANGUAGE_FEATURE(BuiltinTaskGroup, 0, "TaskGroup builtins", true)
4949
LANGUAGE_FEATURE(InheritActorContext, 0, "@_inheritActorContext attribute", true)
50+
LANGUAGE_FEATURE(BuiltinBuildExecutor, 0, "Executor-building builtins", true)
5051

5152
#undef LANGUAGE_FEATURE

0 commit comments

Comments
 (0)