Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Runtimes/Core/Concurrency/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ target_compile_options(swift_Concurrency PRIVATE
# NOTE: do not remove until `IsolatedAny` is on by default in all supported
# compilers.
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature IsolatedAny>"
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature Extern>"
# NOTE: enable the async frame pointer on Darwin to faciliate debugging.
$<$<AND:$<PLATFORM_ID:Darwin>,$<COMPILE_LANGUAGE:C,CXX>>:-fswift-async-fp=always>
"$<$<AND:$<PLATFORM_ID:Darwin>,$<COMPILE_LANGUAGE:Swift>>:SHELL:-Xfrontend -swift-async-frame-pointer=always>"
Expand Down
14 changes: 13 additions & 1 deletion include/swift/Runtime/RuntimeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -2396,13 +2396,25 @@ FUNCTION(TaskSwitchFunc,
// size_t flags);
FUNCTION(DeinitOnExecutorFunc,
_Concurrency, swift_task_deinitOnExecutor, SwiftCC,
ConcurrencyAvailability,
IsolatedDeinitAvailability,
RETURNS(VoidTy),
ARGS(Int8PtrTy, Int8PtrTy, ExecutorFirstTy, ExecutorSecondTy, SizeTy),
ATTRS(NoUnwind),
EFFECT(RuntimeEffect::Concurrency),
UNKNOWN_MEMEFFECTS)

// void swift_task_deinitOnExecutorMainActorBackDeploy(void *object,
// DeinitWorkFunction *work,
// SerialExecutorRef newExecutor,
// size_t flags);
FUNCTION(DeinitOnExecutorMainActorBackDeployFunc,
_Concurrency, deinitOnExecutorMainActorBackDeploy, SwiftCC,
ConcurrencyAvailability,
RETURNS(VoidTy),
ARGS(Int8PtrTy, Int8PtrTy, ExecutorFirstTy, ExecutorSecondTy, SizeTy),
ATTRS(NoUnwind),
EFFECT(RuntimeEffect::Concurrency),
UNKNOWN_MEMEFFECTS)

// AsyncTask *swift_continuation_init(AsyncContext *continuationContext,
// AsyncContinuationFlags);
Expand Down
8 changes: 8 additions & 0 deletions lib/IRGen/IRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,14 @@ namespace RuntimeConstants {
return RuntimeAvailability::AlwaysAvailable;
}

RuntimeAvailability IsolatedDeinitAvailability(ASTContext &context) {
auto featureAvailability = context.getIsolatedDeinitAvailability();
if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) {
return RuntimeAvailability::ConditionallyAvailable;
}
return RuntimeAvailability::AlwaysAvailable;
}

RuntimeAvailability
MultiPayloadEnumTagSinglePayloadAvailability(ASTContext &context) {
auto featureAvailability = context.getMultiPayloadEnumTagSinglePayload();
Expand Down
9 changes: 9 additions & 0 deletions lib/SILGen/SILGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,15 @@ FuncDecl *SILGenModule::getDeinitOnExecutor() {
return lookupConcurrencyIntrinsic(getASTContext(), "_deinitOnExecutor");
}

FuncDecl *SILGenModule::getDeinitOnExecutorMainActorBackDeploy() {
auto found = lookupConcurrencyIntrinsic(getASTContext(),
"_deinitOnExecutorMainActorBackDeploy");
if (found)
return found;

return getDeinitOnExecutor();
}

FuncDecl *SILGenModule::getCreateExecutors() {
return lookupConcurrencyIntrinsic(getASTContext(), "_createExecutors");
}
Expand Down
2 changes: 2 additions & 0 deletions lib/SILGen/SILGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
FuncDecl *getSwiftJobRun();
/// Retrieve the _Concurrency._deinitOnExecutor intrinsic.
FuncDecl *getDeinitOnExecutor();
/// Retrieve the _Concurrency._deinitOnExecutorMainActorBackDeploy intrinsic.
FuncDecl *getDeinitOnExecutorMainActorBackDeploy();
// Retrieve the _SwiftConcurrencyShims.exit intrinsic.
FuncDecl *getExit();

Expand Down
20 changes: 19 additions & 1 deletion lib/SILGen/SILGenDestructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,17 @@ void SILGenFunction::emitDeallocatingMoveOnlyDestructor(DestructorDecl *dd) {
B.createReturn(loc, emitEmptyTuple(loc));
}

/// Determine whether the availability for the body the given destructor predates the introduction of
/// support for isolated deinit.
static bool availabilityPredatesIsolatedDeinit(DestructorDecl *dd) {
ASTContext &ctx = dd->getASTContext();
if (ctx.LangOpts.DisableAvailabilityChecking)
return false;

auto deploymentAvailability = AvailabilityRange::forDeploymentTarget(ctx);
return !deploymentAvailability.isContainedIn(ctx.getIsolatedDeinitAvailability());
}

void SILGenFunction::emitIsolatingDestructor(DestructorDecl *dd) {
MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit"));

Expand Down Expand Up @@ -372,8 +383,15 @@ void SILGenFunction::emitIsolatingDestructor(DestructorDecl *dd) {
executor = B.createExtractExecutor(loc, actor);
}

// Determine whether we need the main-actor back-deployment version of
// this function.
bool useMainActorBackDeploy =
ai.isMainActor() && availabilityPredatesIsolatedDeinit(dd);

// Get deinitOnExecutor
FuncDecl *swiftDeinitOnExecutorDecl = SGM.getDeinitOnExecutor();
FuncDecl *swiftDeinitOnExecutorDecl =
useMainActorBackDeploy ? SGM.getDeinitOnExecutorMainActorBackDeploy()
: SGM.getDeinitOnExecutor();
if (!swiftDeinitOnExecutorDecl) {
dd->diagnose(diag::missing_deinit_on_executor_function);
return;
Expand Down
18 changes: 10 additions & 8 deletions lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,17 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
diagnoseAndRemoveAttr(attr, diag::isolated_deinit_on_value_type);
return;
}
}

TypeChecker::checkAvailability(
attr->getRange(), C.getIsolatedDeinitAvailability(),
D->getDeclContext(),
[&](AvailabilityDomain domain, AvailabilityRange range) {
return diagnoseAndRemoveAttr(
attr, diag::isolated_deinit_unavailable, domain, range);
});
if (!getActorIsolation(nominal).isMainActor()) {
TypeChecker::checkAvailability(
attr->getRange(), C.getIsolatedDeinitAvailability(),
D->getDeclContext(),
[&](AvailabilityDomain domain, AvailabilityRange range) {
return diagnoseAndRemoveAttr(
attr, diag::isolated_deinit_unavailable, domain, range);
});
}
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions stdlib/public/Concurrency/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ list(APPEND SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS
list(APPEND SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS "-strict-memory-safety")
list(APPEND SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS "-enable-experimental-feature" "AllowUnsafeAttribute")

list(APPEND SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS "-enable-experimental-feature" "Extern")

list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS
"-D__STDC_WANT_LIB_EXT1__=1")

Expand Down
33 changes: 33 additions & 0 deletions stdlib/public/Concurrency/MainActor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,39 @@ extension MainActor {
try assumeIsolated(operation, file: file, line: line)
}
}

#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
@_extern(c, "pthread_main_np")
@usableFromInline
internal func pthread_main_np() -> CInt

@available(SwiftStdlib 5.1, *)
@_alwaysEmitIntoClient
@_silgen_name("swift_task_deinitOnExecutorMainActorBackDeploy")
public func _deinitOnExecutorMainActorBackDeploy(
_ object: __owned AnyObject,
_ work: @convention(thin) (__owned AnyObject) -> Void,
_ executor: Builtin.Executor,
_ flags: Builtin.Word) {
if #available(macOS 15.4, iOS 18.4, watchOS 11.4, tvOS 18.4, visionOS 2.4, *) {
// On new-enough platforms, use the runtime functionality, which allocates
// the task more efficiently.
_deinitOnExecutor(object, work, executor, flags)
} else if pthread_main_np() == 1 {
// Using "main thread" as a proxy for "main actor", immediately destroy
// the object.
work(consume object)
} else {
// Steal the local object so that the reference count stays at 1 even when
// the object is captured.
var stolenObject: AnyObject? = consume object
Task.detached { @MainActor in
work(stolenObject.take()!)
}
}
}
#endif

