Skip to content

Commit 1609122

Browse files
authored
Merge pull request #59809 from ktoso/pick-dist-properties-xedin
🍒[5.7][Distributed] Implement distributed computed properties via special accessor
2 parents 6d09e5d + 50e04f2 commit 1609122

30 files changed

+478
-123
lines changed

include/swift/AST/ASTMangler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ class ASTMangler : public Mangler {
197197
Type GlobalActorBound,
198198
ModuleDecl *Module);
199199

200-
std::string mangleDistributedThunk(const FuncDecl *thunk);
200+
std::string mangleDistributedThunk(const AbstractFunctionDecl *thunk);
201201

202202
/// Mangle a completion handler block implementation function, used for importing ObjC
203203
/// APIs as async.

include/swift/AST/Attr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ SIMPLE_DECL_ATTR(_inheritActorContext, InheritActorContext,
661661
// 117 was 'spawn' and is now unused
662662

663663
CONTEXTUAL_SIMPLE_DECL_ATTR(distributed, DistributedActor,
664-
DeclModifier | OnClass | OnFunc | OnVar |
664+
DeclModifier | OnClass | OnFunc | OnAccessor | OnVar |
665665
ABIBreakingToAdd | ABIBreakingToRemove |
666666
APIBreakingToAdd | APIBreakingToRemove,
667667
118)

include/swift/AST/Decl.h

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
412412
SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2,
413413
StaticSpelling : 2
414414
);
415-
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+2+8+1+1+1+1+1+1,
415+
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+2+8+1+1+1+1+1+1+1,
416416
/// \see AbstractFunctionDecl::BodyKind
417417
BodyKind : 3,
418418

@@ -439,7 +439,11 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
439439

440440
/// Whether peeking into this function detected nested type declarations.
441441
/// This is set when skipping over the decl at parsing.
442-
HasNestedTypeDeclarations : 1
442+
HasNestedTypeDeclarations : 1,
443+
444+
/// Whether this function is a distributed thunk for a distributed
445+
/// function or computed property.
446+
DistributedThunk: 1
443447
);
444448

