Skip to content

Commit 0363b99

Browse files
committed
[SIL] Add a new attribute [serialized_for_package].
If Package CMO is enabled, we now add a new attribute to a serialized function, which can then be used during deserialization into a client module to determine the resilience expansion of the function. Resolves rdar://127870822
1 parent 1b848ac commit 0363b99

File tree

11 files changed

+181
-91
lines changed

11 files changed

+181
-91
lines changed

include/swift/SIL/SILFunction.h

Lines changed: 11 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,13 @@ class SILFunction
11381142
"too few bits for Serialized storage");
11391143
}
11401144

1145+
IsSerializedForPackage_t isSerializedForPackage() const {
1146+
return IsSerializedForPackage_t(SerializedForPackage);
1147+
}
1148+
void setSerializedForPackage(IsSerializedForPackage_t isSerializedForPackage) {
1149+
SerializedForPackage = isSerializedForPackage;
1150+
}
1151+
11411152
/// Get this function's thunk attribute.
11421153
IsThunk_t isThunk() const { return IsThunk_t(Thunk); }
11431154
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: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3341,6 +3341,11 @@ void SILFunction::print(SILPrintContext &PrintCtx) const {
33413341
case IsSerialized: OS << "[serialized] "; break;
33423342
}
33433343

3344+
switch (isSerializedForPackage()) {
3345+
case IsNotSerializedForPackage: break;
3346+
case IsSerializedForPackage: OS << "[serialized_for_package] "; break;
3347+
}
3348+
33443349
switch (isThunk()) {
33453350
case IsNotThunk: break;
33463351
case IsThunk: OS << "[thunk] "; break;
@@ -3528,7 +3533,7 @@ void SILGlobalVariable::print(llvm::raw_ostream &OS, bool Verbose) const {
35283533

35293534
if (isSerialized())
35303535
OS << "[serialized] ";
3531-
3536+
35323537
if (isLet())
35333538
OS << "[let] ";
35343539

@@ -3840,7 +3845,7 @@ void SILProperty::print(SILPrintContext &Ctx) const {
38403845
OS << "sil_property ";
38413846
if (isSerialized())
38423847
OS << "[serialized] ";
3843-
3848+
38443849
OS << '#';
38453850
printValueDecl(getDecl(), OS);
38463851
if (auto sig = getDecl()->getInnermostDeclContext()
@@ -4019,6 +4024,7 @@ void SILVTable::print(llvm::raw_ostream &OS, bool Verbose) const {
40194024
OS << "sil_vtable ";
40204025
if (isSerialized())
40214026
OS << "[serialized] ";
4027+
40224028
if (SILType classTy = getClassType()) {
40234029
OS << classTy;
40244030
} else {

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 18 additions & 12 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,
@@ -697,6 +698,8 @@ static bool parseDeclSILOptional(
697698
*isTransparent = true;
698699
else if (isSerialized && SP.P.Tok.getText() == "serialized")
699700
*isSerialized = IsSerialized;
701+
else if (isSerializedForPackage && 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,8 +7142,9 @@ 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,
7145+
&isTransparent, &isSerialized, &isSerializedForPackage,
7146+
&isCanonical, &hasOwnershipSSA, &hasResultDependsOnSelf,
7147+
&isThunk, &isDynamic, &isDistributed,
71437148
&isRuntimeAccessible, &forceEnableLexicalLifetimes,
71447149
&useStackForPackMetadata, &hasUnsafeNonEscapableResult,
71457150
&isExactSelfClass, &DynamicallyReplacedFunction,
@@ -7173,6 +7178,7 @@ bool SILParserState::parseDeclSIL(Parser &P) {
71737178
FunctionState.F->setBare(IsBare);
71747179
FunctionState.F->setTransparent(IsTransparent_t(isTransparent));
71757180
FunctionState.F->setSerialized(IsSerialized_t(isSerialized));
7181+
FunctionState.F->setSerializedForPackage(IsSerializedForPackage_t(isSerializedForPackage));
71767182
FunctionState.F->setWasDeserializedCanonical(isCanonical);
71777183
if (!hasOwnershipSSA)
71787184
FunctionState.F->setOwnershipEliminated();
@@ -7396,13 +7402,12 @@ bool SILParserState::parseSILGlobal(Parser &P) {
73967402

73977403
SILParser State(P);
73987404
if (parseSILLinkage(GlobalLinkage, P) ||
7399-
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
7405+
parseDeclSILOptional(nullptr, &isSerialized, nullptr, 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+
&isLet, nullptr, nullptr, nullptr, nullptr, nullptr,
7410+
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) ||
@@ -7449,12 +7454,13 @@ bool SILParserState::parseSILProperty(Parser &P) {
74497454
SILParser SP(P);
74507455

74517456
IsSerialized_t Serialized = IsNotSerialized;
7452-
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
7457+
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr,
7458+
nullptr, nullptr, nullptr, nullptr, nullptr,
74537459
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
74547460
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
74557461
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
74567462
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7457-
nullptr, nullptr, nullptr, SP, M))
7463+
SP, M))
74587464
return true;
74597465

74607466
ValueDecl *VD;
@@ -7524,7 +7530,7 @@ bool SILParserState::parseSILVTable(Parser &P) {
75247530
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
75257531
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
75267532
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7527-
nullptr, nullptr, nullptr, VTableState, M))
7533+
nullptr, nullptr, nullptr, nullptr, VTableState, M))
75287534
return true;
75297535

75307536

@@ -7642,7 +7648,7 @@ bool SILParserState::parseSILMoveOnlyDeinit(Parser &parser) {
76427648
SILParser moveOnlyDeinitTableState(parser);
76437649

76447650
IsSerialized_t Serialized = IsNotSerialized;
7645-
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
7651+
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr, nullptr,
76467652
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
76477653
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
76487654
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
@@ -8129,7 +8135,7 @@ bool SILParserState::parseSILWitnessTable(Parser &P) {
81298135
parseSILLinkage(Linkage, P);
81308136

81318137
IsSerialized_t isSerialized = IsNotSerialized;
8132-
if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
8138+
if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr, nullptr,
81338139
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
81348140
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
81358141
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,

lib/SILOptimizer/IPO/CrossModuleOptimization.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -571,17 +571,25 @@ bool CrossModuleOptimization::shouldSerialize(SILFunction *function) {
571571
return true;
572572
}
573573

574+
static void addSerializedForPackageAttrIfEnabled(SILFunction *f, const SILModule &mod) {
575+
auto packageOptIn = mod.getOptions().EnableSerializePackage &&
576+
mod.getSwiftModule()->isResilient();
577+
f->setSerializedForPackage(packageOptIn ? IsSerializedForPackage : IsNotSerializedForPackage);
578+
}
579+
574580
/// Serialize \p function and recursively all referenced functions which are
575581
/// marked in \p canSerializeFlags.
576582
void CrossModuleOptimization::serializeFunction(SILFunction *function,
577583
const FunctionFlags &canSerializeFlags) {
578-
if (function->isSerialized())
584+
if (function->isSerialized()) {
585+
addSerializedForPackageAttrIfEnabled(function, M);
579586
return;
580-
587+
}
581588
if (!canSerializeFlags.lookup(function))
582589
return;
583590

584591
function->setSerialized(IsSerialized);
592+
addSerializedForPackageAttrIfEnabled(function, M);
585593

586594
for (SILBasicBlock &block : *function) {
587595
for (SILInstruction &inst : block) {

lib/Serialization/DeserializeSIL.cpp

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -563,16 +563,16 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
563563
IdentifierID replacedFunctionID;
564564
IdentifierID usedAdHocWitnessFunctionID;
565565
GenericSignatureID genericSigID;
566-
unsigned rawLinkage, isTransparent, isSerialized, isThunk,
567-
isWithoutActuallyEscapingThunk, specialPurpose, inlineStrategy,
566+
unsigned rawLinkage, isTransparent, isSerialized, isSerializedForPackage,
567+
isThunk, isWithoutActuallyEscapingThunk, specialPurpose, inlineStrategy,
568568
optimizationMode, perfConstr, subclassScope, hasCReferences, effect,
569569
numAttrs, hasQualifiedOwnership, isWeakImported,
570570
LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass,
571571
isDistributed, isRuntimeAccessible, forceEnableLexicalLifetimes;
572572
ArrayRef<uint64_t> SemanticsIDs;
573573
SILFunctionLayout::readRecord(
574-
scratch, rawLinkage, isTransparent, isSerialized, isThunk,
575-
isWithoutActuallyEscapingThunk, specialPurpose, inlineStrategy,
574+
scratch, rawLinkage, isTransparent, isSerialized, isSerializedForPackage,
575+
isThunk, isWithoutActuallyEscapingThunk, specialPurpose, inlineStrategy,
576576
optimizationMode, perfConstr, subclassScope, hasCReferences, effect,
577577
numAttrs, hasQualifiedOwnership, isWeakImported,
578578
LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass,
@@ -656,13 +656,26 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
656656

657657
fn->setSerialized(IsSerialized_t(isSerialized));
658658

659+
// If fn was serialized in a module with package serialization
660+
// enabled, a new attribute [serialized_for_package] was added
661+
// to its definition. Preserve the attribute here if the current
662+
// module is in the same package, and use it to determine the
663+
// resilience expansion for this function.
664+
auto loadedModule = getFile()->getParentModule();
665+
if (isSerializedForPackage == IsSerializedForPackage &&
666+
loadedModule->isResilient() &&
667+
loadedModule != SILMod.getSwiftModule() &&
668+
loadedModule->serializePackageEnabled() &&
669+
loadedModule->inSamePackage(SILMod.getSwiftModule()))
670+
fn->setSerializedForPackage(IsSerializedForPackage);
671+
659672
// If the serialized function comes from the same module, we're merging
660673
// modules, and can update the linkage directly. This is needed to
661674
// correctly update the linkage for forward declarations to entities defined
662675
// in another file of the same module – we want to ensure the linkage
663676
// reflects the fact that the entity isn't really external and shouldn't be
664677
// dropped from the resulting merged module.
665-
if (getFile()->getParentModule() == SILMod.getSwiftModule())
678+
if (loadedModule == SILMod.getSwiftModule())
666679
fn->setLinkage(linkage);
667680

668681
// Don't override the transparency or linkage of a function with
@@ -703,6 +716,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
703716
fn->setLinkage(linkage);
704717
fn->setTransparent(IsTransparent_t(isTransparent == 1));
705718
fn->setSerialized(IsSerialized_t(isSerialized));
719+
fn->setSerializedForPackage(IsSerializedForPackage_t(isSerializedForPackage));
706720
fn->setThunk(IsThunk_t(isThunk));
707721
fn->setWithoutActuallyEscapingThunk(bool(isWithoutActuallyEscapingThunk));
708722
fn->setInlineStrategy(Inline_t(inlineStrategy));
@@ -3520,16 +3534,16 @@ bool SILDeserializer::hasSILFunction(StringRef Name,
35203534
IdentifierID replacedFunctionID;
35213535
IdentifierID usedAdHocWitnessFunctionID;
35223536
GenericSignatureID genericSigID;
3523-
unsigned rawLinkage, isTransparent, isSerialized, isThunk,
3524-
isWithoutActuallyEscapingThunk, isGlobal, inlineStrategy,
3537+
unsigned rawLinkage, isTransparent, isSerialized, isSerializedForPackage,
3538+
isThunk, isWithoutActuallyEscapingThunk, isGlobal, inlineStrategy,
35253539
optimizationMode, perfConstr, subclassScope, hasCReferences, effect,
35263540
numSpecAttrs, hasQualifiedOwnership, isWeakImported,
35273541
LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass,
35283542
isDistributed, isRuntimeAccessible, forceEnableLexicalLifetimes;
35293543
ArrayRef<uint64_t> SemanticsIDs;
35303544
SILFunctionLayout::readRecord(
3531-
scratch, rawLinkage, isTransparent, isSerialized, isThunk,
3532-
isWithoutActuallyEscapingThunk, isGlobal, inlineStrategy,
3545+
scratch, rawLinkage, isTransparent, isSerialized, isSerializedForPackage,
3546+
isThunk, isWithoutActuallyEscapingThunk, isGlobal, inlineStrategy,
35333547
optimizationMode, perfConstr, subclassScope, hasCReferences, effect,
35343548
numSpecAttrs, hasQualifiedOwnership, isWeakImported,
35353549
LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass,
@@ -3981,7 +3995,7 @@ SILProperty *SILDeserializer::readProperty(DeclID PId) {
39813995
DeclID StorageID;
39823996
ArrayRef<uint64_t> ComponentValues;
39833997
PropertyLayout::readRecord(scratch, StorageID, Serialized, ComponentValues);
3984-
3998+
39853999
auto decl = cast<AbstractStorageDecl>(MF->getDecl(StorageID));
39864000
unsigned ComponentValueIndex = 0;
39874001
auto component = readKeyPathComponent(ComponentValues, ComponentValueIndex);

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 872; // SerializePackageEnabled
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 873; // [serialized_for_package] for SILFunctionLayout
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///

lib/Serialization/SILFormat.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ namespace sil_block {
292292
BCRecordLayout<SIL_FUNCTION, SILLinkageField,
293293
BCFixed<1>, // transparent
294294
BCFixed<1>, // serialized
295+
BCFixed<1>, // serializedForPackage
295296
BCFixed<2>, // thunks: signature optimized/reabstraction
296297
BCFixed<1>, // without_actually_escaping
297298
BCFixed<3>, // specialPurpose

lib/Serialization/SerializeSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,7 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) {
512512
SILFunctionLayout::emitRecord(
513513
Out, ScratchRecord, abbrCode, toStableSILLinkage(Linkage),
514514
(unsigned)F.isTransparent(), (unsigned)F.isSerialized(),
515+
(unsigned)F.isSerializedForPackage(),
515516
(unsigned)F.isThunk(), (unsigned)F.isWithoutActuallyEscapingThunk(),
516517
(unsigned)F.getSpecialPurpose(), (unsigned)F.getInlineStrategy(),
517518
(unsigned)F.getOptimizationMode(), (unsigned)F.getPerfConstraints(),

0 commit comments

Comments
 (0)