Skip to content

Commit 1257db7

Browse files
authored
Merge pull request #73566 from apple/elsh/sil-new-attr
[SIL] Add [serialized_for_package] to control package-wide resilience domain in Package-CMO.
2 parents 764ba94 + 0e88dc2 commit 1257db7

File tree

16 files changed

+517
-294
lines changed

16 files changed

+517
-294
lines changed

include/swift/SIL/SILFunction.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,10 @@ class SILFunction
363363
/// The function's serialized attribute.
364364
bool Serialized : 1;
365365

366+
/// [serialized_for_package] attribute if package serialization
367+
/// is enabled.
368+
bool SerializedForPackage : 1;
369+
366370
/// Specifies if this function is a thunk or a reabstraction thunk.
367371
///
368372
/// The inliner uses this information to avoid inlining (non-trivial)
@@ -1138,6 +1142,22 @@ class SILFunction
11381142
"too few bits for Serialized storage");
11391143
}
11401144

1145+
/// A [serialized_for_package] attribute is used to indicate that a function
1146+
/// is [serialized] because of package-cmo optimization.
1147+
/// Package-cmo allows serializing a function containing a loadable type in
1148+
/// a resiliently built module, which is normally illegal. During SIL deserialization,
1149+
/// this attribute can be used to check whether a loaded function that was serialized
1150+
/// can be allowed to have loadable types. This attribute is also used to determine
1151+
/// if a callee can be inlined into a caller that's serialized without package-cmo, for
1152+
/// example, by explicitly annotating the caller decl with `@inlinable`.
1153+
IsSerializedForPackage_t isSerializedForPackage() const {
1154+
return IsSerializedForPackage_t(SerializedForPackage);
1155+
}
1156+
void
1157+
setSerializedForPackage(IsSerializedForPackage_t isSerializedForPackage) {
1158+
SerializedForPackage = isSerializedForPackage;
1159+
}
1160+
11411161
/// Get this function's thunk attribute.
11421162
IsThunk_t isThunk() const { return IsThunk_t(Thunk); }
11431163
void setThunk(IsThunk_t isThunk) {

include/swift/SIL/SILLinkage.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@ enum IsSerialized_t : unsigned char {
162162
IsSerialized
163163
};
164164

165+
enum IsSerializedForPackage_t : unsigned char {
166+
IsNotSerializedForPackage,
167+
IsSerializedForPackage
168+
};
169+
165170
/// The scope in which a subclassable class can be subclassed.
166171
enum class SubclassScope : uint8_t {
167172
/// This class can be subclassed in other modules.

lib/AST/Decl.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3060,7 +3060,7 @@ bool AbstractStorageDecl::isResilient(ModuleDecl *M,
30603060
case ResilienceExpansion::Maximal:
30613061
if (M == getModuleContext())
30623062
return false;
3063-
// Non-resilient if bypass optimization in package is enabled
3063+
// Access non-resiliently if package optimization is enabled
30643064
if (bypassResilienceInPackage(M))
30653065
return false;
30663066
return isResilient();
@@ -4299,13 +4299,23 @@ bool ValueDecl::hasOpenAccess(const DeclContext *useDC) const {
42994299
}
43004300

43014301
bool ValueDecl::bypassResilienceInPackage(ModuleDecl *accessingModule) const {
4302-
// Client needs to opt in to bypass resilience checks at the use site.
4303-
// Client and the loaded module both need to be in the same package.
4304-
// The loaded module needs to be built from source and opt in to allow
4305-
// non-resilient access.
4306-
return getASTContext().LangOpts.EnableBypassResilienceInPackage &&
4307-
getModuleContext()->inSamePackage(accessingModule) &&
4308-
getModuleContext()->allowNonResilientAccess();
4302+
auto declModule = getModuleContext();
4303+
if (declModule->inSamePackage(accessingModule) &&
4304+
declModule->allowNonResilientAccess()) {
4305+
// If the defining module is built with package-cmo,
4306+
// allow direct access from the use site that belongs
4307+
// to accessingModule (client module).
4308+
if (declModule->isResilient() &&
4309+
declModule->serializePackageEnabled())
4310+
return true;
4311+
4312+
// If not, check if the client can still opt in to
4313+
// have a direct access to this decl from the use
4314+
// site with a flag.
4315+
// FIXME: serialize this flag to Module and get it via accessingModule.
4316+
return getASTContext().LangOpts.EnableBypassResilienceInPackage;
4317+
}
4318+
return false;
43094319
}
43104320

43114321
/// Given the formal access level for using \p VD, compute the scope where
@@ -5162,7 +5172,7 @@ bool NominalTypeDecl::isResilient(ModuleDecl *M,
51625172
// non-resiliently in a maximal context.
51635173
if (M == getModuleContext())
51645174
return false;
5165-
// Non-resilient if bypass optimization in package is enabled
5175+
// Access non-resiliently if package optimization is enabled
51665176
if (bypassResilienceInPackage(M))
51675177
return false;
51685178

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,8 +460,12 @@ static LinkageLimit getLinkageLimit(SILDeclRef constant) {
460460
case Kind::EnumElement:
461461
return Limit::OnDemand;
462462

463-
case Kind::GlobalAccessor:
464-
return cast<VarDecl>(d)->isResilient() ? Limit::NeverPublic : Limit::None;
463+
case Kind::GlobalAccessor: {
464+
auto varDecl = cast<VarDecl>(d);
465+
return varDecl->isResilient() &&
466+
!varDecl->getModuleContext()->allowNonResilientAccess() ?
467+
Limit::NeverPublic : Limit::None;
468+
}
465469

466470
case Kind::DefaultArgGenerator:
467471
// If the default argument is to be serialized, only use non-ABI public

lib/SIL/IR/SILFunction.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ void SILFunction::init(
251251
this->Bare = isBareSILFunction;
252252
this->Transparent = isTrans;
253253
this->Serialized = isSerialized;
254+
this->SerializedForPackage = false;
254255
this->Thunk = isThunk;
255256
this->ClassSubclassScope = unsigned(classSubclassScope);
256257
this->GlobalInitFlag = false;
@@ -523,12 +524,22 @@ ResilienceExpansion SILFunction::getResilienceExpansion() const {
523524
// source and is never used outside of its package;
524525
// Even if the module is built resiliently, return
525526
// maximal expansion here so aggregate types can be
526-
// loadable in the same resilient domain (from a client
527-
// module in the same package.
527+
// treated as loadable in the same resilient domain
528+
// (across modules in the same package).
528529
if (getModule().getSwiftModule()->serializePackageEnabled() &&
529530
getModule().getSwiftModule()->isResilient())
530531
return ResilienceExpansion::Maximal;
531532

533+
// If a function definition is in another module, and
534+
// it was serialized due to package serialization opt,
535+
// a new attribute [serialized_for_package] is added
536+
// to the definition site. During deserialization, this
537+
// attribute is preserved if the current module is in
538+
// the same package, thus should be in the same resilience
539+
// domain.
540+
if (isSerializedForPackage() == IsSerializedForPackage)
541+
return ResilienceExpansion::Maximal;
542+
532543
return (isSerialized()
533544
? ResilienceExpansion::Minimal
534545
: ResilienceExpansion::Maximal);

lib/SIL/IR/SILPrinter.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3353,6 +3353,14 @@ void SILFunction::print(SILPrintContext &PrintCtx) const {
33533353
case IsSerialized: OS << "[serialized] "; break;
33543354
}
33553355

3356+
switch (isSerializedForPackage()) {
3357+
case IsNotSerializedForPackage:
3358+
break;
3359+
case IsSerializedForPackage:
3360+
OS << "[serialized_for_package] ";
3361+
break;
3362+
}
3363+
33563364
switch (isThunk()) {
33573365
case IsNotThunk: break;
33583366
case IsThunk: OS << "[thunk] "; break;
@@ -3540,7 +3548,7 @@ void SILGlobalVariable::print(llvm::raw_ostream &OS, bool Verbose) const {
35403548

35413549
if (isSerialized())
35423550
OS << "[serialized] ";
3543-
3551+
35443552
if (isLet())
35453553
OS << "[let] ";
35463554

@@ -3852,7 +3860,7 @@ void SILProperty::print(SILPrintContext &Ctx) const {
38523860
OS << "sil_property ";
38533861
if (isSerialized())
38543862
OS << "[serialized] ";
3855-
3863+
38563864
OS << '#';
38573865
printValueDecl(getDecl(), OS);
38583866
if (auto sig = getDecl()->getInnermostDeclContext()
@@ -4031,6 +4039,7 @@ void SILVTable::print(llvm::raw_ostream &OS, bool Verbose) const {
40314039
OS << "sil_vtable ";
40324040
if (isSerialized())
40334041
OS << "[serialized] ";
4042+
40344043
if (SILType classTy = getClassType()) {
40354044
OS << classTy;
40364045
} else {

lib/SIL/IR/TypeLowering.cpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2324,31 +2324,34 @@ namespace {
23242324
if (D->isResilient()) {
23252325
// If the type is resilient and defined in our module, make a note of
23262326
// that, since our lowering now depends on the resilience expansion.
2327+
// The same should happen if the type was resilient and serialized in
2328+
// another module in the same package with package-cmo enabled, which
2329+
// treats those modules to be in the same resilience domain.
23272330
auto declModule = D->getModuleContext();
23282331
bool sameModule = (declModule == &TC.M);
2329-
if (sameModule)
2332+
bool serializedPackage = declModule != &TC.M &&
2333+
declModule->inSamePackage(&TC.M) &&
2334+
declModule->isResilient() &&
2335+
declModule->serializePackageEnabled();
2336+
auto inSameResilienceDomain = sameModule || serializedPackage;
2337+
if (inSameResilienceDomain)
23302338
properties.addSubobject(RecursiveProperties::forResilient());
23312339

2332-
// If the type is in a different module, or if we're using a minimal
2340+
// If the type is in a different module and not in the same package
2341+
// resilience domain (with package-cmo), or if we're using a minimal
23332342
// expansion, the type is address only and completely opaque to us.
2334-
// However, this is not true if the different module is in the same
2335-
// package and package serialization is enabled (resilience expansion
2336-
// is maximal), e.g. in case of package-cmo.
23372343
//
2338-
// Note: if the type is in a different module, the lowering does
2339-
// not depend on the resilience expansion, so we do not need to set
2340-
// the isResilient() flag above.
2341-
bool serializedPackage = declModule->inSamePackage(&TC.M) &&
2342-
declModule->isResilient() &&
2343-
declModule->serializePackageEnabled();
2344-
if ((!sameModule && !serializedPackage) ||
2344+
// Note: if the type is in a different module and not in the same
2345+
// package resilience domain, the lowering does not depend on the
2346+
// resilience expansion, so we do not need to set the isResilient()
2347+
// flag above.
2348+
if (!inSameResilienceDomain ||
23452349
Expansion.getResilienceExpansion() ==
23462350
ResilienceExpansion::Minimal) {
23472351
properties.addSubobject(RecursiveProperties::forOpaque());
23482352
return true;
23492353
}
23502354
}
2351-
23522355
return false;
23532356
}
23542357

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,8 @@ void SILParser::convertRequirements(ArrayRef<RequirementRepr> From,
665665
}
666666

667667
static bool parseDeclSILOptional(
668-
bool *isTransparent, IsSerialized_t *isSerialized, bool *isCanonical,
668+
bool *isTransparent, IsSerialized_t *isSerialized,
669+
IsSerializedForPackage_t *isSerializedForPackage, bool *isCanonical,
669670
bool *hasOwnershipSSA, bool *hasResultDependsOnSelf, IsThunk_t *isThunk,
670671
IsDynamicallyReplaceable_t *isDynamic, IsDistributed_t *isDistributed,
671672
IsRuntimeAccessible_t *isRuntimeAccessible,
@@ -676,10 +677,9 @@ static bool parseDeclSILOptional(
676677
SILFunction **usedAdHocRequirementWitness, Identifier *objCReplacementFor,
677678
SILFunction::Purpose *specialPurpose, Inline_t *inlineStrategy,
678679
OptimizationMode *optimizationMode, PerformanceConstraints *perfConstraints,
679-
bool *isPerformanceConstraint,
680-
bool *markedAsUsed, StringRef *section, bool *isLet, bool *isWeakImported,
681-
bool *needStackProtection, AvailabilityContext *availability,
682-
bool *isWithoutActuallyEscapingThunk,
680+
bool *isPerformanceConstraint, bool *markedAsUsed, StringRef *section,
681+
bool *isLet, bool *isWeakImported, bool *needStackProtection,
682+
AvailabilityContext *availability, bool *isWithoutActuallyEscapingThunk,
683683
SmallVectorImpl<std::string> *Semantics,
684684
SmallVectorImpl<ParsedSpecAttr> *SpecAttrs, ValueDecl **ClangDecl,
685685
EffectsKind *MRK, SILParser &SP, SILModule &M) {
@@ -697,6 +697,9 @@ static bool parseDeclSILOptional(
697697
*isTransparent = true;
698698
else if (isSerialized && SP.P.Tok.getText() == "serialized")
699699
*isSerialized = IsSerialized;
700+
else if (isSerializedForPackage &&
701+
SP.P.Tok.getText() == "serialized_for_package")
702+
*isSerializedForPackage = IsSerializedForPackage;
700703
else if (isDynamic && SP.P.Tok.getText() == "dynamically_replacable")
701704
*isDynamic = IsDynamic;
702705
else if (isDistributed && SP.P.Tok.getText() == "distributed")
@@ -7106,6 +7109,7 @@ bool SILParserState::parseDeclSIL(Parser &P) {
71067109

71077110
bool isTransparent = false;
71087111
IsSerialized_t isSerialized = IsNotSerialized;
7112+
IsSerializedForPackage_t isSerializedForPackage = IsNotSerializedForPackage;
71097113
bool isCanonical = false;
71107114
IsDynamicallyReplaceable_t isDynamic = IsNotDynamic;
71117115
IsDistributed_t isDistributed = IsNotDistributed;
@@ -7138,17 +7142,17 @@ bool SILParserState::parseDeclSIL(Parser &P) {
71387142
Identifier objCReplacementFor;
71397143
if (parseSILLinkage(FnLinkage, P) ||
71407144
parseDeclSILOptional(
7141-
&isTransparent, &isSerialized, &isCanonical, &hasOwnershipSSA,
7142-
&hasResultDependsOnSelf, &isThunk, &isDynamic, &isDistributed,
7143-
&isRuntimeAccessible, &forceEnableLexicalLifetimes,
7145+
&isTransparent, &isSerialized, &isSerializedForPackage, &isCanonical,
7146+
&hasOwnershipSSA, &hasResultDependsOnSelf, &isThunk, &isDynamic,
7147+
&isDistributed, &isRuntimeAccessible, &forceEnableLexicalLifetimes,
71447148
&useStackForPackMetadata, &hasUnsafeNonEscapableResult,
71457149
&isExactSelfClass, &DynamicallyReplacedFunction,
71467150
&AdHocWitnessFunction, &objCReplacementFor, &specialPurpose,
71477151
&inlineStrategy, &optimizationMode, &perfConstr,
7148-
&isPerformanceConstraint, &markedAsUsed,
7149-
&section, nullptr, &isWeakImported, &needStackProtection,
7150-
&availability, &isWithoutActuallyEscapingThunk, &Semantics,
7151-
&SpecAttrs, &ClangDecl, &MRK, FunctionState, M) ||
7152+
&isPerformanceConstraint, &markedAsUsed, &section, nullptr,
7153+
&isWeakImported, &needStackProtection, &availability,
7154+
&isWithoutActuallyEscapingThunk, &Semantics, &SpecAttrs, &ClangDecl,
7155+
&MRK, FunctionState, M) ||
71527156
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
71537157
P.parseIdentifier(FnName, FnNameLoc, /*diagnoseDollarPrefix=*/false,
71547158
diag::expected_sil_function_name) ||
@@ -7173,6 +7177,8 @@ bool SILParserState::parseDeclSIL(Parser &P) {
71737177
FunctionState.F->setBare(IsBare);
71747178
FunctionState.F->setTransparent(IsTransparent_t(isTransparent));
71757179
FunctionState.F->setSerialized(IsSerialized_t(isSerialized));
7180+
FunctionState.F->setSerializedForPackage(
7181+
IsSerializedForPackage_t(isSerializedForPackage));
71767182
FunctionState.F->setWasDeserializedCanonical(isCanonical);
71777183
if (!hasOwnershipSSA)
71787184
FunctionState.F->setOwnershipEliminated();
@@ -7399,10 +7405,9 @@ bool SILParserState::parseSILGlobal(Parser &P) {
73997405
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
74007406
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
74017407
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7402-
nullptr,
7403-
nullptr, nullptr, nullptr, nullptr, nullptr, &isLet,
74047408
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7405-
nullptr, nullptr, State, M) ||
7409+
nullptr, &isLet, nullptr, nullptr, nullptr, nullptr,
7410+
nullptr, nullptr, nullptr, nullptr, State, M) ||
74067411
P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
74077412
P.parseIdentifier(GlobalName, NameLoc, /*diagnoseDollarPrefix=*/false,
74087413
diag::expected_sil_value_name) ||
@@ -7455,7 +7460,7 @@ bool SILParserState::parseSILProperty(Parser &P) {
74557460
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
74567461
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
74577462
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7458-
nullptr, nullptr, nullptr, SP, M))
7463+
nullptr, nullptr, nullptr, nullptr, SP, M))
74597464
return true;
74607465

74617466
ValueDecl *VD;
@@ -7525,7 +7530,7 @@ bool SILParserState::parseSILVTable(Parser &P) {
75257530
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
75267531
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
75277532
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7528-
nullptr, nullptr, nullptr, VTableState, M))
7533+
nullptr, nullptr, nullptr, nullptr, VTableState, M))
75297534
return true;
75307535

75317536

@@ -7648,7 +7653,8 @@ bool SILParserState::parseSILMoveOnlyDeinit(Parser &parser) {
76487653
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
76497654
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
76507655
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7651-
nullptr, nullptr, nullptr, moveOnlyDeinitTableState, M))
7656+
nullptr, nullptr, nullptr, nullptr,
7657+
moveOnlyDeinitTableState, M))
76527658
return true;
76537659

76547660
// Parse the class name.
@@ -8135,7 +8141,7 @@ bool SILParserState::parseSILWitnessTable(Parser &P) {
81358141
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
81368142
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
81378143
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
8138-
nullptr, nullptr, nullptr, WitnessState, M))
8144+
nullptr, nullptr, nullptr, nullptr, WitnessState, M))
81398145
return true;
81408146

81418147
// Parse the protocol conformance.

0 commit comments

Comments
 (0)