Skip to content

Commit f21d029

Browse files
authored
[Distributed] Accessor must be available cross module in resilient mode (#80523)
* [Distributed] Accessor must be available cross module in resilient mode This is an important fix for libraries using @resolvable in resilient libraries. Without the fix we're missing an accessor and this will fail some remote calls which make use of remote calls on resolvable protocols. This would manifest as missing accessor error thrown by the executeDistributedTarget function. resolves rdar://148224780 * Disable test on windows since %env not supported
1 parent 5ef33db commit f21d029

4 files changed

+265
-18
lines changed

lib/IRGen/GenMeta.cpp

+7-9
Original file line numberDiff line numberDiff line change
@@ -1082,16 +1082,14 @@ namespace {
10821082
// Define the method descriptor.
10831083
SILDeclRef func(entry.getFunction());
10841084

1085-
/// Distributed thunks don't need resilience.
1086-
if (func.isDistributedThunk()) {
1087-
continue;
1085+
/// Distributed thunks don't need method descriptors
1086+
if (!func.isDistributedThunk()) {
1087+
auto *descriptor =
1088+
B.getAddrOfCurrentPosition(
1089+
IGM.ProtocolRequirementStructTy);
1090+
IGM.defineMethodDescriptor(func, Proto, descriptor,
1091+
IGM.ProtocolRequirementStructTy);
10881092
}
1089-
1090-
auto *descriptor =
1091-
B.getAddrOfCurrentPosition(
1092-
IGM.ProtocolRequirementStructTy);
1093-
IGM.defineMethodDescriptor(func, Proto, descriptor,
1094-
IGM.ProtocolRequirementStructTy);
10951093
}
10961094
}
10971095

lib/IRGen/IRSymbolVisitor.cpp

-9
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,6 @@ class IRSymbolVisitorImpl : public SILSymbolVisitor {
108108

109109
void addDispatchThunk(SILDeclRef declRef) override {
110110
auto entity = LinkEntity::forDispatchThunk(declRef);
111-
112-
// TODO: explain why
113-
if (declRef.isDistributedThunk()) {
114-
auto afd = declRef.getAbstractFunctionDecl();
115-
if (afd && isa<ProtocolDecl>(afd->getDeclContext())) {
116-
return;
117-
}
118-
}
119-
120111
addLinkEntity(entity);
121112

122113
if (declRef.getAbstractFunctionDecl()->hasAsync())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -target %target-swift-6.0-abi-triple %S/../Inputs/FakeDistributedActorSystems.swift -plugin-path %swift-plugin-dir
3+
// RUN: %target-build-swift -module-name ActorsFramework -target %target-swift-6.0-abi-triple -j2 -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -plugin-path %swift-plugin-dir -o %t/a.out
4+
// RUN: %target-codesign %t/a.out
5+
// RUN: %env-SWIFT_DUMP_ACCESSIBLE_FUNCTIONS=true %target-run %t/a.out 2>&1 | %FileCheck %s --color --dump-input=always
6+
7+
// REQUIRES: executable_test
8+
// REQUIRES: concurrency
9+
// REQUIRES: distributed
10+
11+
// rdar://76038845
12+
// UNSUPPORTED: use_os_stdlib
13+
// UNSUPPORTED: back_deployment_runtime
14+
15+
// FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574
16+
// UNSUPPORTED: OS=windows-msvc
17+
18+
import Distributed
19+
import FakeDistributedActorSystems
20+
21+
// ==== Known actor system -----------------------------------------------------
22+
23+
public struct Response: Codable, Sendable {
24+
let resp: Int
25+
public init(resp: Int) {
26+
self.resp = resp
27+
}
28+
}
29+
30+
public struct Provider: Codable, Sendable {
31+
let r1: Int
32+
public init(r1: Int) {
33+
self.r1 = r1
34+
}
35+
}
36+
37+
@Resolvable
38+
public protocol DistributedNotificationService: DistributedActor
39+
where ActorSystem == FakeRoundtripActorSystem {
40+
distributed func getArray(a1: [Int], a2: String?) async throws -> [Response]
41+
}
42+
43+
distributed actor DistributedNotificationServiceImpl: DistributedNotificationService {
44+
typealias ActorSystem = FakeRoundtripActorSystem
45+
46+
distributed func getArray(a1: [Int], a2: String?) async throws -> [Response] {
47+
[] // mock impl is enough
48+
}
49+
}
50+
51+
// ==== ------------------------------------------------------------------------
52+
53+
@main struct Main {
54+
static func main() async throws {
55+
let roundtripSystem = FakeRoundtripActorSystem()
56+
57+
let real: any DistributedNotificationService = DistributedNotificationServiceImpl(
58+
actorSystem: roundtripSystem)
59+
60+
let proxy: any DistributedNotificationService =
61+
try $DistributedNotificationService.resolve(id: real.id, using: roundtripSystem)
62+
_ = try await proxy.getArray(a1: [], a2: "")
63+
64+
// CHECK: ==== Accessible Function Records ====
65+
66+
// CHECK: Record name: $s15ActorsFramework30DistributedNotificationServicePAA0C001_C9ActorStubRzrlE8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
67+
// CHECK: Demangled: distributed thunk (extension in ActorsFramework):ActorsFramework.DistributedNotificationService< where A: Distributed._DistributedActorStub>.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ActorsFramework.Response>
68+
// CHECK: Function Ptr: [[PTR:0x.*]]
69+
// CHECK: Flags.IsDistributed: 1
70+
71+
// CHECK: Record name: $s15ActorsFramework34DistributedNotificationServiceImplC8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
72+
// CHECK: Demangled: distributed thunk ActorsFramework.DistributedNotificationServiceImpl.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ActorsFramework.Response>
73+
// CHECK: Function Ptr: [[PTR:0x.*]]
74+
// CHECK: Flags.IsDistributed: 1
75+
76+
// CHECK: Record name: $s15ActorsFramework31$DistributedNotificationServiceC8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
77+
// CHECK: Demangled: distributed thunk ActorsFramework.$DistributedNotificationService.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ActorsFramework.Response>
78+
// CHECK: Function Ptr: [[PTR:0x.*]]
79+
// CHECK: Flags.IsDistributed: 1
80+
81+
// CHECK: Record count: 3
82+
// CHECK: ==== End of Accessible Function Records ====
83+
}
84+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
// RUN: %empty-directory(%t/src)
2+
// RUN: split-file %s %t/src
3+
4+
/// Build the fake actor systems lib
5+
// RUN: %target-build-swift \
6+
// RUN: -target %target-swift-6.0-abi-triple \
7+
// RUN: -parse-as-library -emit-library \
8+
// RUN: -emit-module-path %t/FakeDistributedActorSystems.swiftmodule \
9+
// RUN: -module-name FakeDistributedActorSystems \
10+
// RUN: %S/../Inputs/FakeDistributedActorSystems.swift \
11+
// RUN: -enable-library-evolution \
12+
// RUN: -o %t/%target-library-name(FakeDistributedActorSystems)
13+
14+
/// Build the Lib
15+
// RUN: %target-build-swift \
16+
// RUN: -target %target-swift-6.0-abi-triple \
17+
// RUN: -parse-as-library -emit-library \
18+
// RUN: -emit-module-path %t/ResilientAPILib.swiftmodule \
19+
// RUN: -module-name ResilientAPILib \
20+
// RUN: -I %t \
21+
// RUN: -L %t \
22+
// RUN: -plugin-path %swift-plugin-dir \
23+
// RUN: %t/src/ResilientAPILib.swift \
24+
// RUN: -lFakeDistributedActorSystems \
25+
// RUN: -enable-library-evolution \
26+
// RUN: -o %t/%target-library-name(ResilientAPILib)
27+
28+
/// Build the ActorLib
29+
// RUN: %target-build-swift \
30+
// RUN: -target %target-swift-6.0-abi-triple \
31+
// RUN: -parse-as-library -emit-library \
32+
// RUN: -emit-module-path %t/ResilientImplLib.swiftmodule \
33+
// RUN: -module-name ResilientImplLib \
34+
// RUN: -I %t \
35+
// RUN: -L %t \
36+
// RUN: %t/src/ResilientImplLib.swift \
37+
// RUN: -lFakeDistributedActorSystems \
38+
// RUN: -lResilientAPILib \
39+
// RUN: -enable-library-evolution \
40+
// RUN: -o %t/%target-library-name(ResilientImplLib)
41+
42+
/// Build the client
43+
// RUN: %target-build-swift \
44+
// RUN: -target %target-swift-6.0-abi-triple \
45+
// RUN: -parse-as-library \
46+
// RUN: -lFakeDistributedActorSystems \
47+
// RUN: -lResilientAPILib \
48+
// RUN: -lResilientImplLib \
49+
// RUN: -module-name main \
50+
// RUN: -I %t \
51+
// RUN: -L %t \
52+
// RUN: %s \
53+
// RUN: -enable-library-evolution \
54+
// RUN: -o %t/a.out
55+
56+
// Sign the main binary and all libraries
57+
// RUN: %target-codesign %t/a.out
58+
// RUN: %target-codesign %t/%target-library-name(FakeDistributedActorSystems)
59+
// RUN: %target-codesign %t/%target-library-name(ResilientAPILib)
60+
// RUN: %target-codesign %t/%target-library-name(ResilientImplLib)
61+
62+
// Run and verify output
63+
// RUN: %env-SWIFT_DUMP_ACCESSIBLE_FUNCTIONS=true %target-run %t/a.out \
64+
// RUN: %t/%target-library-name(FakeDistributedActorSystems) \
65+
// RUN: %t/%target-library-name(ResilientAPILib) \
66+
// RUN: %t/%target-library-name(ResilientImplLib) \
67+
// RUN: 2>&1 \
68+
// RUN: | %FileCheck %s --color --dump-input=always
69+
70+
// REQUIRES: executable_test
71+
// REQUIRES: concurrency
72+
// REQUIRES: distributed
73+
74+
// Locating the built libraries failed on Linux (construction of test case),
75+
// but we primarily care about macOS in this test
76+
// UNSUPPORTED: OS=linux-gnu
77+
78+
// %env does not seem to work on Windows
79+
// UNSUPPORTED: OS=windows-msvc
80+
81+
// UNSUPPORTED: use_os_stdlib
82+
// UNSUPPORTED: back_deployment_runtime
83+
// UNSUPPORTED: remote_run || device_run
84+
85+
86+
// FIXME: Also reproduces the following issue rdar://128284016
87+
//<unknown>:0: error: symbol '$s15ResilientAPILib30ServiceProtocolP8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTj' (dispatch thunk of ResilientAPILib.ServiceProtocol.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ResilientAPILib.Response>) is in generated IR file, but not in TBD file
88+
89+
//<unknown>:0: error: symbol '$s15ResilientAPILib30ServiceProtocolP8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTjTu' (async function pointer to dispatch thunk of ResilientAPILib.ServiceProtocol.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ResilientAPILib.Response>) is in generated IR file, but not in TBD file
90+
91+
//--- ResilientAPILib.swift
92+
93+
import Distributed
94+
import FakeDistributedActorSystems
95+
96+
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
97+
public struct Response: Codable {}
98+
99+
@Resolvable
100+
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
101+
public protocol ServiceProtocol: DistributedActor where ActorSystem == FakeRoundtripActorSystem {
102+
distributed func getArray(a1: [Int], a2: String?) -> [Response]
103+
}
104+
105+
//--- ResilientImplLib.swift
106+
107+
import ResilientAPILib
108+
109+
import Distributed
110+
import FakeDistributedActorSystems
111+
112+
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
113+
public distributed actor ServiceImpl: ServiceProtocol {
114+
public typealias ActorSystem = FakeRoundtripActorSystem
115+
116+
public distributed func getArray(a1: [Int], a2: String?) -> [Response] {
117+
[]
118+
}
119+
}
120+
121+
//--- Main.swift
122+
123+
import ResilientAPILib
124+
import ResilientImplLib
125+
126+
import Distributed
127+
import FakeDistributedActorSystems
128+
129+
@main
130+
struct Main {
131+
static func main() async throws {
132+
if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) {
133+
let system = FakeRoundtripActorSystem()
134+
135+
let real: any ServiceProtocol = ServiceImpl(actorSystem: system)
136+
137+
let proxy: any ServiceProtocol =
138+
try $ServiceProtocol.resolve(id: real.id, using: system)
139+
140+
// just in order to see if we crash and trigger the accessible funcs printout
141+
_ = try await proxy.getArray(a1: [], a2: "")
142+
143+
// === We expect records for accessible functions from other modules as well,
144+
// and especially we want to see records for the `$` macro generated stubs,
145+
// including
146+
147+
// CHECK: ==== Accessible Function Records ====
148+
// CHECK: Record name: $s16ResilientImplLib07ServiceB0C8getArray2a12a2Say0A6APILib8ResponseVGSaySiG_SSSgtYaKFTE
149+
// CHECK: Demangled: distributed thunk ResilientImplLib.ServiceImpl.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ResilientAPILib.Response>
150+
151+
// CHECK: Record name: $s15ResilientAPILib15ServiceProtocolPAA11Distributed01_E9ActorStubRzrlE8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
152+
// CHECK: Demangled: distributed thunk (extension in ResilientAPILib):ResilientAPILib.ServiceProtocol< where A: Distributed._DistributedActorStub>.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ResilientAPILib.Response>
153+
154+
// CHECK: Record name: $s15ResilientAPILib16$ServiceProtocolC8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
155+
// CHECK: Demangled: distributed thunk ResilientAPILib.$ServiceProtocol.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ResilientAPILib.Response>
156+
157+
// CHECK: Record name: $s4main15ServiceProtocolPAA11Distributed01_D9ActorStubRzrlE8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
158+
// CHECK: Demangled: distributed thunk (extension in main):main.ServiceProtocol< where A: Distributed._DistributedActorStub>.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<main.Response>
159+
160+
// CHECK: Record name: $s4main11ServiceImplC8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
161+
// CHECK: Demangled: distributed thunk main.ServiceImpl.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<main.Response>
162+
163+
// CHECK: Record name: $s4main16$ServiceProtocolC8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
164+
// CHECK: Demangled: distributed thunk main.$ServiceProtocol.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<main.Response>
165+
166+
// We expect these to be the exact records we get, no other ones:
167+
// CHECK: Record count: 6
168+
169+
// CHECK: ==== End of Accessible Function Records ====
170+
171+
print("DONE") // CHECK: DONE
172+
}
173+
}
174+
}

0 commit comments

Comments
 (0)