Skip to content

Commit 3322c96

Browse files
authored
Merge pull request #58747 from ktoso/pick-wip-init-crash-fix
🍒[5.7][Distributed] Force the order of properties in AST
2 parents 7c1af8f + 1d7f2ee commit 3322c96

9 files changed

+88
-32
lines changed

lib/SILGen/SILGenDistributed.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,12 @@ static void initializeProperty(SILGenFunction &SGF, SILLocation loc,
6464
SGF.B.createCopyAddr(loc, value, fieldAddr, IsNotTake, IsInitialization);
6565
} else {
6666
if (value->getType().isAddress()) {
67-
value = SGF.B.createTrivialLoadOr(
68-
loc, value, LoadOwnershipQualifier::Take);
67+
SGF.emitSemanticLoadInto(loc, value, SGF.F.getTypeLowering(value->getType()),
68+
fieldAddr, SGF.getTypeLowering(loweredType), IsTake, IsInitialization);
6969
} else {
7070
value = SGF.B.emitCopyValueOperation(loc, value);
71-
}
72-
73-
SGF.B.emitStoreValueOperation(
71+
SGF.B.emitStoreValueOperation(
7472
loc, value, fieldAddr, StoreOwnershipQualifier::Init);
75-
76-
if (value->getType().isAddress()) {
77-
SGF.B.createDestroyAddr(loc, value);
7873
}
7974
}
8075
}

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,17 @@ static VarDecl *addImplicitDistributedActorIDProperty(
117117
propDecl->getAttrs().add(
118118
new (C) CompilerInitializedAttr(/*IsImplicit=*/true));
119119

120-
nominal->addMember(propDecl);
121-
nominal->addMember(pbDecl);
122-
120+
// IMPORTANT: The `id` MUST be the first field of any distributed actor,
121+
// because when we allocate remote proxy instances, we don't allocate memory
122+
// for anything except the first two fields: id and actorSystem, so they
123+
// MUST be those fields.
124+
//
125+
// Their specific order also matters, because it is enforced this way in IRGen
126+
// and how we emit them in AST MUST match what IRGen expects or cross-module
127+
// things could be using wrong offsets and manifest as reading trash memory on
128+
// id or system accesses.
129+
nominal->addMember(propDecl, /*hint=*/nullptr, /*insertAtHead=*/true);
130+
nominal->addMember(pbDecl, /*hint=*/nullptr, /*insertAtHead=*/true);
123131
return propDecl;
124132
}
125133

lib/Sema/DerivedConformanceDistributedActor.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -426,14 +426,12 @@ static FuncDecl *deriveDistributedActorSystem_invokeHandlerOnReturn(
426426
/******************************* PROPERTIES ***********************************/
427427
/******************************************************************************/
428428

429-
// TODO(distributed): make use of this after all, but FORCE it?
430429
static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) {
431430
assert(derived.Nominal->isDistributedActor());
432431
auto &C = derived.Context;
433432

434433
// ```
435-
// nonisolated
436-
// let id: Self.ID // Self.ActorSystem.ActorID
434+
// nonisolated let id: Self.ID // Self.ActorSystem.ActorID
437435
// ```
438436
auto propertyType = getDistributedActorIDType(derived.Nominal);
439437

@@ -448,7 +446,8 @@ static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) {
448446
propDecl->getAttrs().add(
449447
new (C) NonisolatedAttr(/*IsImplicit=*/true));
450448

451-
derived.addMembersToConformanceContext({ propDecl, pbDecl });
449+
derived.addMemberToConformanceContext(pbDecl, /*insertAtHead=*/true);
450+
derived.addMemberToConformanceContext(propDecl, /*insertAtHead=*/true);
452451
return propDecl;
453452
}
454453

