Skip to content

Commit 7d10f95

Browse files
authored
Merge pull request #82662 from DougGregor/back-deploy-main-actor-isolated-deinit-6.2
[6.2] [SE-0371] Back-deploy support for main-actor-isolated deinit
2 parents 478d16a + a74e7e0 commit 7d10f95

File tree

12 files changed

+128
-11
lines changed

12 files changed

+128
-11
lines changed

Runtimes/Core/Concurrency/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ target_compile_options(swift_Concurrency PRIVATE
113113
# NOTE: do not remove until `IsolatedAny` is on by default in all supported
114114
# compilers.
115115
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature IsolatedAny>"
116+
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature Extern>"
116117
# NOTE: enable the async frame pointer on Darwin to faciliate debugging.
117118
$<$<AND:$<PLATFORM_ID:Darwin>,$<COMPILE_LANGUAGE:C,CXX>>:-fswift-async-fp=always>
118119
"$<$<AND:$<PLATFORM_ID:Darwin>,$<COMPILE_LANGUAGE:Swift>>:SHELL:-Xfrontend -swift-async-frame-pointer=always>"

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2396,13 +2396,25 @@ FUNCTION(TaskSwitchFunc,
23962396
// size_t flags);
23972397
FUNCTION(DeinitOnExecutorFunc,
23982398
_Concurrency, swift_task_deinitOnExecutor, SwiftCC,
2399-
ConcurrencyAvailability,
2399+
IsolatedDeinitAvailability,
24002400
RETURNS(VoidTy),
24012401
ARGS(Int8PtrTy, Int8PtrTy, ExecutorFirstTy, ExecutorSecondTy, SizeTy),
24022402
ATTRS(NoUnwind),
24032403
EFFECT(RuntimeEffect::Concurrency),
24042404
UNKNOWN_MEMEFFECTS)
24052405

2406+
// void swift_task_deinitOnExecutorMainActorBackDeploy(void *object,
2407+
// DeinitWorkFunction *work,
2408+
// SerialExecutorRef newExecutor,
2409+
// size_t flags);
2410+
FUNCTION(DeinitOnExecutorMainActorBackDeployFunc,
2411+
_Concurrency, deinitOnExecutorMainActorBackDeploy, SwiftCC,
2412+
ConcurrencyAvailability,
2413+
RETURNS(VoidTy),
2414+
ARGS(Int8PtrTy, Int8PtrTy, ExecutorFirstTy, ExecutorSecondTy, SizeTy),
2415+
ATTRS(NoUnwind),
2416+
EFFECT(RuntimeEffect::Concurrency),
2417+
UNKNOWN_MEMEFFECTS)
24062418

24072419
// AsyncTask *swift_continuation_init(AsyncContext *continuationContext,
24082420
// AsyncContinuationFlags);

lib/IRGen/IRGenModule.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,14 @@ namespace RuntimeConstants {
983983
return RuntimeAvailability::AlwaysAvailable;
984984
}
985985

986+
RuntimeAvailability IsolatedDeinitAvailability(ASTContext &context) {
987+
auto featureAvailability = context.getIsolatedDeinitAvailability();
988+
if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) {
989+
return RuntimeAvailability::ConditionallyAvailable;
990+
}
991+
return RuntimeAvailability::AlwaysAvailable;
992+
}
993+
986994
RuntimeAvailability
987995
MultiPayloadEnumTagSinglePayloadAvailability(ASTContext &context) {
988996
auto featureAvailability = context.getMultiPayloadEnumTagSinglePayload();

lib/SILGen/SILGen.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,15 @@ FuncDecl *SILGenModule::getDeinitOnExecutor() {
458458
return lookupConcurrencyIntrinsic(getASTContext(), "_deinitOnExecutor");
459459
}
460460

461+
FuncDecl *SILGenModule::getDeinitOnExecutorMainActorBackDeploy() {
462+
auto found = lookupConcurrencyIntrinsic(getASTContext(),
463+
"_deinitOnExecutorMainActorBackDeploy");
464+
if (found)
465+
return found;
466+
467+
return getDeinitOnExecutor();
468+
}
469+
461470
FuncDecl *SILGenModule::getCreateExecutors() {
462471
return lookupConcurrencyIntrinsic(getASTContext(), "_createExecutors");
463472
}

lib/SILGen/SILGen.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
557557
FuncDecl *getSwiftJobRun();
558558
/// Retrieve the _Concurrency._deinitOnExecutor intrinsic.
559559
FuncDecl *getDeinitOnExecutor();
560+
/// Retrieve the _Concurrency._deinitOnExecutorMainActorBackDeploy intrinsic.
561+
FuncDecl *getDeinitOnExecutorMainActorBackDeploy();
560562
// Retrieve the _SwiftConcurrencyShims.exit intrinsic.
561563
FuncDecl *getExit();
562564

lib/SILGen/SILGenDestructor.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,17 @@ void SILGenFunction::emitDeallocatingMoveOnlyDestructor(DestructorDecl *dd) {
339339
B.createReturn(loc, emitEmptyTuple(loc));
340340
}
341341

342+
/// Determine whether the availability for the body the given destructor predates the introduction of
343+
/// support for isolated deinit.
344+
static bool availabilityPredatesIsolatedDeinit(DestructorDecl *dd) {
345+
ASTContext &ctx = dd->getASTContext();
346+
if (ctx.LangOpts.DisableAvailabilityChecking)
347+
return false;
348+
349+
auto deploymentAvailability = AvailabilityRange::forDeploymentTarget(ctx);
350+
return !deploymentAvailability.isContainedIn(ctx.getIsolatedDeinitAvailability());
351+
}
352+
342353
void SILGenFunction::emitIsolatingDestructor(DestructorDecl *dd) {
343354
MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit"));
344355

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

386+
// Determine whether we need the main-actor back-deployment version of
387+
// this function.
388+
bool useMainActorBackDeploy =
389+
ai.isMainActor() && availabilityPredatesIsolatedDeinit(dd);
390+
375391
// Get deinitOnExecutor
376-
FuncDecl *swiftDeinitOnExecutorDecl = SGM.getDeinitOnExecutor();
392+
FuncDecl *swiftDeinitOnExecutorDecl =
393+
useMainActorBackDeploy ? SGM.getDeinitOnExecutorMainActorBackDeploy()
394+
: SGM.getDeinitOnExecutor();
377395
if (!swiftDeinitOnExecutorDecl) {
378396
dd->diagnose(diag::missing_deinit_on_executor_function);
379397
return;

lib/Sema/TypeCheckAttr.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,15 +123,17 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
123123
diagnoseAndRemoveAttr(attr, diag::isolated_deinit_on_value_type);
124124
return;
125125
}
126-
}
127126

128-
TypeChecker::checkAvailability(
129-
attr->getRange(), C.getIsolatedDeinitAvailability(),
130-
D->getDeclContext(),
131-
[&](AvailabilityDomain domain, AvailabilityRange range) {
132-
return diagnoseAndRemoveAttr(
133-
attr, diag::isolated_deinit_unavailable, domain, range);
134-
});
127+
if (!getActorIsolation(nominal).isMainActor()) {
128+
TypeChecker::checkAvailability(
129+
attr->getRange(), C.getIsolatedDeinitAvailability(),
130+
D->getDeclContext(),
131+
[&](AvailabilityDomain domain, AvailabilityRange range) {
132+
return diagnoseAndRemoveAttr(
133+
attr, diag::isolated_deinit_unavailable, domain, range);
134+
});
135+
}
136+
}
135137
}
136138
}
137139

