@@ -67,12 +67,14 @@ class CrossModuleOptimization {
6767 bool everything;
6868
6969 typedef llvm::DenseMap<SILFunction *, bool > FunctionFlags;
70+ FunctionFlags canSerializeFlags;
7071
7172public:
7273 CrossModuleOptimization (SILModule &M, bool conservative, bool everything)
7374 : M(M), conservative(conservative), everything(everything) { }
7475
75- void serializeFunctionsInModule (ArrayRef<SILFunction *> functions);
76+ void trySerializeFunctions (ArrayRef<SILFunction *> functions);
77+ void serializeFunctionsInModule (SILPassManager *manager);
7678 void serializeTablesInModule ();
7779
7880private:
@@ -187,6 +189,10 @@ static bool isPackageOrPublic(AccessLevel accessLevel, SILOptions options) {
187189 return accessLevel == AccessLevel::Public;
188190}
189191
192+ static bool isPackageCMOEnabled (ModuleDecl *mod) {
193+ return mod->isResilient () && mod->serializePackageEnabled ();
194+ }
195+
190196// / Checks wither this function is [serialized_for_package] due to Package CMO
191197// / or [serialized] with non-package CMO. The [serialized_for_package] attribute
192198// / is used to indicate that a function is serialized because of Package CMO, which
@@ -201,22 +207,19 @@ static bool isSerializedWithRightKind(const SILModule &mod,
201207 SILFunction *f) {
202208 // If Package CMO is enabled in resilient mode, return
203209 // true if the function is [serialized] due to @inlinable
204- // (or similar) or [serialized_for_pkg] due to this
210+ // (or similar) or [serialized_for_pkg] due to this
205211 // optimization.
206- return mod.getSwiftModule ()->serializePackageEnabled () &&
207- mod.getSwiftModule ()->isResilient () ?
208- f->isAnySerialized () : f->isSerialized ();
212+ return isPackageCMOEnabled (mod.getSwiftModule ()) ? f->isAnySerialized ()
213+ : f->isSerialized ();
209214}
210215static bool isSerializedWithRightKind (const SILModule &mod,
211216 SILGlobalVariable *g) {
212- return mod.getSwiftModule ()->serializePackageEnabled () &&
213- mod.getSwiftModule ()->isResilient () ?
214- g->isAnySerialized () : g->isSerialized ();
217+ return isPackageCMOEnabled (mod.getSwiftModule ()) ? g->isAnySerialized ()
218+ : g->isSerialized ();
215219}
216220static SerializedKind_t getRightSerializedKind (const SILModule &mod) {
217- return mod.getSwiftModule ()->serializePackageEnabled () &&
218- mod.getSwiftModule ()->isResilient () ?
219- IsSerializedForPackage : IsSerialized;
221+ return isPackageCMOEnabled (mod.getSwiftModule ()) ? IsSerializedForPackage
222+ : IsSerialized;
220223}
221224
222225static bool isSerializeCandidate (SILFunction *F, SILOptions options) {
@@ -255,12 +258,8 @@ static bool isReferenceSerializeCandidate(SILGlobalVariable *G,
255258}
256259
257260// / Select functions in the module which should be serialized.
258- void CrossModuleOptimization::serializeFunctionsInModule (
261+ void CrossModuleOptimization::trySerializeFunctions (
259262 ArrayRef<SILFunction *> functions) {
260- FunctionFlags canSerializeFlags;
261-
262- // The passed functions are already ordered bottom-up so the most
263- // nested referenced function is checked first.
264263 for (SILFunction *F : functions) {
265264 if (isSerializeCandidate (F, M.getOptions ()) || everything) {
266265 if (canSerializeFunction (F, canSerializeFlags, /* maxDepth*/ 64 )) {
@@ -270,31 +269,91 @@ void CrossModuleOptimization::serializeFunctionsInModule(
270269 }
271270}
272271
272+ void CrossModuleOptimization::serializeFunctionsInModule (SILPassManager *manager) {
273+ // Reorder SIL funtions in the module bottom up so we can serialize
274+ // the most nested referenced functions first and avoid unnecessary
275+ // recursive checks.
276+ BasicCalleeAnalysis *BCA = manager->getAnalysis <BasicCalleeAnalysis>();
277+ BottomUpFunctionOrder BottomUpOrder (M, BCA);
278+ auto bottomUpFunctions = BottomUpOrder.getFunctions ();
279+ trySerializeFunctions (bottomUpFunctions);
280+ }
281+
273282void CrossModuleOptimization::serializeTablesInModule () {
274283 if (!M.getSwiftModule ()->serializePackageEnabled ())
275284 return ;
276285
277286 for (const auto &vt : M.getVTables ()) {
278- if (! vt->isAnySerialized ( ) &&
287+ if (vt->getSerializedKind () != getRightSerializedKind (M ) &&
279288 vt->getClass ()->getEffectiveAccess () >= AccessLevel::Package) {
280- vt->setSerializedKind (getRightSerializedKind (M));
289+ // This checks if a vtable entry is not serialized and attempts to
290+ // serialize (and its references) if they have the right visibility.
291+ // This should not be necessary but is added to ensure all applicable
292+ // symbols are serialized. Whether serialized or not is cached so
293+ // this check shouldn't be expensive.
294+ auto unserializedClassMethodRange = llvm::make_filter_range (
295+ vt->getEntries (), [&](const SILVTableEntry &entry) {
296+ return entry.getImplementation ()->getSerializedKind () !=
297+ getRightSerializedKind (M);
298+ });
299+ std::vector<SILFunction *> classMethodsToSerialize;
300+ llvm::transform (unserializedClassMethodRange,
301+ std::back_inserter (classMethodsToSerialize),
302+ [&](const SILVTableEntry &entry) {
303+ return entry.getImplementation ();
304+ });
305+ trySerializeFunctions (classMethodsToSerialize);
306+
307+ bool containsInternal =
308+ llvm::any_of (vt->getEntries (), [&](const SILVTableEntry &entry) {
309+ // If the entry is internal, vtable should not be serialized.
310+ // However, if the entry is not serialized but has the right
311+ // visibility, it can still be referenced, thus the vtable
312+ // should serialized.
313+ return !entry.getImplementation ()->hasValidLinkageForFragileRef (
314+ getRightSerializedKind (M));
315+ });
316+ if (!containsInternal)
317+ vt->setSerializedKind (getRightSerializedKind (M));
281318 }
282319 }
283320
321+ // Witness thunks are not serialized, so serialize them here.
284322 for (auto &wt : M.getWitnessTables ()) {
285- if (! wt.isAnySerialized ( ) &&
323+ if (wt.getSerializedKind () != getRightSerializedKind (M ) &&
286324 hasPublicOrPackageVisibility (wt.getLinkage (), /* includePackage*/ true )) {
287- for (auto &entry : wt.getEntries ()) {
288- // Witness thunks are not serialized, so serialize them here.
289- if (entry.getKind () == SILWitnessTable::Method &&
290- !entry.getMethodWitness ().Witness ->isAnySerialized () &&
291- isSerializeCandidate (entry.getMethodWitness ().Witness ,
292- M.getOptions ())) {
293- entry.getMethodWitness ().Witness ->setSerializedKind (getRightSerializedKind (M));
294- }
295- }
296- // Then serialize the witness table itself.
297- wt.setSerializedKind (getRightSerializedKind (M));
325+ // This checks if a wtable entry is not serialized and attempts to
326+ // serialize (and its references) if they have the right visibility.
327+ // This should not be necessary but is added to ensure all applicable
328+ // symbols are serialized. Whether serialized or not is cached so
329+ // this check shouldn't be expensive.
330+ auto unserializedWTMethodRange = llvm::make_filter_range (
331+ wt.getEntries (), [&](const SILWitnessTable::Entry &entry) {
332+ return entry.getKind () == SILWitnessTable::Method &&
333+ entry.getMethodWitness ().Witness ->getSerializedKind () !=
334+ getRightSerializedKind (M);
335+ });
336+ std::vector<SILFunction *> wtMethodsToSerialize;
337+ llvm::transform (unserializedWTMethodRange,
338+ std::back_inserter (wtMethodsToSerialize),
339+ [&](const SILWitnessTable::Entry &entry) {
340+ return entry.getMethodWitness ().Witness ;
341+ });
342+ trySerializeFunctions (wtMethodsToSerialize);
343+
344+ bool containsInternal = llvm::any_of (
345+ wt.getEntries (), [&](const SILWitnessTable::Entry &entry) {
346+ // If the entry is internal, wtable should not be serialized.
347+ // However, if the entry is not serialized but has the right
348+ // visibility, it can still be referenced, thus the vtable
349+ // should serialized.
350+ return entry.getKind () == SILWitnessTable::Method &&
351+ !entry.getMethodWitness ()
352+ .Witness ->hasValidLinkageForFragileRef (
353+ getRightSerializedKind (M));
354+ });
355+ if (!containsInternal)
356+ wt.setSerializedKind (getRightSerializedKind (M));
298357 }
299358 }
300359}
@@ -440,11 +499,29 @@ bool CrossModuleOptimization::canSerializeInstruction(
440499 [&](SILDeclRef method) {
441500 if (method.isForeign )
442501 canUse = false ;
502+ else if (isPackageCMOEnabled (method.getModuleContext ())) {
503+ // If the referenced keypath is internal, do not
504+ // serialize.
505+ auto methodScope = method.getDecl ()->getFormalAccessScope (
506+ nullptr ,
507+ /* treatUsableFromInlineAsPublic*/ true );
508+ canUse = methodScope.isPublicOrPackage ();
509+ }
443510 });
444511 return canUse;
445512 }
446513 if (auto *MI = dyn_cast<MethodInst>(inst)) {
447- return !MI->getMember ().isForeign ;
514+ // If a class_method or witness_method is internal,
515+ // it can't be serialized.
516+ auto member = MI->getMember ();
517+ auto canUse = !member.isForeign ;
518+ if (canUse && isPackageCMOEnabled (member.getModuleContext ())) {
519+ auto methodScope = member.getDecl ()->getFormalAccessScope (
520+ nullptr ,
521+ /* treatUsableFromInlineAsPublic*/ true );
522+ canUse = methodScope.isPublicOrPackage ();
523+ }
524+ return canUse;
448525 }
449526 if (auto *REAI = dyn_cast<RefElementAddrInst>(inst)) {
450527 // In conservative mode, we don't support class field accesses of non-public
@@ -679,7 +756,9 @@ void CrossModuleOptimization::serializeInstruction(SILInstruction *inst,
679756 if (canSerializeGlobal (global)) {
680757 serializeGlobal (global);
681758 }
682- if (!hasPublicOrPackageVisibility (global->getLinkage (), M.getSwiftModule ()->serializePackageEnabled ())) {
759+ if (!hasPublicOrPackageVisibility (
760+ global->getLinkage (),
761+ M.getSwiftModule ()->serializePackageEnabled ())) {
683762 global->setLinkage (SILLinkage::Public);
684763 }
685764 return ;
@@ -851,14 +930,7 @@ class CrossModuleOptimizationPass: public SILModuleTransform {
851930 }
852931
853932 CrossModuleOptimization CMO (M, conservative, everything);
854-
855- // Reorder SIL funtions in the module bottom up so we can serialize
856- // the most nested referenced functions first and avoid unnecessary
857- // recursive checks.
858- BasicCalleeAnalysis *BCA = PM->getAnalysis <BasicCalleeAnalysis>();
859- BottomUpFunctionOrder BottomUpOrder (M, BCA);
860- auto BottomUpFunctions = BottomUpOrder.getFunctions ();
861- CMO.serializeFunctionsInModule (BottomUpFunctions);
933+ CMO.serializeFunctionsInModule (PM);
862934
863935 // Serialize SIL v-tables and witness-tables if package-cmo is enabled.
864936 CMO.serializeTablesInModule ();
0 commit comments