mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Use &_dispatch_main_q as the identity of the main actor.
I added Builtin.buildMainActorExecutor before, but because I never implemented it correctly in IRGen, it's not okay to use it on old versions, so I had to introduce a new feature only for it. The shim dispatch queue class in the Concurrency runtime is rather awful, but I couldn't think of a reasonable alternative without just entirely hard-coding the witness table in the runtime. It's not ABI, at least.
This commit is contained in:
@@ -82,6 +82,15 @@ public:
|
|||||||
return ExecutorRef(actor, 0);
|
return ExecutorRef(actor, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given a pointer to a serial executor and its SerialExecutor
|
||||||
|
/// conformance, return an executor reference for it.
|
||||||
|
static ExecutorRef forOrdinary(HeapObject *identity,
|
||||||
|
const SerialExecutorWitnessTable *witnessTable) {
|
||||||
|
assert(identity);
|
||||||
|
assert(witnessTable);
|
||||||
|
return ExecutorRef(identity, reinterpret_cast<uintptr_t>(witnessTable));
|
||||||
|
}
|
||||||
|
|
||||||
HeapObject *getIdentity() const {
|
HeapObject *getIdentity() const {
|
||||||
return Identity;
|
return Identity;
|
||||||
}
|
}
|
||||||
@@ -112,6 +121,9 @@ public:
|
|||||||
return Identity != newExecutor.Identity;
|
return Identity != newExecutor.Identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is this executor the main executor?
|
||||||
|
bool isMainExecutor() const;
|
||||||
|
|
||||||
bool operator==(ExecutorRef other) const {
|
bool operator==(ExecutorRef other) const {
|
||||||
return Identity == other.Identity;
|
return Identity == other.Identity;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,4 +137,29 @@
|
|||||||
#define SWIFT_POINTER_IS_4_BYTES 1
|
#define SWIFT_POINTER_IS_4_BYTES 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Produce a string literal for the raw argument tokens.
|
||||||
|
#define SWIFT_STRINGIZE_RAW(TOK) #TOK
|
||||||
|
|
||||||
|
// Produce a string literal for the macro-expanded argument tokens.
|
||||||
|
#define SWIFT_STRINGIZE_EXPANDED(TOK) SWIFT_STRINGIZE_RAW(TOK)
|
||||||
|
|
||||||
|
#if defined(__USER_LABEL_PREFIX__)
|
||||||
|
#define SWIFT_SYMBOL_PREFIX_STRING \
|
||||||
|
SWIFT_STRINGIZE_EXPANDED(__USER_LABEL_PREFIX__)
|
||||||
|
#else
|
||||||
|
// Clang and GCC always define __USER_LABEL_PREFIX__, so this should
|
||||||
|
// only come up with MSVC, and Windows doesn't use a prefix.
|
||||||
|
#define SWIFT_SYMBOL_PREFIX_STRING ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// An attribute to override the symbol name of a declaration.
|
||||||
|
// This does not compensate for platform symbol prefixes; for that,
|
||||||
|
// use SWIFT_ASM_LABEL_WITH_PREFIX.
|
||||||
|
//
|
||||||
|
// This only actually works on Clang or GCC; MSVC does not provide
|
||||||
|
// an attribute to change the asm label.
|
||||||
|
#define SWIFT_ASM_LABEL_RAW(STRING) __asm__(STRING)
|
||||||
|
#define SWIFT_ASM_LABEL_WITH_PREFIX(STRING) \
|
||||||
|
SWIFT_ASM_LABEL_RAW(SWIFT_SYMBOL_PREFIX_STRING STRING)
|
||||||
|
|
||||||
#endif // SWIFT_BASIC_COMPILER_H
|
#endif // SWIFT_BASIC_COMPILER_H
|
||||||
|
|||||||
@@ -51,5 +51,6 @@ LANGUAGE_FEATURE(BuiltinTaskGroup, 0, "TaskGroup builtins", true)
|
|||||||
LANGUAGE_FEATURE(InheritActorContext, 0, "@_inheritActorContext attribute", true)
|
LANGUAGE_FEATURE(InheritActorContext, 0, "@_inheritActorContext attribute", true)
|
||||||
LANGUAGE_FEATURE(ImplicitSelfCapture, 0, "@_implicitSelfCapture attribute", true)
|
LANGUAGE_FEATURE(ImplicitSelfCapture, 0, "@_implicitSelfCapture attribute", true)
|
||||||
LANGUAGE_FEATURE(BuiltinBuildExecutor, 0, "Executor-building builtins", true)
|
LANGUAGE_FEATURE(BuiltinBuildExecutor, 0, "Executor-building builtins", true)
|
||||||
|
LANGUAGE_FEATURE(BuiltinBuildMainExecutor, 0, "MainActor executor building builtin", true)
|
||||||
|
|
||||||
#undef LANGUAGE_FEATURE
|
#undef LANGUAGE_FEATURE
|
||||||
|
|||||||
@@ -563,6 +563,10 @@ void swift_task_enqueueGlobalWithDelay(unsigned long long delay, Job *job);
|
|||||||
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
|
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
|
||||||
void swift_task_enqueueMainExecutor(Job *job);
|
void swift_task_enqueueMainExecutor(Job *job);
|
||||||
|
|
||||||
|
/// Enqueue the given job on the main executor.
|
||||||
|
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
|
||||||
|
void swift_task_enqueueOnDispatchQueue(Job *job, HeapObject *queue);
|
||||||
|
|
||||||
/// A hook to take over global enqueuing.
|
/// A hook to take over global enqueuing.
|
||||||
typedef SWIFT_CC(swift) void (*swift_task_enqueueGlobal_original)(Job *job);
|
typedef SWIFT_CC(swift) void (*swift_task_enqueueGlobal_original)(Job *job);
|
||||||
SWIFT_EXPORT_FROM(swift_Concurrency)
|
SWIFT_EXPORT_FROM(swift_Concurrency)
|
||||||
@@ -680,6 +684,10 @@ AsyncTask *swift_task_getCurrent(void);
|
|||||||
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
|
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
|
||||||
ExecutorRef swift_task_getCurrentExecutor(void);
|
ExecutorRef swift_task_getCurrentExecutor(void);
|
||||||
|
|
||||||
|
/// Return the main-actor executor reference.
|
||||||
|
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
|
||||||
|
ExecutorRef swift_task_getMainExecutor(void);
|
||||||
|
|
||||||
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
|
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
|
||||||
bool swift_task_isCurrentExecutor(ExecutorRef executor);
|
bool swift_task_isCurrentExecutor(ExecutorRef executor);
|
||||||
|
|
||||||
|
|||||||
@@ -1666,6 +1666,14 @@ FUNCTION(TaskGetCurrentExecutor,
|
|||||||
ARGS(),
|
ARGS(),
|
||||||
ATTRS(NoUnwind, ArgMemOnly))
|
ATTRS(NoUnwind, ArgMemOnly))
|
||||||
|
|
||||||
|
// ExecutorRef swift_task_getMainExecutor();
|
||||||
|
FUNCTION(TaskGetMainExecutor,
|
||||||
|
swift_task_getMainExecutor, SwiftCC,
|
||||||
|
ConcurrencyAvailability,
|
||||||
|
RETURNS(SwiftExecutorTy),
|
||||||
|
ARGS(),
|
||||||
|
ATTRS(NoUnwind, ArgMemOnly))
|
||||||
|
|
||||||
// void swift_defaultActor_initialize(DefaultActor *actor);
|
// void swift_defaultActor_initialize(DefaultActor *actor);
|
||||||
FUNCTION(DefaultActorInitialize,
|
FUNCTION(DefaultActorInitialize,
|
||||||
swift_defaultActor_initialize, SwiftCC,
|
swift_defaultActor_initialize, SwiftCC,
|
||||||
|
|||||||
@@ -2768,6 +2768,10 @@ static bool usesFeatureBuiltinBuildExecutor(Decl *decl) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool usesFeatureBuiltinBuildMainExecutor(Decl *decl) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool usesFeatureBuiltinContinuation(Decl *decl) {
|
static bool usesFeatureBuiltinContinuation(Decl *decl) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,7 +127,12 @@ const LoadableTypeInfo &TypeConverter::getExecutorTypeInfo() {
|
|||||||
|
|
||||||
void irgen::emitBuildMainActorExecutorRef(IRGenFunction &IGF,
|
void irgen::emitBuildMainActorExecutorRef(IRGenFunction &IGF,
|
||||||
Explosion &out) {
|
Explosion &out) {
|
||||||
// FIXME
|
auto call = IGF.Builder.CreateCall(IGF.IGM.getTaskGetMainExecutorFn(),
|
||||||
|
{});
|
||||||
|
call->setDoesNotThrow();
|
||||||
|
call->setCallingConv(IGF.IGM.SwiftCC);
|
||||||
|
|
||||||
|
IGF.emitAllExtractValues(call, IGF.IGM.SwiftExecutorTy, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void irgen::emitBuildDefaultActorExecutorRef(IRGenFunction &IGF,
|
void irgen::emitBuildDefaultActorExecutorRef(IRGenFunction &IGF,
|
||||||
|
|||||||
@@ -321,8 +321,7 @@ static bool swift_task_isCurrentExecutorImpl(ExecutorRef executor) {
|
|||||||
return currentTracking->getActiveExecutor() == executor;
|
return currentTracking->getActiveExecutor() == executor;
|
||||||
}
|
}
|
||||||
|
|
||||||
return executor == _swift_task_getMainExecutor()
|
return executor.isMainExecutor() && isExecutingOnMainThread();
|
||||||
&& isExecutingOnMainThread();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Logging level for unexpected executors:
|
/// Logging level for unexpected executors:
|
||||||
@@ -365,7 +364,7 @@ void swift::swift_task_reportUnexpectedExecutor(
|
|||||||
|
|
||||||
const char *functionIsolation;
|
const char *functionIsolation;
|
||||||
const char *whereExpected;
|
const char *whereExpected;
|
||||||
if (executor == _swift_task_getMainExecutor()) {
|
if (executor.isMainExecutor()) {
|
||||||
functionIsolation = "@MainActor function";
|
functionIsolation = "@MainActor function";
|
||||||
whereExpected = "the main thread";
|
whereExpected = "the main thread";
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -51,12 +51,3 @@ public func _defaultActorDestroy(_ actor: AnyObject)
|
|||||||
@_silgen_name("swift_task_enqueueMainExecutor")
|
@_silgen_name("swift_task_enqueueMainExecutor")
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
internal func _enqueueOnMain(_ job: UnownedJob)
|
internal func _enqueueOnMain(_ job: UnownedJob)
|
||||||
|
|
||||||
// Used by the concurrency runtime
|
|
||||||
@available(SwiftStdlib 5.5, *)
|
|
||||||
extension SerialExecutor {
|
|
||||||
@_silgen_name("_swift_task_getMainExecutor")
|
|
||||||
internal func _getMainExecutor() -> UnownedSerialExecutor {
|
|
||||||
return MainActor.shared.unownedExecutor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -92,3 +92,27 @@ func _checkExpectedExecutor(_filenameStart: Builtin.RawPointer,
|
|||||||
_reportUnexpectedExecutor(
|
_reportUnexpectedExecutor(
|
||||||
_filenameStart, _filenameLength, _filenameIsASCII, _line, _executor)
|
_filenameStart, _filenameLength, _filenameIsASCII, _line, _executor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(SwiftStdlib 5.5, *)
|
||||||
|
@_silgen_name("swift_task_enqueueOnDispatchQueue")
|
||||||
|
internal func _enqueueOnDispatchQueue(_ job: UnownedJob, queue: AnyObject)
|
||||||
|
|
||||||
|
/// Used by the runtime solely for the witness table it produces.
|
||||||
|
/// FIXME: figure out some way to achieve that which doesn't generate
|
||||||
|
/// all the other metadata
|
||||||
|
///
|
||||||
|
/// Expected to work for any primitive dispatch queue; note that this
|
||||||
|
/// means a dispatch_queue_t, which is not the same as DispatchQueue
|
||||||
|
/// on platforms where that is an instance of a wrapper class.
|
||||||
|
@available(SwiftStdlib 5.5, *)
|
||||||
|
internal class DispatchQueueShim: UnsafeSendable, SerialExecutor {
|
||||||
|
@inlinable
|
||||||
|
func enqueue(_ job: UnownedJob) {
|
||||||
|
_enqueueOnDispatchQueue(job, queue: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
@inlinable
|
||||||
|
func asUnownedSerialExecutor() -> UnownedSerialExecutor {
|
||||||
|
return UnownedSerialExecutor(ordinary: self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -390,8 +390,7 @@ static void swift_task_enqueueMainExecutorImpl(Job *job) {
|
|||||||
// This is an inline function that compiles down to a pointer to a global.
|
// This is an inline function that compiles down to a pointer to a global.
|
||||||
auto mainQueue = dispatch_get_main_queue();
|
auto mainQueue = dispatch_get_main_queue();
|
||||||
|
|
||||||
dispatchEnqueue(mainQueue, job, (dispatch_qos_class_t)priority,
|
dispatchEnqueue(mainQueue, job, (dispatch_qos_class_t)priority, mainQueue);
|
||||||
DISPATCH_QUEUE_MAIN_EXECUTOR);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -404,5 +403,22 @@ void swift::swift_task_enqueueMainExecutor(Job *job) {
|
|||||||
swift_task_enqueueMainExecutorImpl(job);
|
swift_task_enqueueMainExecutorImpl(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void swift::swift_task_enqueueOnDispatchQueue(Job *job,
|
||||||
|
HeapObject *_queue) {
|
||||||
|
JobPriority priority = job->getPriority();
|
||||||
|
auto queue = reinterpret_cast<dispatch_queue_t>(_queue);
|
||||||
|
dispatchEnqueue(queue, job, (dispatch_qos_class_t)priority, queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecutorRef swift::swift_task_getMainExecutor() {
|
||||||
|
return ExecutorRef::forOrdinary(
|
||||||
|
reinterpret_cast<HeapObject*>(&_dispatch_main_q),
|
||||||
|
_swift_task_getDispatchQueueSerialExecutorWitnessTable());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExecutorRef::isMainExecutor() const {
|
||||||
|
return Identity == reinterpret_cast<HeapObject*>(&_dispatch_main_q);
|
||||||
|
}
|
||||||
|
|
||||||
#define OVERRIDE_GLOBAL_EXECUTOR COMPATIBILITY_OVERRIDE
|
#define OVERRIDE_GLOBAL_EXECUTOR COMPATIBILITY_OVERRIDE
|
||||||
#include COMPATIBILITY_OVERRIDE_INCLUDE_PATH
|
#include COMPATIBILITY_OVERRIDE_INCLUDE_PATH
|
||||||
|
|||||||
@@ -15,17 +15,25 @@ import Swift
|
|||||||
/// A singleton actor whose executor is equivalent to the main
|
/// A singleton actor whose executor is equivalent to the main
|
||||||
/// dispatch queue.
|
/// dispatch queue.
|
||||||
@available(SwiftStdlib 5.5, *)
|
@available(SwiftStdlib 5.5, *)
|
||||||
@globalActor public final actor MainActor: SerialExecutor, GlobalActor {
|
@globalActor public final actor MainActor: GlobalActor {
|
||||||
public static let shared = MainActor()
|
public static let shared = MainActor()
|
||||||
|
|
||||||
@inlinable
|
@inlinable
|
||||||
public nonisolated var unownedExecutor: UnownedSerialExecutor {
|
public nonisolated var unownedExecutor: UnownedSerialExecutor {
|
||||||
return asUnownedSerialExecutor()
|
#if compiler(>=5.5) && $BuiltinBuildMainExecutor
|
||||||
|
return UnownedSerialExecutor(Builtin.buildMainActorExecutorRef())
|
||||||
|
#else
|
||||||
|
fatalError("Swift compiler is incompatible with this SDK version")
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@inlinable
|
@inlinable
|
||||||
public nonisolated func asUnownedSerialExecutor() -> UnownedSerialExecutor {
|
public static var sharedUnownedExecutor: UnownedSerialExecutor {
|
||||||
return UnownedSerialExecutor(ordinary: self)
|
#if compiler(>=5.5) && $BuiltinBuildMainExecutor
|
||||||
|
return UnownedSerialExecutor(Builtin.buildMainActorExecutorRef())
|
||||||
|
#else
|
||||||
|
fatalError("Swift compiler is incompatible with this SDK version")
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@inlinable
|
@inlinable
|
||||||
|
|||||||
@@ -238,10 +238,9 @@ static ExecutorRef executorForEnqueuedJob(Job *job) {
|
|||||||
void *jobQueue = job->SchedulerPrivate[Job::DispatchQueueIndex];
|
void *jobQueue = job->SchedulerPrivate[Job::DispatchQueueIndex];
|
||||||
if (jobQueue == DISPATCH_QUEUE_GLOBAL_EXECUTOR)
|
if (jobQueue == DISPATCH_QUEUE_GLOBAL_EXECUTOR)
|
||||||
return ExecutorRef::generic();
|
return ExecutorRef::generic();
|
||||||
else if (jobQueue == DISPATCH_QUEUE_MAIN_EXECUTOR)
|
|
||||||
return _swift_task_getMainExecutor();
|
|
||||||
else
|
else
|
||||||
swift_unreachable("jobQueue was not a known value.");
|
return ExecutorRef::forOrdinary(reinterpret_cast<HeapObject*>(jobQueue),
|
||||||
|
_swift_task_getDispatchQueueSerialExecutorWitnessTable());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void jobInvoke(void *obj, void *unused, uint32_t flags) {
|
static void jobInvoke(void *obj, void *unused, uint32_t flags) {
|
||||||
|
|||||||
@@ -104,15 +104,13 @@ void _swift_tsan_release(void *addr);
|
|||||||
/// Special values used with DispatchQueueIndex to indicate the global and main
|
/// Special values used with DispatchQueueIndex to indicate the global and main
|
||||||
/// executors.
|
/// executors.
|
||||||
#define DISPATCH_QUEUE_GLOBAL_EXECUTOR (void *)1
|
#define DISPATCH_QUEUE_GLOBAL_EXECUTOR (void *)1
|
||||||
#define DISPATCH_QUEUE_MAIN_EXECUTOR (void *)2
|
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
inline SerialExecutorWitnessTable *
|
||||||
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
|
_swift_task_getDispatchQueueSerialExecutorWitnessTable() {
|
||||||
// FIXME: remove this and switch to a representation that uses
|
extern SerialExecutorWitnessTable wtable
|
||||||
// _dispatch_main_q somehow
|
SWIFT_ASM_LABEL_WITH_PREFIX("$ss17DispatchQueueShimCScfsWP");
|
||||||
extern "C" SWIFT_CC(swift)
|
return &wtable;
|
||||||
ExecutorRef _swift_task_getMainExecutor();
|
}
|
||||||
#pragma clang diagnostic pop
|
|
||||||
|
|
||||||
// ==== ------------------------------------------------------------------------
|
// ==== ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user