stdlib/public/Concurrency/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ list(APPEND SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS
6868
list(APPEND SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS "-strict-memory-safety")
6969
list(APPEND SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS "-enable-experimental-feature" "AllowUnsafeAttribute")
7070

71+
list(APPEND SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS "-enable-experimental-feature" "Extern")
72+
7173
list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS
7274
"-D__STDC_WANT_LIB_EXT1__=1")
7375

stdlib/public/Concurrency/MainActor.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,39 @@ extension MainActor {
162162
try assumeIsolated(operation, file: file, line: line)
163163
}
164164
}
165+
166+
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
167+
@_extern(c, "pthread_main_np")
168+
@usableFromInline
169+
internal func pthread_main_np() -> CInt
170+
171+
@available(SwiftStdlib 5.1, *)
172+
@_alwaysEmitIntoClient
173+
@_silgen_name("swift_task_deinitOnExecutorMainActorBackDeploy")
174+
public func _deinitOnExecutorMainActorBackDeploy(
175+
_ object: __owned AnyObject,
176+
_ work: @convention(thin) (__owned AnyObject) -> Void,
177+
_ executor: Builtin.Executor,
178+
_ flags: Builtin.Word) {
179+
if #available(macOS 15.4, iOS 18.4, watchOS 11.4, tvOS 18.4, visionOS 2.4, *) {
180+
// On new-enough platforms, use the runtime functionality, which allocates
181+
// the task more efficiently.
182+
_deinitOnExecutor(object, work, executor, flags)
183+
} else if pthread_main_np() == 1 {
184+
// Using "main thread" as a proxy for "main actor", immediately destroy
185+
// the object.
186+
work(consume object)
187+
} else {
188+
// Steal the local object so that the reference count stays at 1 even when
189+
// the object is captured.
190+
var stolenObject: AnyObject? = consume object
191+
Task.detached { @MainActor in
192+
work(stolenObject.take()!)
193+
}
194+
}
195+
}
196+
#endif
197+
165198
#endif // !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
166199

