@@ -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:
@@ -251,12 +253,8 @@ static bool isReferenceSerializeCandidate(SILGlobalVariable *G,
251
253
}
252
254
253
255
// / Select functions in the module which should be serialized.
254
- void CrossModuleOptimization::serializeFunctionsInModule (
256
+ void CrossModuleOptimization::trySerializeFunctions (
255
257
ArrayRef<SILFunction *> functions) {
256
- FunctionFlags canSerializeFlags;
257
-
258
- // The passed functions are already ordered bottom-up so the most
259
- // nested referenced function is checked first.
260
258
for (SILFunction *F : functions) {
261
259
if (isSerializeCandidate (F, M.getOptions ()) || everything) {
262
260
if (canSerializeFunction (F, canSerializeFlags, /* maxDepth*/ 64 )) {
@@ -266,31 +264,81 @@ void CrossModuleOptimization::serializeFunctionsInModule(
266
264
}
267
265
}
268
266
267
+ void CrossModuleOptimization::serializeFunctionsInModule (SILPassManager *manager) {
268
+ // Reorder SIL funtions in the module bottom up so we can serialize
269
+ // the most nested referenced functions first and avoid unnecessary
270
+ // recursive checks.
271
+ BasicCalleeAnalysis *BCA = manager->getAnalysis <BasicCalleeAnalysis>();
272
+ BottomUpFunctionOrder BottomUpOrder (M, BCA);
273
+ auto bottomUpFunctions = BottomUpOrder.getFunctions ();
274
+ trySerializeFunctions (bottomUpFunctions);
275
+ }
276
+
269
277
void CrossModuleOptimization::serializeTablesInModule () {
270
278
if (!M.getSwiftModule ()->serializePackageEnabled ())
271
279
return ;
272
280
273
281
for (const auto &vt : M.getVTables ()) {
274
- if (vt->isNotSerialized ( ) &&
282
+ if (vt->getSerializedKind () != getRightSerializedKind (M ) &&
275
283
vt->getClass ()->getEffectiveAccess () >= AccessLevel::Package) {
276
- vt->setSerializedKind (getRightSerializedKind (M));
284
+ // This checks if a vtable entry is not serialized and attempts to
285
+ // serialize (and its references) if they have the right visibility.
286
+ // This should not be necessary but is added to ensure all applicable
287
+ // symbols are serialized. Whether serialized or not is cached so
288
+ // this check shouldn't be expensive.
289
+ auto unserializedClassMethodRange = llvm::make_filter_range (vt->getEntries (), [&](auto &entry) {
290
+ return entry.getImplementation ()->getSerializedKind () != getRightSerializedKind (M);
291
+ });
292
+ std::vector<SILFunction *> classMethodsToSerialize;
293
+ llvm::transform (unserializedClassMethodRange,
294
+ std::back_inserter (classMethodsToSerialize),
295
+ [&](auto entry) {
296
+ return entry.getImplementation ();
297
+ });
298
+ trySerializeFunctions (classMethodsToSerialize);
299
+
300
+ bool containsInternal = llvm::any_of (classMethodsToSerialize, [&](auto &method) {
301
+ // If the entry is internal, vtable should not be serialized.
302
+ // However, if the entry is not serialized but has the right
303
+ // visibility, it can still be referenced, thus the vtable
304
+ // should serialized.
305
+ return !method->hasValidLinkageForFragileRef (getRightSerializedKind (M));
306
+ });
307
+ if (!containsInternal)
308
+ vt->setSerializedKind (getRightSerializedKind (M));
277
309
}
278
310
}
279
311
312
+ // Witness thunks are not serialized, so serialize them here.
280
313
for (auto &wt : M.getWitnessTables ()) {
281
- if (wt.isNotSerialized () &&
314
+ if (wt.getSerializedKind () != getRightSerializedKind (M) &&
282
315
hasPublicOrPackageVisibility (wt.getLinkage (), /* includePackage*/ true )) {
283
- for (auto &entry : wt.getEntries ()) {
284
- // Witness thunks are not serialized, so serialize them here.
285
- if (entry.getKind () == SILWitnessTable::Method &&
286
- entry.getMethodWitness ().Witness ->isNotSerialized () &&
287
- isSerializeCandidate (entry.getMethodWitness ().Witness ,
288
- M.getOptions ())) {
289
- entry.getMethodWitness ().Witness ->setSerializedKind (getRightSerializedKind (M));
290
- }
291
- }
292
- // Then serialize the witness table itself.
293
- wt.setSerializedKind (getRightSerializedKind (M));
316
+ // This checks if a wtable entry is not serialized and attempts to
317
+ // serialize (and its references) if they have the right visibility.
318
+ // This should not be necessary but is added to ensure all applicable
319
+ // symbols are serialized. Whether serialized or not is cached so
320
+ // this check shouldn't be expensive.
321
+ auto unserializedWTMethodRange = llvm::make_filter_range (wt.getEntries (), [&](auto &entry) {
322
+ return entry.getKind () == SILWitnessTable::Method &&
323
+ entry.getMethodWitness ().Witness ->getSerializedKind () != getRightSerializedKind (M);
324
+ });
325
+ std::vector<SILFunction *> wtMethodsToSerialize;
326
+ llvm::transform (unserializedWTMethodRange,
327
+ std::back_inserter (wtMethodsToSerialize),
328
+ [&](auto entry) {
329
+ return entry.getMethodWitness ().Witness ;
330
+ });
331
+ trySerializeFunctions (wtMethodsToSerialize);
332
+
333
+ bool containsInternal = llvm::any_of (wtMethodsToSerialize, [&](auto &method) {
334
+ // If the entry is internal, wtable should not be serialized.
335
+ // However, if the entry is not serialized but has the right
336
+ // visibility, it can still be referenced, thus the vtable
337
+ // should serialized.
338
+ return !method->hasValidLinkageForFragileRef (getRightSerializedKind (M));
339
+ });
340
+ if (!containsInternal)
341
+ wt.setSerializedKind (getRightSerializedKind (M));
294
342
}
295
343
}
296
344
}
@@ -441,7 +489,13 @@ bool CrossModuleOptimization::canSerializeInstruction(
441
489
return canUse;
442
490
}
443
491
if (auto *MI = dyn_cast<MethodInst>(inst)) {
444
- return !MI->getMember ().isForeign ;
492
+ // If a class_method or witness_method is internal, it can't
493
+ // be serialized.
494
+ auto member = MI->getMember ();
495
+ auto methodAccessScope = member.getDecl ()->getFormalAccessScope (nullptr ,
496
+ /* treatUsableFromInlineAsPublic*/ true );
497
+ return methodAccessScope.isPublicOrPackage () &&
498
+ !member.isForeign ;
445
499
}
446
500
if (auto *REAI = dyn_cast<RefElementAddrInst>(inst)) {
447
501
// In conservative mode, we don't support class field accesses of non-public
@@ -855,14 +909,7 @@ class CrossModuleOptimizationPass: public SILModuleTransform {
855
909
}
856
910
857
911
CrossModuleOptimization CMO (M, conservative, everything);
858
-
859
- // Reorder SIL funtions in the module bottom up so we can serialize
860
- // the most nested referenced functions first and avoid unnecessary
861
- // recursive checks.
862
- BasicCalleeAnalysis *BCA = PM->getAnalysis <BasicCalleeAnalysis>();
863
- BottomUpFunctionOrder BottomUpOrder (M, BCA);
864
- auto BottomUpFunctions = BottomUpOrder.getFunctions ();
865
- CMO.serializeFunctionsInModule (BottomUpFunctions);
912
+ CMO.serializeFunctionsInModule (PM);
866
913
867
914
// Serialize SIL v-tables and witness-tables if package-cmo is enabled.
868
915
CMO.serializeTablesInModule ();
0 commit comments