Skip to content

Commit 2d81d0f

Browse files
committed
[SIL] Add a new attribute [serialized_for_package] to support
package-wide resilience domain if Package CMO is enabled. The purpose of the attribute includes: - Indicates that certain types such as loadable types are allowed in serialized functions in resiliently built module if the optimization is enabled, which are otherwise disallowed. - Used during SIL deserialization to determine whether such functions are allowed. - Used to determine if a callee can be inlined into a caller that's serialized without package-cmo, e.g. with an explicit annotation like @inlinable, where the callee was serialized due to package-cmo. Resolves rdar://127870822
1 parent 1b848ac commit 2d81d0f

File tree

14 files changed

+405
-277
lines changed

14 files changed

+405
-277
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/SIL/IR/SILFunction.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -523,12 +523,22 @@ ResilienceExpansion SILFunction::getResilienceExpansion() const {
523523
// source and is never used outside of its package;
524524
// Even if the module is built resiliently, return
525525
// maximal expansion here so aggregate types can be
526-
// loadable in the same resilient domain (from a client
527-
// module in the same package.
526+
// treated as loadable in the same resilient domain
527+
// (across modules in the same package).
528528
if (getModule().getSwiftModule()->serializePackageEnabled() &&
529529
getModule().getSwiftModule()->isResilient())
530530
return ResilienceExpansion::Maximal;
531531

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

lib/SIL/IR/SILPrinter.cpp

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

3344+
switch (isSerializedForPackage()) {
3345+
case IsNotSerializedForPackage:
3346+
break;
3347+
case IsSerializedForPackage:
3348+
OS << "[serialized_for_package] ";
3349+
break;
3350+
}
3351+
33443352
switch (isThunk()) {
33453353
case IsNotThunk: break;
33463354
case IsThunk: OS << "[thunk] "; break;
@@ -3528,7 +3536,7 @@ void SILGlobalVariable::print(llvm::raw_ostream &OS, bool Verbose) const {
35283536

35293537
if (isSerialized())
35303538
OS << "[serialized] ";
3531-
3539+
35323540
if (isLet())
35333541
OS << "[let] ";
35343542

@@ -3840,7 +3848,7 @@ void SILProperty::print(SILPrintContext &Ctx) const {
38403848
OS << "sil_property ";
38413849
if (isSerialized())
38423850
OS << "[serialized] ";
3843-
3851+
38443852
OS << '#';
38453853
printValueDecl(getDecl(), OS);
38463854
if (auto sig = getDecl()->getInnermostDeclContext()
@@ -4019,6 +4027,7 @@ void SILVTable::print(llvm::raw_ostream &OS, bool Verbose) const {
40194027
OS << "sil_vtable ";
40204028
if (isSerialized())
40214029
OS << "[serialized] ";
4030+
40224031
if (SILType classTy = getClassType()) {
40234032
OS << classTy;
40244033
} 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) ||
@@ -7454,7 +7459,7 @@ bool SILParserState::parseSILProperty(Parser &P) {
74547459
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
74557460
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
74567461
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7457-
nullptr, nullptr, nullptr, SP, M))
7462+
nullptr, nullptr, nullptr, nullptr, SP, M))
74587463
return true;
74597464

74607465
ValueDecl *VD;
@@ -7524,7 +7529,7 @@ bool SILParserState::parseSILVTable(Parser &P) {
75247529
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
75257530
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
75267531
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7527-
nullptr, nullptr, nullptr, VTableState, M))
7532+
nullptr, nullptr, nullptr, nullptr, VTableState, M))
75287533
return true;
75297534

75307535

@@ -7647,7 +7652,8 @@ bool SILParserState::parseSILMoveOnlyDeinit(Parser &parser) {
76477652
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
76487653
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
76497654
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7650-
nullptr, nullptr, nullptr, moveOnlyDeinitTableState, M))
7655+
nullptr, nullptr, nullptr, nullptr,
7656+
moveOnlyDeinitTableState, M))
76517657
return true;
76527658

76537659
// Parse the class name.
@@ -8134,7 +8140,7 @@ bool SILParserState::parseSILWitnessTable(Parser &P) {
81348140
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
81358141
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
81368142
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
8137-
nullptr, nullptr, nullptr, WitnessState, M))
8143+
nullptr, nullptr, nullptr, nullptr, WitnessState, M))
81388144
return true;
81398145

81408146
// Parse the protocol conformance.

0 commit comments

Comments
 (0)