Skip to content

Commit 2266a57

Browse files
authored
Merge pull request #42252 from ktoso/wip-retain-dist-decode
[Distributed] retain ad-hoc witnesses so that they are not optimized away in SIL
2 parents 41c9651 + fc662bc commit 2266a57

24 files changed

+285
-95
lines changed

include/swift/AST/Decl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3564,10 +3564,10 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
35643564
VarDecl *getDistributedActorIDProperty() const;
35653565

35663566
/// Find the 'RemoteCallTarget.init(_:)' initializer function.
3567-
ConstructorDecl* getDistributedRemoteCallTargetInitFunction() const;
3567+
ConstructorDecl *getDistributedRemoteCallTargetInitFunction() const;
35683568

35693569
/// Find the 'RemoteCallArgument(label:name:value:)' initializer function.
3570-
ConstructorDecl* getDistributedRemoteCallArgumentInitFunction() const;
3570+
ConstructorDecl *getDistributedRemoteCallArgumentInitFunction() const;
35713571

35723572
/// Collect the set of protocols to which this type should implicitly
35733573
/// conform, such as AnyObject (for classes).

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,8 @@ ERROR(expected_sil_function_type, none,
680680
"sil function expected to have SIL function type", ())
681681
ERROR(sil_dynamically_replaced_func_not_found,none,
682682
"dynamically replaced function not found %0", (Identifier))
683+
ERROR(sil_adhoc_requirement_witness_func_not_found,none,
684+
"ad-hoc requirement witness function not found %0", (Identifier))
683685
ERROR(sil_specialize_target_func_not_found,none,
684686
"_specialize target function not found %0", (Identifier))
685687
ERROR(sil_availability_expected_version,none,

include/swift/AST/DistributedDecl.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,21 @@ Type getDistributedActorIDType(NominalTypeDecl *actor);
5353
Type getDistributedSerializationRequirementType(
5454
NominalTypeDecl *nominal, ProtocolDecl *protocol);
5555

56+
/// Given a distributed thunk declaration, inside a 'distributed actor',
57+
/// finds the ad-hoc witness for 'decodeNextArgument' on the associated
58+
/// 'ActorSystem.InvocationDecoder' of the actor, or null.
59+
AbstractFunctionDecl *
60+
getAssociatedDistributedInvocationDecoderDecodeNextArgumentFunction(
61+
ValueDecl *thunk);
62+
5663
/// Get the specific 'InvocationEncoder' type of a specific distributed actor
5764
/// system.
5865
Type getDistributedActorSystemInvocationEncoderType(NominalTypeDecl *system);
5966

67+
/// Get the specific 'InvocationDecoder' type of a specific distributed actor
68+
/// system.
69+
Type getDistributedActorSystemInvocationDecoderType(NominalTypeDecl *system);
70+
6071
/// Get the specific 'ResultHandler' type of a specific distributed actor
6172
/// system.
6273
Type getDistributedActorSystemResultHandlerType(NominalTypeDecl *system);

include/swift/SIL/SILFunction.h

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,17 @@ class SILFunction
212212
/// @_dynamicReplacement(for:) function.
213213
SILFunction *ReplacedFunction = nullptr;
214214

215+
/// This SILFunction REFerences an ad-hoc protocol requirement witness in
216+
/// order to keep it alive, such that it main be obtained in IRGen. Without
217+
/// this explicit reference, the witness would seem not-used, and not be
218+
/// accessible for IRGen.
219+
///
220+
/// Specifically, one such case is the DistributedTargetInvocationDecoder's
221+
/// 'decodeNextArgument' which must be retained, as it is only used from IRGen
222+
/// and such, appears as-if unused in SIL and would get optimized away.
223+
// TODO: Consider making this a general "references adhoc functions" and make it an array?
224+
SILFunction *RefAdHocRequirementFunction = nullptr;
225+
215226
Identifier ObjCReplacementFor;
216227

217228
/// The head of a single-linked list of currently alive BasicBlockBitfield.
@@ -298,7 +309,7 @@ class SILFunction
298309

299310
/// Whether the implementation can be dynamically replaced.
300311
unsigned IsDynamicReplaceable : 1;
301-
312+
302313
/// If true, this indicates that a class method implementation will always be
303314
/// invoked with a `self` argument of the exact base class type.
304315
unsigned ExactSelfClass : 1;
@@ -466,16 +477,6 @@ class SILFunction
466477
ReplacedFunction = f;
467478
ReplacedFunction->incrementRefCount();
468479
}
469-
470-
SILFunction *getDistributedRecordArgumentFunction() const {
471-
return ReplacedFunction;
472-
}
473-
void setDistributedRecordArgumentFunction(SILFunction *f) {
474-
if (f == nullptr)
475-
return;
476-
f->incrementRefCount();
477-
}
478-
479480
/// This function should only be called when SILFunctions are bulk deleted.
480481
void dropDynamicallyReplacedFunction() {
481482
if (!ReplacedFunction)
@@ -484,6 +485,27 @@ class SILFunction
484485
ReplacedFunction = nullptr;
485486
}
486487

