Skip to content

Commit e3a331f

Browse files
authored
Merge pull request #8422 from slavapestov/thunk-linkage-and-fragility-cleanup
Thunk linkage and fragility cleanup
2 parents 695a8d2 + 91b980b commit e3a331f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+269
-203
lines changed

include/swift/SIL/SILFunction.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,8 @@ class SILFunction
382382
/// Returns true if this function can be inlined into a fragile function
383383
/// body.
384384
bool hasValidLinkageForFragileInline() const {
385-
return isSerialized() || isThunk() == IsReabstractionThunk;
385+
return (isSerialized() == IsSerialized ||
386+
isSerialized() == IsSerializable);
386387
}
387388

388389
/// Returns true if this function can be referenced from a fragile function

lib/AST/Decl.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1878,11 +1878,15 @@ static bool isVersionedInternalDecl(const ValueDecl *VD) {
18781878
if (VD->getAttrs().hasAttribute<VersionedAttr>())
18791879
return true;
18801880

1881-
if (auto *fn = dyn_cast<FuncDecl>(VD))
1882-
if (auto *ASD = fn->getAccessorStorageDecl())
1881+
if (auto *FD = dyn_cast<FuncDecl>(VD))
1882+
if (auto *ASD = FD->getAccessorStorageDecl())
18831883
if (ASD->getAttrs().hasAttribute<VersionedAttr>())
18841884
return true;
18851885

1886+
if (auto *EED = dyn_cast<EnumElementDecl>(VD))
1887+
if (EED->getParentEnum()->getAttrs().hasAttribute<VersionedAttr>())
1888+
return true;
1889+
18861890
return false;
18871891
}
18881892

lib/SIL/Linker.cpp

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -182,41 +182,42 @@ bool SILLinkerVisitor::visitApplyInst(ApplyInst *AI) {
182182
if (!Callee)
183183
return false;
184184

185-
// If the linking mode is not link all, AI is not transparent, and the
186-
// callee is not shared, we don't want to perform any linking.
187-
if (!isLinkAll() && !Callee->isTransparent() &&
188-
!hasSharedVisibility(Callee->getLinkage()))
189-
return false;
185+
if (isLinkAll() ||
186+
hasSharedVisibility(Callee->getLinkage())) {
187+
addFunctionToWorklist(Callee);
188+
return true;
189+
}
190190

191-
// Otherwise we want to try and link in the callee... Add it to the callee
192-
// list and return true.
193-
addFunctionToWorklist(Callee);
194-
return true;
191+
return false;
195192
}
196193

197194
bool SILLinkerVisitor::visitPartialApplyInst(PartialApplyInst *PAI) {
198195
SILFunction *Callee = PAI->getReferencedFunction();
199196
if (!Callee)
200197
return false;
201-
if (!isLinkAll() && !Callee->isTransparent() &&
202-
!hasSharedVisibility(Callee->getLinkage()))
203-
return false;
204198

205-
addFunctionToWorklist(Callee);
206-
return true;
199+
if (isLinkAll() ||
200+
hasSharedVisibility(Callee->getLinkage())) {
201+
addFunctionToWorklist(Callee);
202+
return true;
203+
}
204+
205+
return false;
207206
}
208207

209208
bool SILLinkerVisitor::visitFunctionRefInst(FunctionRefInst *FRI) {
210209
// Needed to handle closures which are no longer applied, but are left
211210
// behind as dead code. This shouldn't happen, but if it does don't get into
212211
// an inconsistent state.
213212
SILFunction *Callee = FRI->getReferencedFunction();
214-
if (!isLinkAll() && !Callee->isTransparent() &&
215-
!hasSharedVisibility(Callee->getLinkage()))
216-
return false;
217213

218-
addFunctionToWorklist(FRI->getReferencedFunction());
219-
return true;
214+
if (isLinkAll() ||
215+
hasSharedVisibility(Callee->getLinkage())) {
216+
addFunctionToWorklist(FRI->getReferencedFunction());
217+
return true;
218+
}
219+
220+
return false;
220221
}
221222

