@@ -49,7 +49,11 @@ class CrossModuleSerializationSetup {
49
49
}
50
50
}
51
51
52
- bool setUpForSerialization (SILFunction *F);
52
+ bool canUseFromInline (SILFunction *F, bool lookIntoThunks);
53
+
54
+ bool canSerialize (SILFunction *F, bool lookIntoThunks);
55
+
56
+ void setUpForSerialization (SILFunction *F);
53
57
54
58
void prepareInstructionForSerialization (SILInstruction *inst);
55
59
@@ -67,27 +71,6 @@ class CrossModuleSerializationSetup {
67
71
void scanModule ();
68
72
};
69
73
70
- static bool canUseFromInline (SILFunction *F) {
71
- if (!F)
72
- return false ;
73
-
74
- switch (F->getLinkage ()) {
75
- case SILLinkage::PublicNonABI:
76
- case SILLinkage::Shared:
77
- return F->isSerialized () != IsNotSerialized;
78
- case SILLinkage::Public:
79
- case SILLinkage::Hidden:
80
- case SILLinkage::Private:
81
- case SILLinkage::PublicExternal:
82
- case SILLinkage::SharedExternal:
83
- case SILLinkage::PrivateExternal:
84
- case SILLinkage::HiddenExternal:
85
- break ;
86
- }
87
-
88
- return true ;
89
- }
90
-
91
74
// / Visitor for making used types of an intruction inlinable.
92
75
// /
93
76
// / We use the SILCloner for visiting types, though it sucks that we allocate
@@ -253,11 +236,27 @@ prepareInstructionForSerialization(SILInstruction *inst) {
253
236
void CrossModuleSerializationSetup::handleReferencedFunction (SILFunction *func) {
254
237
if (!func->isDefinition () || func->isAvailableExternally ())
255
238
return ;
239
+ if (func->getLinkage () == SILLinkage::Shared) {
240
+ assert (func->isThunk () != IsNotThunk &&
241
+ " only thunks are accepted to have shared linkage" );
242
+ assert (canSerialize (func, /* lookIntoThunks*/ false ) &&
243
+ " we should already have checked that the thunk is serializable" );
244
+
245
+ if (func->isSerialized () == IsSerialized)
246
+ return ;
247
+
248
+ // We cannot make shared functions "usableFromInline", i.e. make them Public
249
+ // because this could result in duplicate-symbol errors. Instead we make
250
+ // them "@alwaysEmitIntoClient"
251
+ setUpForSerialization (func);
252
+ return ;
253
+ }
256
254
if (shouldSerialize (func)) {
257
255
addToWorklistIfNotHandled (func);
258
- } else {
259
- makeFunctionUsableFromInline (func);
256
+ return ;
260
257
}
258
+ makeFunctionUsableFromInline (func);
259
+ return ;
261
260
}
262
261
263
262
void CrossModuleSerializationSetup::handleReferencedMethod (SILDeclRef method) {
@@ -268,23 +267,24 @@ void CrossModuleSerializationSetup::handleReferencedMethod(SILDeclRef method) {
268
267
M.addExternallyVisibleDecl (getBaseMethod (methodDecl));
269
268
}
270
269
271
- // / Setup the function \p param F for serialization and put callees onto the
272
- // / worklist for further processing.
270
+ // / Check if the function \p F can be serialized.
273
271
// /
274
- // / Returns false in case this is not possible for some reason.
275
- bool CrossModuleSerializationSetup::setUpForSerialization (SILFunction *F) {
272
+ // / If \p lookIntoThunks is true, function_ref instructions of shared
273
+ // / thunks are also accepted.
274
+ bool CrossModuleSerializationSetup::canSerialize (SILFunction *F,
275
+ bool lookIntoThunks) {
276
276
// First step: check if serializing F is even possible.
277
277
for (SILBasicBlock &block : *F) {
278
278
for (SILInstruction &inst : block) {
279
279
if (auto *FRI = dyn_cast<FunctionRefBaseInst>(&inst)) {
280
280
SILFunction *callee = FRI->getReferencedFunctionOrNull ();
281
- if (!canUseFromInline (callee))
281
+ if (!canUseFromInline (callee, lookIntoThunks ))
282
282
return false ;
283
283
} else if (auto *KPI = dyn_cast<KeyPathInst>(&inst)) {
284
284
bool canUse = true ;
285
285
KPI->getPattern ()->visitReferencedFunctionsAndMethods (
286
286
[&](SILFunction *func) {
287
- if (!canUseFromInline (func))
287
+ if (!canUseFromInline (func, lookIntoThunks ))
288
288
canUse = false ;
289
289
},
290
290
[](SILDeclRef method) { });
@@ -293,6 +293,45 @@ bool CrossModuleSerializationSetup::setUpForSerialization(SILFunction *F) {
293
293
}
294
294
}
295
295
}
296
+ return true ;
297
+ }
298
+
299
+ // / Returns true if the function \p func can be used from a serialized function.
300
+ // /
301
+ // / If \p lookIntoThunks is true, serializable shared thunks are also accepted.
302
+ bool CrossModuleSerializationSetup::canUseFromInline (SILFunction *func,
303
+ bool lookIntoThunks) {
304
+ if (!func)
305
+ return false ;
306
+
307
+ switch (func->getLinkage ()) {
308
+ case SILLinkage::PublicNonABI:
309
+ return func->isSerialized () != IsNotSerialized;
310
+ case SILLinkage::Shared:
311
+ if (func->isThunk () != IsNotThunk && lookIntoThunks &&
312
+ // Don't recursively lookIntoThunks to avoid infinite loops.
313
+ canSerialize (func, /* lookIntoThunks*/ false )) {
314
+ return true ;
315
+ }
316
+ return false ;
317
+ case SILLinkage::Public:
318
+ case SILLinkage::Hidden:
319
+ case SILLinkage::Private:
320
+ case SILLinkage::PublicExternal:
321
+ case SILLinkage::SharedExternal:
322
+ case SILLinkage::PrivateExternal:
323
+ case SILLinkage::HiddenExternal:
324
+ break ;
325
+ }
326
+ return true ;
327
+ }
328
+
329
+ // / Setup the function \p param F for serialization and put callees onto the
330
+ // / worklist for further processing.
331
+ // /
332
+ // / Returns false in case this is not possible for some reason.
333
+ void CrossModuleSerializationSetup::setUpForSerialization (SILFunction *F) {
334
+ assert (F->isSerialized () != IsSerialized);
296
335
297
336
// Second step: go through all instructions and prepare them for
298
337
// for serialization.
@@ -301,7 +340,14 @@ bool CrossModuleSerializationSetup::setUpForSerialization(SILFunction *F) {
301
340
prepareInstructionForSerialization (&inst);
302
341
}
303
342
}
304
- return true ;
343
+ F->setSerialized (IsSerialized);
344
+
345
+ // As a code size optimization, make serialized functions
346
+ // @alwaysEmitIntoClient.
347
+ // Also, for shared thunks it's required to make them @alwaysEmitIntoClient.
348
+ // SILLinkage::Public would not work for shared functions, because it could
349
+ // result in duplicate-symbol linker errors.
350
+ F->setLinkage (SILLinkage::PublicNonABI);
305
351
}
306
352
307
353
// / Select functions in the module which should be serialized.
@@ -319,12 +365,8 @@ void CrossModuleSerializationSetup::scanModule() {
319
365
// Decide whether we want to serialize the function.
320
366
if (shouldSerialize (F)) {
321
367
// Try to serialize.
322
- if (setUpForSerialization (F)) {
323
- F->setSerialized (IsSerialized);
324
-
325
- // As a code size optimization, make serialized functions
326
- // @alwaysEmitIntoClient.
327
- F->setLinkage (SILLinkage::PublicNonABI);
368
+ if (canSerialize (F, /* lookIntoThunks*/ true )) {
369
+ setUpForSerialization (F);
328
370
} else {
329
371
// If for some reason the function cannot be serialized, we mark it as
330
372
// usable-from-inline.
0 commit comments