488+
SILFunction *getReferencedAdHocRequirementWitnessFunction() const {
489+
return RefAdHocRequirementFunction;
490+
}
491+
// Marks that this `SILFunction` uses the passed in ad-hoc protocol
492+
// requirement witness `f` and therefore must retain it explicitly,
493+
// otherwise we might not be able to get a reference to it.
494+
void setReferencedAdHocRequirementWitnessFunction(SILFunction *f) {
495+
assert(RefAdHocRequirementFunction == nullptr && "already set");
496+
497+
if (f == nullptr)
498+
return;
499+
RefAdHocRequirementFunction = f;
500+
RefAdHocRequirementFunction->incrementRefCount();
501+
}
502+
void dropReferencedAdHocRequirementWitnessFunction() {
503+
if (!RefAdHocRequirementFunction)
504+
return;
505+
RefAdHocRequirementFunction->decrementRefCount();
506+
RefAdHocRequirementFunction = nullptr;
507+
}
508+
487509
bool hasObjCReplacement() const {
488510
return !ObjCReplacementFor.empty();
489511
}
@@ -758,7 +780,7 @@ class SILFunction
758780
IsDynamicReplaceable = value;
759781
assert(!Transparent || !IsDynamicReplaceable);
760782
}
761-
783+
762784
IsExactSelfClass_t isExactSelfClass() const {
763785
return IsExactSelfClass_t(ExactSelfClass);
764786
}

lib/AST/DistributedDecl.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ Type swift::getConcreteReplacementForProtocolActorSystemType(ValueDecl *member)
9797
}
9898

