@@ -71,6 +71,7 @@ class CrossModuleOptimization {
71
71
: M(M), conservative(conservative), everything(everything) { }
72
72
73
73
void serializeFunctionsInModule ();
74
+ void serializeTablesInModule ();
74
75
75
76
private:
76
77
bool canSerializeFunction (SILFunction *function,
@@ -172,6 +173,14 @@ static bool isVisible(AccessLevel accessLevel, SILOptions options) {
172
173
return accessLevel == AccessLevel::Public;
173
174
}
174
175
176
+ static bool hasSerializableVisibility (SILLinkage linkage, bool isDefinition,
177
+ SILOptions options) {
178
+ if (options.EnableSerializePackage )
179
+ return (hasPublicOrPackageVisibility (linkage, /* includePackage*/ true ) ||
180
+ (hasSharedVisibility (linkage) && isDefinition));
181
+ return hasPublicVisibility (linkage);
182
+ }
183
+
175
184
// / Select functions in the module which should be serialized.
176
185
void CrossModuleOptimization::serializeFunctionsInModule () {
177
186
@@ -188,6 +197,40 @@ void CrossModuleOptimization::serializeFunctionsInModule() {
188
197
}
189
198
}
190
199
200
+ void CrossModuleOptimization::serializeTablesInModule () {
201
+ if (!M.getOptions ().EnableSerializePackage )
202
+ return ;
203
+
204
+ for (const auto &vt : M.getVTables ()) {
205
+ if (!vt->isSerialized () &&
206
+ vt->getClass ()->getEffectiveAccess () >= AccessLevel::Package) {
207
+ vt->setSerialized (IsSerialized);
208
+ }
209
+ }
210
+
211
+ for (auto &wt : M.getWitnessTables ()) {
212
+ if (!wt.isSerialized () && hasPublicOrPackageVisibility (
213
+ wt.getLinkage (), /* includePackage*/ true )) {
214
+ for (auto &entry : wt.getEntries ()) {
215
+ // Entries in witness table with package linkage are not serialized
216
+ // (by default only entries in public witness table are; \see
217
+ // SILWitnessTable::conformanceIsSerialized), so serialize them here
218
+ // if package-cmo is enabled (otherwise nil).
219
+ if (entry.getKind () == SILWitnessTable::Method &&
220
+ !entry.getMethodWitness ().Witness ->isSerialized () &&
221
+ hasSerializableVisibility (
222
+ entry.getMethodWitness ().Witness ->getLinkage (),
223
+ entry.getMethodWitness ().Witness ->isDefinition (),
224
+ M.getOptions ())) {
225
+ entry.getMethodWitness ().Witness ->setSerialized (IsSerialized);
226
+ }
227
+ }
228
+ // Then serialize the witness table itself.
229
+ wt.setSerialized (IsSerialized);
230
+ }
231
+ }
232
+ }
233
+
191
234
// / Recursively walk the call graph and select functions to be serialized.
192
235
// /
193
236
// / The results are stored in \p canSerializeFlags and the result for \p
@@ -280,9 +323,16 @@ bool CrossModuleOptimization::canSerializeInstruction(SILInstruction *inst,
280
323
// public functions, because that can increase code size. E.g. if the
281
324
// function is completely inlined afterwards.
282
325
// Also, when emitting TBD files, we cannot introduce a new public symbol.
283
- if ((conservative || M.getOptions ().emitTBD ) &&
284
- !hasPublicOrPackageVisibility (callee->getLinkage (), M.getOptions ().EnableSerializePackage )) {
285
- return false ;
326
+ if (conservative || M.getOptions ().emitTBD ) {
327
+ // In package-cmo, allow serializing this inst if its referenced function
328
+ // is a definition with a shared linkage or has a package/public linkage.
329
+ // For example, `public func foo() { print("") }` is a function with
330
+ // a public linkage which references `print`; the definition of `print`
331
+ // should have a shared linkage and be allowed to be serialized, so that
332
+ // `foo` could be serialized.
333
+ if (!hasSerializableVisibility (callee->getLinkage (),
334
+ callee->isDefinition (), M.getOptions ()))
335
+ return false ;
286
336
}
287
337
288
338
// In some project configurations imported C functions are not necessarily
@@ -306,7 +356,8 @@ bool CrossModuleOptimization::canSerializeInstruction(SILInstruction *inst,
306
356
if (auto *GAI = dyn_cast<GlobalAddrInst>(inst)) {
307
357
SILGlobalVariable *global = GAI->getReferencedGlobal ();
308
358
if ((conservative || M.getOptions ().emitTBD ) &&
309
- !hasPublicOrPackageVisibility (global->getLinkage (), M.getOptions ().EnableSerializePackage )) {
359
+ !hasSerializableVisibility (global->getLinkage (), global->isDefinition (),
360
+ M.getOptions ())) {
310
361
return false ;
311
362
}
312
363
@@ -354,7 +405,9 @@ bool CrossModuleOptimization::canSerializeGlobal(SILGlobalVariable *global) {
354
405
// function is completely inlined afterwards.
355
406
// Also, when emitting TBD files, we cannot introduce a new public symbol.
356
407
if ((conservative || M.getOptions ().emitTBD ) &&
357
- !hasPublicOrPackageVisibility (referencedFunc->getLinkage (), M.getOptions ().EnableSerializePackage )) {
408
+ !hasSerializableVisibility (referencedFunc->getLinkage (),
409
+ referencedFunc->isDefinition (),
410
+ M.getOptions ())) {
358
411
return false ;
359
412
}
360
413
@@ -374,7 +427,7 @@ bool CrossModuleOptimization::canSerializeType(SILType type) {
374
427
[this ](Type rawSubType) {
375
428
CanType subType = rawSubType->getCanonicalType ();
376
429
if (NominalTypeDecl *subNT = subType->getNominalOrBoundGenericNominal ()) {
377
-
430
+
378
431
if (conservative && subNT->getEffectiveAccess () < AccessLevel::Package) {
379
432
return true ;
380
433
}
@@ -482,6 +535,12 @@ bool CrossModuleOptimization::shouldSerialize(SILFunction *function) {
482
535
483
536
if (function->getLinkage () == SILLinkage::Shared)
484
537
return true ;
538
+ } else if (hasSerializableVisibility (function->getLinkage (),
539
+ function->isDefinition (),
540
+ function->getModule ().getOptions ())) {
541
+ // If package-cmo is enabled, we should not limit the amount of inlining
542
+ // as checked with CMOFunctionSizeLimit below.
543
+ return true ;
485
544
}
486
545
487
546
// Also serialize "small" non-generic functions.
@@ -503,7 +562,7 @@ void CrossModuleOptimization::serializeFunction(SILFunction *function,
503
562
const FunctionFlags &canSerializeFlags) {
504
563
if (function->isSerialized ())
505
564
return ;
506
-
565
+
507
566
if (!canSerializeFlags.lookup (function))
508
567
return ;
509
568
@@ -699,7 +758,10 @@ class CrossModuleOptimizationPass: public SILModuleTransform {
699
758
void run () override {
700
759
701
760
auto &M = *getModule ();
702
- if (M.getSwiftModule ()->isResilient ())
761
+ if (M.getSwiftModule ()->isResilient () &&
762
+ // FIXME: need to properly lower type when this is enabled
763
+ // else leads to assert fail.
764
+ !M.getOptions ().EnableSerializePackage )
703
765
return ;
704
766
if (!M.isWholeModule ())
705
767
return ;
@@ -727,6 +789,7 @@ class CrossModuleOptimizationPass: public SILModuleTransform {
727
789
728
790
CrossModuleOptimization CMO (M, conservative, everything);
729
791
CMO.serializeFunctionsInModule ();
792
+ CMO.serializeTablesInModule ();
730
793
}
731
794
};
732
795
0 commit comments