@@ -67,12 +67,14 @@ class CrossModuleOptimization {
67
67
bool everything;
68
68
69
69
typedef llvm::DenseMap<SILFunction *, bool > FunctionFlags;
70
+ FunctionFlags canSerializeFlags;
70
71
71
72
public:
72
73
CrossModuleOptimization (SILModule &M, bool conservative, bool everything)
73
74
: M(M), conservative(conservative), everything(everything) { }
74
75
75
- void serializeFunctionsInModule (ArrayRef<SILFunction *> functions);
76
+ void trySerializeFunctions (ArrayRef<SILFunction *> functions);
77
+ void serializeFunctionsInModule (SILPassManager *manager);
76
78
void serializeTablesInModule ();
77
79
78
80
private:
@@ -187,6 +189,10 @@ static bool isPackageOrPublic(AccessLevel accessLevel, SILOptions options) {
187
189
return accessLevel == AccessLevel::Public;
188
190
}
189
191
192
+ static bool isPackageCMOEnabled (ModuleDecl *mod) {
193
+ return mod->isResilient () && mod->serializePackageEnabled ();
194
+ }
195
+
190
196
// / Checks wither this function is [serialized_for_package] due to Package CMO
191
197
// / or [serialized] with non-package CMO. The [serialized_for_package] attribute
192
198
// / is used to indicate that a function is serialized because of Package CMO, which
@@ -201,22 +207,19 @@ static bool isSerializedWithRightKind(const SILModule &mod,
201
207
SILFunction *f) {
202
208
// If Package CMO is enabled in resilient mode, return
203
209
// 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
205
211
// 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 ();
209
214
}
210
215
static bool isSerializedWithRightKind (const SILModule &mod,
211
216
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 ();
215
219
}
216
220
static 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;
220
223
}
221
224
222
225
static bool isSerializeCandidate (SILFunction *F, SILOptions options) {
@@ -255,12 +258,8 @@ static bool isReferenceSerializeCandidate(SILGlobalVariable *G,
255
258
}
256
259
257
260
// / Select functions in the module which should be serialized.
258
- void CrossModuleOptimization::serializeFunctionsInModule (
261
+ void CrossModuleOptimization::trySerializeFunctions (
259
262
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.
264
263
for (SILFunction *F : functions) {
265
264
if (isSerializeCandidate (F, M.getOptions ()) || everything) {
266
265
if (canSerializeFunction (F, canSerializeFlags, /* maxDepth*/ 64 )) {
@@ -270,31 +269,91 @@ void CrossModuleOptimization::serializeFunctionsInModule(
270
269
}
271
270
}
272
271
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
+
273
282
void CrossModuleOptimization::serializeTablesInModule () {
274
283
if (!M.getSwiftModule ()->serializePackageEnabled ())
275
284
return ;
276
285
277
286
for (const auto &vt : M.getVTables ()) {
278
- if (! vt->isAnySerialized ( ) &&
287
+ if (vt->getSerializedKind () != getRightSerializedKind (M ) &&
279
288
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));
281
318
}
282
319
}
283
320
321
+ // Witness thunks are not serialized, so serialize them here.
284
322
for (auto &wt : M.getWitnessTables ()) {
285
- if (! wt.isAnySerialized ( ) &&
323
+ if (wt.getSerializedKind () != getRightSerializedKind (M ) &&
286
324
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));
298
357
}
299
358
}
300
359
}
@@ -440,11 +499,29 @@ bool CrossModuleOptimization::canSerializeInstruction(
440
499
[&](SILDeclRef method) {
441
500
if (method.isForeign )
442
501
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
+ }
443
510
});
444
511
return canUse;
445
512
}
446
513
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;
448
525
}
449
526
if (auto *REAI = dyn_cast<RefElementAddrInst>(inst)) {
450
527
// In conservative mode, we don't support class field accesses of non-public
@@ -679,7 +756,9 @@ void CrossModuleOptimization::serializeInstruction(SILInstruction *inst,
679
756
if (canSerializeGlobal (global)) {
680
757
serializeGlobal (global);
681
758
}
682
- if (!hasPublicOrPackageVisibility (global->getLinkage (), M.getSwiftModule ()->serializePackageEnabled ())) {
759
+ if (!hasPublicOrPackageVisibility (
760
+ global->getLinkage (),
761
+ M.getSwiftModule ()->serializePackageEnabled ())) {
683
762
global->setLinkage (SILLinkage::Public);
684
763
}
685
764
return ;
@@ -851,14 +930,7 @@ class CrossModuleOptimizationPass: public SILModuleTransform {
851
930
}
852
931
853
932
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);
862
934
863
935
// Serialize SIL v-tables and witness-tables if package-cmo is enabled.
864
936
CMO.serializeTablesInModule ();
0 commit comments