9999
Type swift::getDistributedActorSystemType(NominalTypeDecl *actor) {
100+
assert(!dyn_cast<ProtocolDecl>(actor) &&
101+
"Use getConcreteReplacementForProtocolActorSystemType instead to get"
102+
"the concrete ActorSystem, if bound, for this DistributedActor "
103+
"constrained ProtocolDecl!");
100104
assert(actor->isDistributedActor());
101105
auto &C = actor->getASTContext();
102106

@@ -168,6 +172,21 @@ Type swift::getDistributedActorSystemInvocationEncoderType(NominalTypeDecl *syst
168172
return conformance.getTypeWitnessByName(selfType, ctx.Id_InvocationEncoder);
169173
}
170174

175+
Type swift::getDistributedActorSystemInvocationDecoderType(NominalTypeDecl *system) {
176+
assert(!system->isDistributedActor());
177+
auto &ctx = system->getASTContext();
178+
179+
auto DAS = ctx.getDistributedActorSystemDecl();
180+
if (!DAS)
181+
return Type();
182+
183+
// Dig out the serialization requirement type.
184+
auto module = system->getParentModule();
185+
Type selfType = system->getSelfInterfaceType();
186+
auto conformance = module->lookupConformance(selfType, DAS);
187+
return conformance.getTypeWitnessByName(selfType, ctx.Id_InvocationDecoder);
188+
}
189+
171190
Type swift::getDistributedSerializationRequirementType(
172191
NominalTypeDecl *nominal, ProtocolDecl *protocol) {
173192
assert(nominal);
@@ -184,6 +203,32 @@ Type swift::getDistributedSerializationRequirementType(
184203
return conformance.getTypeWitnessByName(selfType, ctx.Id_SerializationRequirement);
185204
}
186205

206+
AbstractFunctionDecl *
207+
swift::getAssociatedDistributedInvocationDecoderDecodeNextArgumentFunction(
208+
ValueDecl *thunk) {
209+
assert(thunk);
210+
auto &C = thunk->getASTContext();
211+
212+
auto *actor = thunk->getDeclContext()->getSelfNominalTypeDecl();
213+
if (!actor)
214+
return nullptr;
215+
if (!actor->isDistributedActor())
216+
return nullptr;
217+
218+
auto systemTy = getConcreteReplacementForProtocolActorSystemType(thunk);
219+
if (!systemTy)
220+
return nullptr;
221+
222+
auto decoderTy =
223+
getDistributedActorSystemInvocationDecoderType(
224+
systemTy->getAnyNominal());
225+
if (!decoderTy)
226+
return nullptr;
227+
228+
return C.getDecodeNextArgumentOnDistributedInvocationDecoder(
229+
decoderTy->getAnyNominal());
230+
}
231+
187232
Type ASTContext::getAssociatedTypeOfDistributedSystemOfActor(
188233
NominalTypeDecl *actor, Identifier member) {
189234
auto &ctx = actor->getASTContext();

lib/IRGen/GenDistributed.cpp

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -813,21 +813,13 @@ ArgumentDecoderInfo DistributedAccessor::findArgumentDecoder(
813813
decoder = instance.claimNext();
814814
}
815815

816-
if (isa<StructDecl>(decoderDecl) || isa<EnumDecl>(decoderDecl) ||
817-
decoderDecl->isFinal()) {
818-
auto *decodeSIL = IGM.getSILModule().lookUpFunction(SILDeclRef(decodeFn));
819-
auto *fnPtr = IGM.getAddrOfSILFunction(decodeSIL, NotForDefinition,
820-
/*isDynamicallyReplacible=*/false);
816+
auto *decodeSIL = IGM.getSILModule().lookUpFunction(SILDeclRef(decodeFn));
817+
auto *fnPtr = IGM.getAddrOfSILFunction(decodeSIL, NotForDefinition,
818+
/*isDynamicallyReplacible=*/false);
821819

822-
auto methodPtr = FunctionPointer::forDirect(
823-
classifyFunctionPointerKind(decodeSIL), fnPtr,
824-
/*secondaryValue=*/nullptr, signature);
825-
826-
return {decoder, decoderTy, witnessTable, methodPtr, methodTy};
827-
}
828-
829-
auto methodPtr =
830-
emitVirtualMethodValue(IGF, decoderTy, SILDeclRef(decodeFn), methodTy);
820+
auto methodPtr = FunctionPointer::forDirect(
821+
classifyFunctionPointerKind(decodeSIL), fnPtr,
822+
/*secondaryValue=*/nullptr, signature);
831823

832824
return {decoder, decoderTy, witnessTable, methodPtr, methodTy};
833825
}

lib/SIL/IR/SILFunctionBuilder.cpp

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "swift/AST/AttrKind.h"
1515
#include "swift/AST/Availability.h"
1616
#include "swift/AST/DiagnosticsParse.h"
17+
#include "swift/AST/DistributedDecl.h"
1718
#include "swift/AST/Decl.h"
1819
#include "swift/AST/ParameterList.h"
1920
#include "swift/AST/SemanticAttrs.h"
@@ -200,29 +201,35 @@ void SILFunctionBuilder::addFunctionAttributes(
200201
// Only assign replacements when the thing being replaced is function-like and
201202
// explicitly declared.
202203
auto *origDecl = decl->getDynamicallyReplacedDecl();
203-
auto *replacedDecl = dyn_cast_or_null<AbstractFunctionDecl>(origDecl);
204-
if (!replacedDecl)
205-
return;
206-
207-
// For @objc method replacement we normally use categories to perform the
208-
// replacement. Except for methods in generic class where we can't. Instead,
209-
// we special case this and use the native swift replacement mechanism.
210-
if (decl->isObjC() && !decl->isNativeMethodReplacement()) {
211-
F->setObjCReplacement(replacedDecl);
212-
return;
213-
}
214-
215-
if (!constant.canBeDynamicReplacement())
216-
return;
204+
if (auto *replacedDecl = dyn_cast_or_null<AbstractFunctionDecl>(origDecl)) {
205+
// For @objc method replacement we normally use categories to perform the
206+
// replacement. Except for methods in generic class where we can't. Instead,
207+
// we special case this and use the native swift replacement mechanism.
208+
if (decl->isObjC() && !decl->isNativeMethodReplacement()) {
209+
F->setObjCReplacement(replacedDecl);
210+
return;
211+
}
217212

218-
SILDeclRef declRef(replacedDecl, constant.kind, false);
219-
auto *replacedFunc = getOrCreateDeclaration(replacedDecl, declRef);
213+
if (constant.canBeDynamicReplacement()) {
214+
SILDeclRef declRef(replacedDecl, constant.kind, false);
215+
auto *replacedFunc = getOrCreateDeclaration(replacedDecl, declRef);
220216

221-
assert(replacedFunc->getLoweredFunctionType() ==
222-
F->getLoweredFunctionType() ||
223-
replacedFunc->getLoweredFunctionType()->hasOpaqueArchetype());
217+
assert(replacedFunc->getLoweredFunctionType() ==
218+
F->getLoweredFunctionType() ||
219+
replacedFunc->getLoweredFunctionType()->hasOpaqueArchetype());
224220

225-
F->setDynamicallyReplacedFunction(replacedFunc);
221+
F->setDynamicallyReplacedFunction(replacedFunc);
222+
}
223+
} else if (constant.isDistributedThunk()) {
224+
auto decodeFuncDecl =
225+
getAssociatedDistributedInvocationDecoderDecodeNextArgumentFunction(
226+
decl);
227+
assert(decodeFuncDecl && "decodeNextArgument function not found!");
228+
229+
auto decodeRef = SILDeclRef(decodeFuncDecl);
230+
auto *adHocFunc = getOrCreateDeclaration(decodeFuncDecl, decodeRef);
231+
F->setReferencedAdHocRequirementWitnessFunction(adHocFunc);
232+
}
226233
}
227234

228235
SILFunction *SILFunctionBuilder::getOrCreateFunction(

lib/SIL/IR/SILModule.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ SILModule::~SILModule() {
138138
for (SILFunction &F : *this) {
139139
F.dropAllReferences();
140140
F.dropDynamicallyReplacedFunction();
141+
F.dropReferencedAdHocRequirementWitnessFunction();
141142
F.clearSpecializeAttrs();
142143
}
143144

@@ -467,6 +468,7 @@ void SILModule::eraseFunction(SILFunction *F) {
467468
// (References are not needed anymore.)
468469
F->clear();
469470
F->dropDynamicallyReplacedFunction();
471+
F->dropReferencedAdHocRequirementWitnessFunction();
470472
// Drop references for any _specialize(target:) functions.
471473
F->clearSpecializeAttrs();
472474
}

lib/SIL/IR/SILPrinter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2983,6 +2983,12 @@ void SILFunction::print(SILPrintContext &PrintCtx) const {
29832983
OS << "\"] ";
29842984
}
29852985

2986+
if (auto *usedFunc = getReferencedAdHocRequirementWitnessFunction()) {
2987+
OS << "[ref_adhoc_requirement_witness \"";
2988+
OS << usedFunc->getName();
2989+
OS << "\"] ";
2990+
}
2991+
29862992
if (hasObjCReplacement()) {
29872993
OS << "[objc_replacement_for \"";
29882994
OS << getObjCReplacement().str();

0 commit comments

Comments
 (0)