167200
#endif // !$Embedded
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -parse-as-library -emit-silgen -DSILGEN %s | %FileCheck %s
2+
3+
// REQUIRES: concurrency
4+
// REQUIRES: OS=macosx
5+
6+
7+
@MainActor
8+
class C {
9+
// CHECK-LABEL: sil hidden [ossa] @$s27deinit_isolation_backdeploy1CCfD : $@convention(method) (@owned C) -> ()
10+
// CHECK: function_ref @swift_task_deinitOnExecutorMainActorBackDeploy
11+
isolated deinit { }
12+
}
13+
14+
// Make sure this function is available
15+
// CHECK: sil hidden_external [serialized] [available 12.0.0] @swift_task_deinitOnExecutorMainActorBackDeploy : $@convention(thin) (@owned AnyObject, @convention(thin) (@owned AnyObject) -> (), Builtin.Executor, Builtin.Word) -> ()

test/Concurrency/nonisolated_deinit.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,24 @@ class NotSendable {}
1313
}
1414
}
1515

16+
@globalActor
17+
actor SomeGlobalActor {
18+
static let shared = SomeGlobalActor()
19+
}
20+
1621
// expected-note@+1{{add '@available' attribute to enclosing class}}
17-
@MainActor class C2 {
22+
@SomeGlobalActor class C2 {
1823
var x: Int = 0
1924

2025
isolated deinit { // expected-error{{isolated deinit is only available in macOS 15.4.0 or newer}}
2126
print(x)
2227
}
2328
}
29+
30+
@MainActor class C3 {
31+
var x: Int = 0
32+
33+
isolated deinit { // okay, this back-deploys
34+
print(x)
35+
}
36+
}

test/api-digester/stability-concurrency-abi.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ Func withThrowingTaskGroup(of:returning:body:) has parameter 2 type change from
128128
Func withTaskGroup(of:returning:body:) has been renamed to Func withTaskGroup(of:returning:isolation:body:)
129129
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'
130130

131+
Func pthread_main_np() is a new API without '@available'
132+
131133
// *** DO NOT DISABLE OR XFAIL THIS TEST. *** (See comment above.)
132134

133135

0 commit comments

Comments
 (0)