222223
bool SILLinkerVisitor::visitProtocolConformance(

lib/SIL/SILDeclRef.cpp

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -430,24 +430,35 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const {
430430
return SILLinkage::Shared;
431431
moduleContext = moduleContext->getParent();
432432
}
433-
434-
// Currying and calling convention thunks have shared linkage.
435-
if (isThunk())
436-
// If a function declares a @_cdecl name, its native-to-foreign thunk
437-
// is exported with the visibility of the function.
438-
if (!isNativeToForeignThunk() || !d->getAttrs().hasAttribute<CDeclAttr>())
439-
return SILLinkage::Shared;
440-
441-
// Enum constructors are essentially the same as thunks, they are
433+
434+
// Enum constructors and curry thunks either have private or shared
435+
// linkage, dependings are essentially the same as thunks, they are
442436
// emitted by need and have shared linkage.
443-
if (isEnumElement())
437+
if (isEnumElement() || isCurried) {
438+
switch (d->getEffectiveAccess()) {
439+
case Accessibility::Private:
440+
case Accessibility::FilePrivate:
441+
return (forDefinition
442+
? SILLinkage::Private
443+
: SILLinkage::PrivateExternal);
444+
445+
default:
446+
return SILLinkage::Shared;
447+
}
448+
}
449+
450+
// Calling convention thunks have shared linkage.
451+
if (isForeignToNativeThunk())
444452
return SILLinkage::Shared;
445453

446-
// Declarations imported from Clang modules have shared linkage.
447-
const SILLinkage ClangLinkage = SILLinkage::Shared;
454+
// If a function declares a @_cdecl name, its native-to-foreign thunk
455+
// is exported with the visibility of the function.
456+
if (isNativeToForeignThunk() && !d->getAttrs().hasAttribute<CDeclAttr>())
457+
return SILLinkage::Shared;
448458

459+
// Declarations imported from Clang modules have shared linkage.
449460
if (isClangImported())
450-
return ClangLinkage;
461+
return SILLinkage::Shared;
451462

452463
// Otherwise, we have external linkage.
453464
switch (d->getEffectiveAccess()) {
@@ -529,18 +540,30 @@ IsSerialized_t SILDeclRef::isSerialized() const {
529540
if (auto closure = getAbstractClosureExpr())
530541
dc = closure->getLocalContext();
531542
else {
543+
auto *d = getDecl();
532544
dc = getDecl()->getInnermostDeclContext();
533545

534-
// Enum case constructors are serialized if the enum is @_versioned
535-
// or public.
546+
// Enum element constructors are serialized if the enum is
547+
// @_versioned or public.
536548
if (isEnumElement())
537-
if (cast<EnumDecl>(dc)->getEffectiveAccess() >= Accessibility::Public)
549+
if (d->getEffectiveAccess() >= Accessibility::Public)
538550
return IsSerialized;
539551

552+
// Currying thunks are serialized if referenced from an inlinable
553+
// context -- Sema's semantic checks ensure the serialization of
554+
// such a thunk is valid, since it must in turn reference a public
555+
// symbol, or dispatch via class_method or witness_method.
556+
if (isCurried)
557+
if (d->getEffectiveAccess() >= Accessibility::Public)
558+
return IsSerializable;
559+
560+
if (isForeignToNativeThunk())
561+
return IsSerializable;
562+
540563
// The allocating entry point for designated initializers are serialized
541564
// if the class is @_versioned or public.
542565
if (kind == SILDeclRef::Kind::Allocator) {
543-
auto *ctor = cast<ConstructorDecl>(getDecl());
566+
auto *ctor = cast<ConstructorDecl>(d);
544567
if (ctor->isDesignatedInit() &&
545568
ctor->getDeclContext()->getAsClassOrClassExtensionContext()) {
546569
if (ctor->getEffectiveAccess() >= Accessibility::Public &&
@@ -550,6 +573,11 @@ IsSerialized_t SILDeclRef::isSerialized() const {
550573
}
551574
}
552575

576+
// Declarations imported from Clang modules are serialized if
577+
// referenced from an inlineable context.
578+
if (isClangImported())
579+
return IsSerializable;
580+
553581
// Otherwise, ask the AST if we're inside an @_inlineable context.
554582
if (dc->getResilienceExpansion() == ResilienceExpansion::Minimal)
555583
return IsSerialized;

lib/SIL/SILModule.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -347,9 +347,7 @@ SILFunction *SILModule::getOrCreateFunction(SILLocation loc,
347347
IsTransparent_t IsTrans = constant.isTransparent()
348348
? IsTransparent
349349
: IsNotTransparent;
350-
IsSerialized_t IsSer = constant.isSerialized()
351-
? IsSerialized
352-
: IsNotSerialized;
350+
IsSerialized_t IsSer = constant.isSerialized();
353351

354352
EffectsKind EK = constant.hasEffectsAttribute()
355353
? constant.getEffectsAttribute()

lib/SIL/SILVerifier.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3903,18 +3903,6 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
39033903
void visitSILFunction(SILFunction *F) {
39043904
PrettyStackTraceSILFunction stackTrace("verifying", F);
39053905

3906-
if (F->getLinkage() == SILLinkage::PrivateExternal) {
3907-
// FIXME: uncomment these checks.
3908-
// <rdar://problem/18635841> SILGen can create non-fragile external
3909-
// private_external declarations
3910-
//
3911-
// assert(!isExternalDeclaration() &&
3912-
// "PrivateExternal should not be an external declaration");
3913-
// assert(isFragile() &&
3914-
// "PrivateExternal should be fragile (otherwise, how did it appear "
3915-
// "in this module?)");
3916-
}
3917-
39183906
CanSILFunctionType FTy = F->getLoweredFunctionType();
39193907
verifySILFunctionType(FTy);
39203908

lib/SILGen/SILGenThunk.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,9 @@ SILFunction *SILGenModule::getDynamicThunk(SILDeclRef constant,
3838
// Mangle the constant with a _TTD header.
3939
auto name = constant.mangle(SILDeclRef::ManglingKind::DynamicThunk);
4040

41-
IsSerialized_t isSerialized = IsNotSerialized;
42-
if (makeModuleFragile)
43-
isSerialized = IsSerialized;
44-
if (constant.isSerialized())
45-
isSerialized = IsSerialized;
4641
auto F = M.getOrCreateFunction(constant.getDecl(), name, SILLinkage::Shared,
47-
constantInfo.getSILType().castTo<SILFunctionType>(),
48-
IsBare, IsTransparent, isSerialized, IsThunk);
42+
constantInfo.SILFnType, IsBare, IsTransparent,
43+
IsSerializable, IsThunk);
4944

5045
if (F->empty()) {
5146
// Emit the thunk if we haven't yet.
@@ -283,6 +278,6 @@ getOrCreateReabstractionThunk(GenericEnvironment *genericEnv,
283278

284279
auto loc = RegularLocation::getAutoGeneratedLocation();
285280
return M.getOrCreateSharedFunction(loc, name, thunkType, IsBare,
286-
IsTransparent, Serialized,
281+
IsTransparent, IsSerializable,
287282
IsReabstractionThunk);
288283
}

lib/SILGen/SILGenType.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,9 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
640640
IsSerialized_t isSerialized = IsNotSerialized;
641641
if (makeModuleFragile)
642642
isSerialized = IsSerialized;
643-
if (witnessRef.isSerialized())
643+
if (witnessRef.isSerialized() &&
644+
(hasSharedVisibility(linkage) ||
645+
hasPublicVisibility(linkage)))
644646
isSerialized = IsSerialized;
645647

646648
auto *f = M.createFunction(

lib/Serialization/SerializeSIL.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -270,13 +270,10 @@ void SILSerializer::addReferencedSILFunction(const SILFunction *F,
270270
return;
271271
}
272272

273-
// If we referenced a non-fragile shared function from a fragile
274-
// function, serialize it too. In practice, it will either be a
275-
// thunk, or an optimizer specialization. In both cases, we don't
276-
// have enough information at the time we emit the function to
277-
// know if it should be marked fragile or not.
278273
if (F->getLinkage() == SILLinkage::Shared && !DeclOnly) {
279-
assert(F->isThunk() == IsReabstractionThunk || F->hasForeignBody());
274+
assert(F->isSerialized() == IsSerializable ||
275+
F->hasForeignBody());
276+
280277
FuncsToEmit[F] = false;
281278
Worklist.push_back(F);
282279
return;
@@ -1996,7 +1993,7 @@ bool SILSerializer::shouldEmitFunctionBody(const SILFunction *F,
19961993
return true;
19971994

19981995
// If F is serialized, we should always emit its body.
1999-
if (F->isSerialized())
1996+
if (F->isSerialized() == IsSerialized)
20001997
return true;
20011998

20021999
return false;

test/ClangImporter/static_inline.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// RUN: %FileCheck < %t/test.sil %s
77
// RUN: %target-swift-frontend -parse-as-library -module-name=test -O -emit-ir %t/test.sil -import-objc-header %S/Inputs/static_inline.h | %FileCheck --check-prefix=CHECK-IR %s
88

9-
// CHECK: sil shared [clang c_inline_func] @c_inline_func : $@convention(c) (Int32) -> Int32
9+
// CHECK: sil shared [serializable] [clang c_inline_func] @c_inline_func : $@convention(c) (Int32) -> Int32
1010

1111
// CHECK-IR-LABEL: define{{.*}} i32 @_T04test6testits5Int32VAD1x_tF(i32)
1212
// CHECK-IR: = add {{.*}}, 27

test/SILGen/c_materializeForSet_linkage.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ extension NSReferencePoint: Pointable {}
1616
// Make sure synthesized materializeForSet and its callbacks have shared linkage
1717
// for properties imported from Clang
1818

19-
// CHECK-LABEL: sil shared [transparent] [serialized] @_T0SC7NSPointV1xSffm
20-
// CHECK-LABEL: sil shared [transparent] [serialized] @_T0SC7NSPointV1ySffm
19+
// CHECK-LABEL: sil shared [transparent] [serializable] @_T0SC7NSPointV1xSffm
20+
// CHECK-LABEL: sil shared [transparent] [serializable] @_T0SC7NSPointV1ySffm
2121

22-
// CHECK-LABEL: sil shared @_T0So16NSReferencePointC1xSffmytfU_
23-
// CHECK-LABEL: sil shared @_T0So16NSReferencePointC1xSffm
22+
// CHECK-LABEL: sil shared [serializable] @_T0So16NSReferencePointC1xSffmytfU_
23+
// CHECK-LABEL: sil shared [serializable] @_T0So16NSReferencePointC1xSffm
2424

25-
// CHECK-LABEL: sil shared @_T0So16NSReferencePointC1ySffmytfU_
26-
// CHECK-LABEL: sil shared @_T0So16NSReferencePointC1ySffm
25+
// CHECK-LABEL: sil shared [serializable] @_T0So16NSReferencePointC1ySffmytfU_
26+
// CHECK-LABEL: sil shared [serializable] @_T0So16NSReferencePointC1ySffm

test/SILGen/cf.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ protocol Impedance {
6565

6666
extension CCImpedance: Impedance {}
6767

68-
// CHECK-LABEL: sil hidden [transparent] [serialized] [thunk] @_T0SC11CCImpedanceV2cf9ImpedanceA2cDP4real9ComponentQzfgTW
69-
// CHECK-LABEL: sil shared [transparent] [serialized] @_T0SC11CCImpedanceV4realSdfg
70-
// CHECK-LABEL: sil hidden [transparent] [serialized] [thunk] @_T0SC11CCImpedanceV2cf9ImpedanceA2cDP4imag9ComponentQzfgTW
71-
// CHECK-LABEL: sil shared [transparent] [serialized] @_T0SC11CCImpedanceV4imagSdfg
68+
// CHECK-LABEL: sil hidden [transparent] [thunk] @_T0SC11CCImpedanceV2cf9ImpedanceA2cDP4real9ComponentQzfgTW
69+
// CHECK-LABEL: sil shared [transparent] [serializable] @_T0SC11CCImpedanceV4realSdfg
70+
// CHECK-LABEL: sil hidden [transparent] [thunk] @_T0SC11CCImpedanceV2cf9ImpedanceA2cDP4imag9ComponentQzfgTW
71+
// CHECK-LABEL: sil shared [transparent] [serializable] @_T0SC11CCImpedanceV4imagSdfg
7272

7373
class MyMagnetism : CCMagnetismModel {
7474
// CHECK-LABEL: sil hidden [thunk] @_T02cf11MyMagnetismC15getRefrigerator{{[_0-9a-zA-Z]*}}FTo : $@convention(objc_method) (MyMagnetism) -> @autoreleased CCRefrigerator

test/SILGen/cf_members.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,37 +202,37 @@ public func foo(_ x: Double) {
202202
}
203203
// CHECK: } // end sil function '_T010cf_members3foo{{[_0-9a-zA-Z]*}}F'
204204

205-
// CHECK-LABEL: sil shared [thunk] @_T0SC7Struct1VABSd5value_tcfCTO
205+
// CHECK-LABEL: sil shared [serializable] [thunk] @_T0SC7Struct1VABSd5value_tcfCTO
206206
// CHECK: bb0([[X:%.*]] : $Double, [[SELF:%.*]] : $@thin Struct1.Type):
207207
// CHECK: [[CFUNC:%.*]] = function_ref @IAMStruct1CreateSimple
208208
// CHECK: [[RET:%.*]] = apply [[CFUNC]]([[X]])
209209
// CHECK: return [[RET]]
210210

211-
// CHECK-LABEL: sil shared [thunk] @_T0SC7Struct1V9translateABSd7radians_tFTO
211+
// CHECK-LABEL: sil shared [serializable] [thunk] @_T0SC7Struct1V9translateABSd7radians_tFTO
212212
// CHECK: bb0([[X:%.*]] : $Double, [[SELF:%.*]] : $Struct1):
213213
// CHECK: store [[SELF]] to [trivial] [[TMP:%.*]] :
214214
// CHECK: [[CFUNC:%.*]] = function_ref @IAMStruct1Rotate
215215
// CHECK: [[RET:%.*]] = apply [[CFUNC]]([[TMP]], [[X]])
216216
// CHECK: return [[RET]]
217217

218-
// CHECK-LABEL: sil shared [thunk] @_T0SC7Struct1V5scaleABSdFTO
218+
// CHECK-LABEL: sil shared [serializable] [thunk] @_T0SC7Struct1V5scaleABSdFTO
219219
// CHECK: bb0([[X:%.*]] : $Double, [[SELF:%.*]] : $Struct1):
220220
// CHECK: [[CFUNC:%.*]] = function_ref @IAMStruct1Scale
221221
// CHECK: [[RET:%.*]] = apply [[CFUNC]]([[SELF]], [[X]])
222222
// CHECK: return [[RET]]
223223

224-
// CHECK-LABEL: sil shared [thunk] @_T0SC7Struct1V12staticMethods5Int32VyFZTO
224+
// CHECK-LABEL: sil shared [serializable] [thunk] @_T0SC7Struct1V12staticMethods5Int32VyFZTO
225225
// CHECK: bb0([[SELF:%.*]] : $@thin Struct1.Type):
226226
// CHECK: [[CFUNC:%.*]] = function_ref @IAMStruct1StaticMethod
227227
// CHECK: [[RET:%.*]] = apply [[CFUNC]]()
228228
// CHECK: return [[RET]]
229229

230-
// CHECK-LABEL: sil shared [thunk] @_T0SC7Struct1V13selfComesLastySd1x_tFTO
230+
// CHECK-LABEL: sil shared [serializable] [thunk] @_T0SC7Struct1V13selfComesLastySd1x_tFTO
231231
// CHECK: bb0([[X:%.*]] : $Double, [[SELF:%.*]] : $Struct1):
232232
// CHECK: [[CFUNC:%.*]] = function_ref @IAMStruct1SelfComesLast
233233
// CHECK: apply [[CFUNC]]([[X]], [[SELF]])
234234

235-
// CHECK-LABEL: sil shared [thunk] @_T0SC7Struct1V14selfComesThirdys5Int32V1a_Sf1bSd1xtFTO
235+
// CHECK-LABEL: sil shared [serializable] [thunk] @_T0SC7Struct1V14selfComesThirdys5Int32V1a_Sf1bSd1xtFTO
236236
// CHECK: bb0([[X:%.*]] : $Int32, [[Y:%.*]] : $Float, [[Z:%.*]] : $Double, [[SELF:%.*]] : $Struct1):
237237
// CHECK: [[CFUNC:%.*]] = function_ref @IAMStruct1SelfComesThird
238238
// CHECK: apply [[CFUNC]]([[X]], [[Y]], [[SELF]], [[Z]])

0 commit comments

Comments
 (0)