445449
SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, 1+1+2+1+1+2+1,
@@ -5109,6 +5113,13 @@ class AbstractStorageDecl : public ValueDecl {
51095113

51105114
bool hasAnyNativeDynamicAccessors() const;
51115115

5116+
/// Does this have a 'distributed' modifier?
5117+
bool isDistributed() const;
5118+
5119+
/// Return a distributed thunk if this computed property is marked as
5120+
/// 'distributed' and and nullptr otherwise.
5121+
FuncDecl *getDistributedThunk() const;
5122+
51125123
// Implement isa/cast/dyncast/etc.
51135124
static bool classof(const Decl *D) {
51145125
return D->getKind() >= DeclKind::First_AbstractStorageDecl &&
@@ -5342,9 +5353,6 @@ class VarDecl : public AbstractStorageDecl {
53425353
/// Is this an "async let" property?
53435354
bool isAsyncLet() const;
53445355

5345-
/// Does this have a 'distributed' modifier?
5346-
bool isDistributed() const;
5347-
53485356
/// Is this var known to be a "local" distributed actor,
53495357
/// if so the implicit throwing ans some isolation checks can be skipped.
53505358
bool isKnownToBeLocal() const;
@@ -6314,6 +6322,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
63146322
Bits.AbstractFunctionDecl.Throws = Throws;
63156323
Bits.AbstractFunctionDecl.HasSingleExpressionBody = false;
63166324
Bits.AbstractFunctionDecl.HasNestedTypeDeclarations = false;
6325+
Bits.AbstractFunctionDecl.DistributedThunk = false;
63176326
}
63186327

63196328
void setBodyKind(BodyKind K) {
@@ -6415,6 +6424,16 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
64156424
/// Returns 'true' if the function is distributed.
64166425
bool isDistributed() const;
64176426

6427+
/// Is this a thunk function used to access a distributed method
6428+
/// or computed property outside of its actor isolation context?
6429+
bool isDistributedThunk() const {
6430+
return Bits.AbstractFunctionDecl.DistributedThunk;
6431+
}
6432+
6433+
void setDistributedThunk(bool isThunk) {
6434+
Bits.AbstractFunctionDecl.DistributedThunk = isThunk;
6435+
}
6436+
64186437
/// For a 'distributed' target (func or computed property),
64196438
/// get the 'thunk' responsible for performing the 'remoteCall'.
64206439
///

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4833,6 +4833,9 @@ ERROR(distributed_property_cannot_be_static,none,
48334833
ERROR(distributed_property_can_only_be_computed,none,
48344834
"%0 %1 cannot be 'distributed', only computed properties can",
48354835
(DescriptiveDeclKind, DeclName))
4836+
ERROR(distributed_property_accessor_only_get_can_be_distributed,none,
4837+
"only 'get' accessors may be 'distributed'",
4838+
())
48364839
NOTE(distributed_actor_isolated_property,none,
48374840
"access to %0 %1 is only permitted within distributed actor %2",
48384841
(DescriptiveDeclKind, DeclName, DeclName))

include/swift/AST/Expr.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ enum class AccessSemantics : uint8_t {
124124
/// This is an ordinary access to a declaration, using whatever
125125
/// polymorphism is expected.
126126
Ordinary,
127+
128+
/// This is an access to the underlying storage through a distributed thunk.
129+
///
130+
/// The declaration must be a 'distributed' computed property used outside
131+
/// of its actor isolation context.
132+
DistributedThunk,
127133
};
128134

129135
/// Expr - Base class for all expressions in swift.
@@ -1684,6 +1690,14 @@ class MemberRefExpr : public LookupExpr {
16841690
return (AccessSemantics) Bits.MemberRefExpr.Semantics;
16851691
}
16861692

1693+
/// Informs IRGen to that this member should be applied via its distributed
1694+
/// thunk, rather than invoking it directly.
1695+
///
1696+
/// Only intended to be set on distributed get-only computed properties.
1697+
void setAccessViaDistributedThunk() {
1698+
Bits.MemberRefExpr.Semantics = (unsigned)AccessSemantics::DistributedThunk;
1699+
}
1700+
16871701
SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); }
16881702
SourceLoc getStartLoc() const {
16891703
SourceLoc BaseStartLoc = getBase()->getStartLoc();

include/swift/AST/StorageImpl.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ class AccessStrategy {
110110
/// separately performing a Read into a temporary variable followed by
111111
/// a Write access back into the storage.
112112
MaterializeToTemporary,
113+
114+
/// The access is to a computed distributed property, and thus the
115+
/// get-accessor is a distributed thunk which may perform a remote call.
116+
DispatchToDistributedThunk,
113117
};
114118

115119
private:
@@ -149,6 +153,10 @@ class AccessStrategy {
149153
return { dispatched ? DispatchToAccessor : DirectToAccessor, accessor };
150154
}
151155

156+
static AccessStrategy getDistributedThunkDispatchStrategy() {
157+
return {DispatchToDistributedThunk, AccessorKind::Get};
158+
}
159+
152160
static AccessStrategy getMaterializeToTemporary(AccessStrategy read,
153161
AccessStrategy write) {
154162
return { read, write };
@@ -157,7 +165,8 @@ class AccessStrategy {
157165
Kind getKind() const { return TheKind; }
158166

159167
bool hasAccessor() const {
160-
return TheKind == DirectToAccessor || TheKind == DispatchToAccessor;
168+
return TheKind == DirectToAccessor || TheKind == DispatchToAccessor ||
169+
TheKind == DispatchToDistributedThunk;
161170
}
162171

163172
AccessorKind getAccessor() const {

include/swift/AST/TypeCheckRequests.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,17 +1279,22 @@ class GetDistributedRemoteCallArgumentInitFunctionRequest :
12791279
///
12801280
/// The thunk is responsible for invoking 'remoteCall' when invoked on a remote
12811281
/// 'distributed actor'.
1282-
class GetDistributedThunkRequest :
1283-
public SimpleRequest<GetDistributedThunkRequest,
1284-
FuncDecl *(AbstractFunctionDecl *),
1285-
RequestFlags::Cached> {
1282+
class GetDistributedThunkRequest
1283+
: public SimpleRequest<GetDistributedThunkRequest,
1284+
FuncDecl *(
1285+
llvm::PointerUnion<AbstractStorageDecl *,
1286+
AbstractFunctionDecl *>),
1287+
RequestFlags::Cached> {
1288+
using Originator =
1289+
llvm::PointerUnion<AbstractStorageDecl *, AbstractFunctionDecl *>;
1290+
12861291
public:
12871292
using SimpleRequest::SimpleRequest;
12881293

12891294
private:
12901295
friend SimpleRequest;
12911296

1292-
FuncDecl *evaluate(Evaluator &evaluator, AbstractFunctionDecl *distributedFunc) const;
1297+
FuncDecl *evaluate(Evaluator &evaluator, Originator originator) const;
12931298

12941299
public:
12951300
// Caching

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ SWIFT_REQUEST(TypeChecker, GetDistributedTargetInvocationResultHandlerOnReturnFu
137137
AbstractFunctionDecl *(NominalTypeDecl *),
138138
Cached, NoLocationInfo)
139139
SWIFT_REQUEST(TypeChecker, GetDistributedThunkRequest,
140-
FuncDecl *(AbstractFunctionDecl *),
140+
FuncDecl *(llvm::PointerUnion<AbstractStorageDecl *, AbstractFunctionDecl *>),
141141
Cached, NoLocationInfo)
142142
SWIFT_REQUEST(TypeChecker, GetDistributedActorIDPropertyRequest,
143143
VarDecl *(NominalTypeDecl *),

lib/AST/ASTDumper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ static StringRef getAccessSemanticsString(AccessSemantics value) {
255255
case AccessSemantics::Ordinary: return "ordinary";
256256
case AccessSemantics::DirectToStorage: return "direct_to_storage";
257257
case AccessSemantics::DirectToImplementation: return "direct_to_impl";
258+
case AccessSemantics::DistributedThunk: return "distributed_thunk";
258259
}
259260

260261
llvm_unreachable("Unhandled AccessSemantics in switch.");
@@ -742,6 +743,8 @@ namespace {
742743

743744
void visitVarDecl(VarDecl *VD) {
744745
printCommon(VD, "var_decl");
746+
if (VD->isDistributed())
747+
PrintWithColorRAII(OS, DeclModifierColor) << " distributed";
745748
if (VD->isLet())
746749
PrintWithColorRAII(OS, DeclModifierColor) << " let";
747750
if (VD->getAttrs().hasAttribute<LazyAttr>())
@@ -872,6 +875,9 @@ namespace {
872875
if (D->isDistributed()) {
873876
PrintWithColorRAII(OS, ExprModifierColor) << " distributed";
874877
}
878+
if (D->isDistributedThunk()) {
879+
PrintWithColorRAII(OS, ExprModifierColor) << " distributed-thunk";
880+
}
875881

876882
if (auto fac = D->getForeignAsyncConvention()) {
877883
OS << " foreign_async=";

lib/AST/ASTMangler.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3484,10 +3484,33 @@ ASTMangler::mangleOpaqueTypeDescriptorRecord(const OpaqueTypeDecl *decl) {
34843484
return finalize();
34853485
}
34863486

3487-
std::string ASTMangler::mangleDistributedThunk(const FuncDecl *thunk) {
3487+
std::string ASTMangler::mangleDistributedThunk(const AbstractFunctionDecl *thunk) {
34883488
// Marker protocols cannot be checked at runtime, so there is no point
34893489
// in recording them for distributed thunks.
34903490
llvm::SaveAndRestore<bool> savedAllowMarkerProtocols(AllowMarkerProtocols,
34913491
false);
3492+
3493+
// Since computed property SILDeclRef's refer to the "originator"
3494+
// of the thunk, we need to mangle distributed thunks of accessors
3495+
// specially.
3496+
if (auto *accessor = dyn_cast<AccessorDecl>(thunk)) {
3497+
// TODO: This needs to use accessor type instead of
3498+
// distributed thunk after all SILDeclRefs are switched
3499+
// to use "originator" instead of the thunk itself.
3500+
//
3501+
// ```
3502+
// beginMangling();
3503+
// appendContextOf(thunk);
3504+
// appendDeclName(accessor->getStorage());
3505+
// appendDeclType(accessor, FunctionMangling);
3506+
// appendOperator("F");
3507+
// appendSymbolKind(SymbolKind::DistributedThunk);
3508+
// return finalize();
3509+
// ```
3510+
auto *storage = accessor->getStorage();
3511+
thunk = storage->getDistributedThunk();
3512+
assert(thunk);
3513+
}
3514+
34923515
return mangleEntity(thunk, SymbolKind::DistributedThunk);
34933516
}

lib/AST/Decl.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2259,6 +2259,9 @@ AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics,
22592259
assert(hasStorage());
22602260
return AccessStrategy::getStorage();
22612261

2262+
case AccessSemantics::DistributedThunk:
2263+
return AccessStrategy::getDistributedThunkDispatchStrategy();
2264+
22622265
case AccessSemantics::Ordinary:
22632266
// Skip these checks for local variables, both because they're unnecessary
22642267
// and because we won't necessarily have computed access.
@@ -6417,10 +6420,6 @@ bool VarDecl::isAsyncLet() const {
64176420
return getAttrs().hasAttribute<AsyncAttr>();
64186421
}
64196422

6420-
bool VarDecl::isDistributed() const {
6421-
return getAttrs().hasAttribute<DistributedActorAttr>();
6422-
}
6423-
64246423
bool VarDecl::isKnownToBeLocal() const {
64256424
return getAttrs().hasAttribute<KnownToBeLocalAttr>();
64266425
}

lib/AST/DistributedDecl.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,10 @@ bool AbstractFunctionDecl::isDistributed() const {
13611361
return getAttrs().hasAttribute<DistributedActorAttr>();
13621362
}
13631363

1364+
bool AbstractStorageDecl::isDistributed() const {
1365+
return getAttrs().hasAttribute<DistributedActorAttr>();
1366+
}
1367+
13641368
ConstructorDecl *
13651369
NominalTypeDecl::getDistributedRemoteCallTargetInitFunction() const {
13661370
auto mutableThis = const_cast<NominalTypeDecl *>(this);
@@ -1404,6 +1408,15 @@ AbstractFunctionDecl *ASTContext::getRemoteCallOnDistributedActorSystem(
14041408
/********************** Distributed Actor Properties **************************/
14051409
/******************************************************************************/
14061410

1411+
FuncDecl *AbstractStorageDecl::getDistributedThunk() const {
1412+
if (!isDistributed())
1413+
return nullptr;
1414+
1415+
auto mutableThis = const_cast<AbstractStorageDecl *>(this);
1416+
return evaluateOrDefault(getASTContext().evaluator,
1417+
GetDistributedThunkRequest{mutableThis}, nullptr);
1418+
}
1419+
14071420
FuncDecl*
14081421
AbstractFunctionDecl::getDistributedThunk() const {
14091422
if (!isDistributed())

lib/SILGen/SILGen.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,7 @@ SILGenModule::canStorageUseStoredKeyPathComponent(AbstractStorageDecl *decl,
18321832
case AccessStrategy::DirectToAccessor:
18331833
case AccessStrategy::DispatchToAccessor:
18341834
case AccessStrategy::MaterializeToTemporary:
1835+
case AccessStrategy::DispatchToDistributedThunk:
18351836
return false;
18361837
}
18371838
llvm_unreachable("unhandled strategy");

lib/SILGen/SILGenApply.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5764,7 +5764,8 @@ RValue SILGenFunction::emitGetAccessor(SILLocation loc, SILDeclRef get,
57645764
ArgumentSource &&selfValue, bool isSuper,
57655765
bool isDirectUse,
57665766
PreparedArguments &&subscriptIndices,
5767-
SGFContext c, bool isOnSelfParameter) {
5767+
SGFContext c,
5768+
bool isOnSelfParameter) {
57685769
// Scope any further writeback just within this operation.
57695770
FormalEvaluationScope writebackScope(*this);
57705771

@@ -5838,8 +5839,8 @@ void SILGenFunction::emitSetAccessor(SILLocation loc, SILDeclRef set,
58385839
ManagedValue SILGenFunction::emitAddressorAccessor(
58395840
SILLocation loc, SILDeclRef addressor, SubstitutionMap substitutions,
58405841
ArgumentSource &&selfValue, bool isSuper, bool isDirectUse,
5841-
PreparedArguments &&subscriptIndices, SILType addressType,
5842-
bool isOnSelfParameter) {
5842+
PreparedArguments &&subscriptIndices,
5843+
SILType addressType, bool isOnSelfParameter) {
58435844
// Scope any further writeback just within this operation.
58445845
FormalEvaluationScope writebackScope(*this);
58455846

@@ -5900,7 +5901,8 @@ SILGenFunction::emitCoroutineAccessor(SILLocation loc, SILDeclRef accessor,
59005901
Callee callee =
59015902
emitSpecializedAccessorFunctionRef(*this, loc, accessor,
59025903
substitutions, selfValue,
5903-
isSuper, isDirectUse, isOnSelfParameter);
5904+
isSuper, isDirectUse,
5905+
isOnSelfParameter);
59045906

59055907
// We're already in a full formal-evaluation scope.
59065908
// Make a dead writeback scope; applyCoroutine won't try to pop this.

lib/SILGen/SILGenDistributed.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ void SILGenFunction::emitDistActorIdentityInit(ConstructorDecl *ctor,
213213
initializeProperty(*this, loc, borrowedSelfArg, var, temp);
214214
}
215215

216+
// TODO(distributed): rename to DistributedActorID
216217
InitializeDistActorIdentity::InitializeDistActorIdentity(ConstructorDecl *ctor,
217218
ManagedValue actorSelf)
218219
: ctor(ctor),

lib/SILGen/SILGenExpr.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3505,6 +3505,14 @@ getIdForKeyPathComponentComputedProperty(SILGenModule &SGM,
35053505
// Identify the property by its vtable or wtable slot.
35063506
return SGM.getAccessorDeclRef(getRepresentativeAccessorForKeyPath(storage));
35073507
}
3508+
3509+
case AccessStrategy::DispatchToDistributedThunk: {
3510+
auto thunkRef = SILDeclRef(cast<VarDecl>(storage)->getDistributedThunk(),
3511+
SILDeclRef::Kind::Func,
3512+
/*isForeign=*/false,
3513+
/*isDistributed=*/true);
3514+
return SGM.getFunction(thunkRef, NotForDefinition);
3515+
}
35083516
}
35093517
llvm_unreachable("unhandled access strategy");
35103518
}

lib/SILGen/SILGenFunction.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1477,7 +1477,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
14771477
ManagedValue emitAddressorAccessor(
14781478
SILLocation loc, SILDeclRef addressor, SubstitutionMap substitutions,
14791479
ArgumentSource &&optionalSelfValue, bool isSuper,
1480-
bool isDirectAccessorUse, PreparedArguments &&optionalSubscripts,
1480+
bool isDirectAccessorUse,
1481+
PreparedArguments &&optionalSubscripts,
14811482
SILType addressType, bool isOnSelfParameter);
14821483

14831484
CleanupHandle emitCoroutineAccessor(SILLocation loc, SILDeclRef accessor,

0 commit comments

Comments
 (0)