#endif // !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY

#endif // !$Embedded
15 changes: 15 additions & 0 deletions test/Concurrency/deinit_isolation_backdeploy.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -parse-as-library -emit-silgen -DSILGEN %s | %FileCheck %s

// REQUIRES: concurrency
// REQUIRES: OS=macosx


@MainActor
class C {
// CHECK-LABEL: sil hidden [ossa] @$s27deinit_isolation_backdeploy1CCfD : $@convention(method) (@owned C) -> ()
// CHECK: function_ref @swift_task_deinitOnExecutorMainActorBackDeploy
isolated deinit { }
}

// Make sure this function is available
// CHECK: sil hidden_external [serialized] [available 12.0.0] @swift_task_deinitOnExecutorMainActorBackDeploy : $@convention(thin) (@owned AnyObject, @convention(thin) (@owned AnyObject) -> (), Builtin.Executor, Builtin.Word) -> ()
15 changes: 14 additions & 1 deletion test/Concurrency/nonisolated_deinit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,24 @@ class NotSendable {}
}
}

@globalActor
actor SomeGlobalActor {
static let shared = SomeGlobalActor()
}

// expected-note@+1{{add '@available' attribute to enclosing class}}
@MainActor class C2 {
@SomeGlobalActor class C2 {
var x: Int = 0

isolated deinit { // expected-error{{isolated deinit is only available in macOS 15.4.0 or newer}}
print(x)
}
}

@MainActor class C3 {
var x: Int = 0

isolated deinit { // okay, this back-deploys
print(x)
}
}
2 changes: 2 additions & 0 deletions test/api-digester/stability-concurrency-abi.test
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ Func withThrowingTaskGroup(of:returning:body:) has parameter 2 type change from
Func withTaskGroup(of:returning:body:) has been renamed to Func withTaskGroup(of:returning:isolation:body:)
Func withTaskGroup(of:returning:body:) has mangled name changing from '_Concurrency.withTaskGroup<A, B where A: Swift.Sendable>(of: A.Type, returning: B.Type, body: (inout Swift.TaskGroup<A>) async -> B) async -> B' to '_Concurrency.withTaskGroup<A, B where A: Swift.Sendable>(of: A.Type, returning: B.Type, isolation: isolated Swift.Optional<Swift.Actor>, body: (inout Swift.TaskGroup<A>) async -> B) async -> B'

Func pthread_main_np() is a new API without '@available'

// *** DO NOT DISABLE OR XFAIL THIS TEST. *** (See comment above.)


Expand Down