@@ -460,8 +459,7 @@ static ValueDecl *deriveDistributedActor_actorSystem(
460459
assert(classDecl && derived.Nominal->isDistributedActor());
461460

462461
// ```
463-
// nonisolated
464-
// let actorSystem: ActorSystem
462+
// nonisolated let actorSystem: ActorSystem
465463
// ```
466464
// (no need for @actorIndependent because it is an immutable let)
467465
auto propertyType = getDistributedActorSystemType(classDecl);
@@ -477,7 +475,17 @@ static ValueDecl *deriveDistributedActor_actorSystem(
477475
propDecl->getAttrs().add(
478476
new (C) NonisolatedAttr(/*IsImplicit=*/true));
479477

480-
derived.addMembersToConformanceContext({ propDecl, pbDecl });
478+
// IMPORTANT: `id` MUST be the first field of a distributed actor, and
479+
// `actorSystem` MUST be the second field, because for a remote instance
480+
// we don't allocate memory after those two fields, so their order is very
481+
// important. The `hint` below makes sure the system is inserted right after.
482+
auto id = derived.Nominal->getDistributedActorIDProperty();
483+
assert(id && "id must be synthesized first, so it is the first field of any "
484+
"distributed actor (followed by actorSystem)");
485+
486+
derived.addMemberToConformanceContext(pbDecl, /*hint=*/id);
487+
derived.addMemberToConformanceContext(propDecl, /*hint=*/id);
488+
481489
return propDecl;
482490
}
483491

lib/Sema/DerivedConformances.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ void DerivedConformance::addMembersToConformanceContext(
5151
IDC->addMember(child);
5252
}
5353

54+
void DerivedConformance::addMemberToConformanceContext(
55+
Decl *member, Decl *hint) {
56+
auto IDC = cast<IterableDeclContext>(ConformanceDecl);
57+
IDC->addMember(member, hint, /*insertAtHead=*/false);
58+
}
59+
60+
void DerivedConformance::addMemberToConformanceContext(
61+
Decl *member, bool insertAtHead) {
62+
auto IDC = cast<IterableDeclContext>(ConformanceDecl);
63+
IDC->addMember(member, /*hint=*/nullptr, insertAtHead);
64+
}
65+
5466
Type DerivedConformance::getProtocolType() const {
5567
return Protocol->getDeclaredInterfaceType();
5668
}

lib/Sema/DerivedConformances.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ class DerivedConformance {
7070

7171
/// Add \c children as members of the context that declares the conformance.
7272
void addMembersToConformanceContext(ArrayRef<Decl *> children);
73+
/// Add \c member right after the \c hint member which may be the tail
74+
void addMemberToConformanceContext(Decl *member, Decl* hint);
75+
/// Add \c member in front of any other existing members
76+
void addMemberToConformanceContext(Decl *member, bool insertAtHead);
7377

7478
/// Get the declared type of the protocol that this is conformance is for.
7579
Type getProtocolType() const;

stdlib/public/Distributed/LocalTestingDistributedActorSystem.swift

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import WinSDK
2727
/// prototyping stages of development where a real system is not necessary yet.
2828
@available(SwiftStdlib 5.7, *)
2929
public final class LocalTestingDistributedActorSystem: DistributedActorSystem, @unchecked Sendable {
30-
public typealias ActorID = LocalTestingActorAddress
30+
public typealias ActorID = LocalTestingActorID
3131
public typealias ResultHandler = LocalTestingInvocationResultHandler
3232
public typealias InvocationEncoder = LocalTestingInvocationEncoder
3333
public typealias InvocationDecoder = LocalTestingInvocationDecoder
@@ -115,32 +115,45 @@ public final class LocalTestingDistributedActorSystem: DistributedActorSystem, @
115115

116116
init() {}
117117

118-
mutating func next() -> LocalTestingActorAddress {
118+
mutating func next() -> LocalTestingActorID {
119119
let id: Int = self.counterLock.withLock {
120120
self.counter += 1
121121
return self.counter
122122
}
123-
return LocalTestingActorAddress(parse: "\(id)")
123+
return LocalTestingActorID(id: "\(id)")
124124
}
125125
}
126126
}
127127

128128
@available(SwiftStdlib 5.7, *)
129-
public struct LocalTestingActorAddress: Hashable, Sendable, Codable {
130-
public let address: String
129+
@available(*, deprecated, renamed: "LocalTestingActorID")
130+
public typealias LocalTestingActorAddress = LocalTestingActorID
131131

132-
public init(parse address: String) {
133-
self.address = address
132+
@available(SwiftStdlib 5.7, *)
133+
public struct LocalTestingActorID: Hashable, Sendable, Codable {
134+
@available(*, deprecated, renamed: "id")
135+
public var address: String {
136+
self.id
137+
}
138+
public let id: String
139+
140+
@available(*, deprecated, renamed: "init(id:)")
141+
public init(parse id: String) {
142+
self.id = id
143+
}
144+
145+
public init(id: String) {
146+
self.id = id
134147
}
135148

136149
public init(from decoder: Decoder) throws {
137150
let container = try decoder.singleValueContainer()
138-
self.address = try container.decode(String.self)
151+
self.id = try container.decode(String.self)
139152
}
140153

141154
public func encode(to encoder: Encoder) throws {
142155
var container = encoder.singleValueContainer()
143-
try container.encode(self.address)
156+
try container.encode(self.id)
144157
}
145158
}
146159

test/Distributed/Runtime/distributed_actor_in_other_module.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// REQUIRES: concurrency
99
// REQUIRES: distributed
1010

11-
1211
// UNSUPPORTED: use_os_stdlib
1312
// UNSUPPORTED: back_deployment_runtime
1413

test/Distributed/Runtime/distributed_actor_init_local.swift

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
// UNSUPPORTED: use_os_stdlib
99
// UNSUPPORTED: back_deployment_runtime
1010

11+
// FIXME(distributed): 5.7 branches seem to be missing something; as `main + 32bit watch` does not crash on DA usage with the local testing actor system, but 5.7 does.
12+
// rdar://92952551
13+
// UNSUPPORTED: OS=watchos
14+
1115
import Distributed
1216

1317
enum MyError: Error {
@@ -21,8 +25,8 @@ distributed actor PickATransport1 {
2125
}
2226

2327
distributed actor PickATransport2 {
24-
init(other: Int, thesystem: FakeActorSystem) async {
25-
self.actorSystem = thesystem
28+
init(other: Int, theSystem: FakeActorSystem) async {
29+
self.actorSystem = theSystem
2630
}
2731
}
2832

@@ -90,6 +94,15 @@ distributed actor MaybeAfterAssign {
9094
}
9195
}
9296

97+
distributed actor LocalTestingDA_Int {
98+
typealias ActorSystem = LocalTestingDistributedActorSystem
99+
var int: Int
100+
init() {
101+
actorSystem = .init()
102+
int = 12
103+
}
104+
}
105+
93106
// ==== Fake Transport ---------------------------------------------------------
94107

95108
struct ActorAddress: Sendable, Hashable, Codable {
@@ -240,7 +253,7 @@ func test() async {
240253
// CHECK-NOT: ready
241254
// CHECK: resign id:ActorAddress(address: "[[ID5]]")
242255

243-
test.append(await PickATransport2(other: 1, thesystem: system))
256+
test.append(await PickATransport2(other: 1, theSystem: system))
244257
// CHECK: assign type:PickATransport2, id:ActorAddress(address: "[[ID6:.*]]")
245258
// CHECK: ready actor:main.PickATransport2, id:ActorAddress(address: "[[ID6]]")
246259

@@ -262,6 +275,10 @@ func test() async {
262275
// CHECK: assign type:MaybeAfterAssign, id:ActorAddress(address: "[[ID10:.*]]")
263276
// CHECK-NEXT: ready actor:main.MaybeAfterAssign, id:ActorAddress(address: "[[ID10]]")
264277

278+
let localDA = LocalTestingDA_Int()
279+
print("localDA = \(localDA.id)")
280+
// CHECK: localDA = LocalTestingActorID(id: "1")
281+
265282
// the following tests fail to initialize the actor's identity.
266283
print("-- start of no-assign tests --")
267284
test.append(MaybeSystem(nil))

test/IRGen/distributed_actor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import Distributed
77

88
// Type descriptor.
9-
// CHECK-LABEL: @"$s17distributed_actor7MyActorC2id11Distributed012LocalTestingD7AddressVvpWvd"
9+
// CHECK-LABEL: @"$s17distributed_actor7MyActorC2id11Distributed012LocalTestingD2IDVvpWvd"
1010
@available(SwiftStdlib 5.6, *)
1111
public distributed actor MyActor {
1212
public typealias ActorSystem = LocalTestingDistributedActorSystem

0 commit comments

Comments
 (0)