Skip to content

Commit e99f537

Browse files
authored
Merge pull request #6630 from eeckstein/fix-dead-method-elim
2 parents 15ff133 + 1eb3a05 commit e99f537

File tree

20 files changed

+193
-112
lines changed

20 files changed

+193
-112
lines changed

docs/SIL.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,7 @@ VTables
10281028
decl ::= sil-vtable
10291029
sil-vtable ::= 'sil_vtable' identifier '{' sil-vtable-entry* '}'
10301030

1031-
sil-vtable-entry ::= sil-decl-ref ':' sil-function-name
1031+
sil-vtable-entry ::= sil-decl-ref ':' sil-linkage? sil-function-name
10321032

10331033
SIL represents dynamic dispatch for class methods using the `class_method`_,
10341034
`super_method`_, and `dynamic_method`_ instructions. The potential destinations
@@ -1084,6 +1084,9 @@ visible through that class (in the example above, ``B``'s vtable references
10841084
that can be used to look up overridden methods in the SIL vtable for a derived
10851085
class (such as ``C.bas`` in ``C``'s vtable).
10861086

1087+
In case the SIL function is a thunk, the function name is preceded with the
1088+
linkage of the original implementing function.
1089+
10871090
Witness Tables
10881091
~~~~~~~~~~~~~~
10891092
::

include/swift/SIL/SILVTable.h

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,28 @@ class SILVTable : public llvm::ilist_node<SILVTable>,
4242
public:
4343
// TODO: Entry should include substitutions needed to invoke an overridden
4444
// generic base class method.
45-
using Pair = std::pair<SILDeclRef, SILFunction*>;
45+
struct Entry {
46+
47+
Entry() : Implementation(nullptr), Linkage(SILLinkage::Private) { }
48+
49+
Entry(SILDeclRef Method, SILFunction *Implementation, SILLinkage Linkage) :
50+
Method(Method), Implementation(Implementation), Linkage(Linkage) { }
51+
52+
/// The declaration reference to the least-derived method visible through
53+
/// the class.
54+
SILDeclRef Method;
55+
56+
/// The function which implements the method for the class.
57+
SILFunction *Implementation;
58+
59+
/// The linkage of the implementing function.
60+
///
61+
/// This is usuallly the same as
62+
/// stripExternalFromLinkage(Implementation->getLinkage())
63+
/// except if Implementation is a thunk (which has private or shared
64+
/// linkage).
65+
SILLinkage Linkage;
66+
};
4667

4768
// Disallow copying into temporary objects.
4869
SILVTable(const SILVTable &other) = delete;
@@ -56,10 +77,10 @@ class SILVTable : public llvm::ilist_node<SILVTable>,
5677
unsigned NumEntries;
5778

5879
/// Tail-allocated SILVTable entries.
59-
Pair Entries[1];
80+
Entry Entries[1];
6081

6182
/// Private constructor. Create SILVTables by calling SILVTable::create.
62-
SILVTable(ClassDecl *c, ArrayRef<Pair> entries);
83+
SILVTable(ClassDecl *c, ArrayRef<Entry> entries);
6384

6485
public:
6586
~SILVTable();
@@ -68,24 +89,24 @@ class SILVTable : public llvm::ilist_node<SILVTable>,
6889
/// The SILDeclRef keys should reference the most-overridden members available
6990
/// through the class.
7091
static SILVTable *create(SILModule &M, ClassDecl *Class,
71-
ArrayRef<Pair> Entries);
92+
ArrayRef<Entry> Entries);
7293

7394
/// Return the class that the vtable represents.
7495
ClassDecl *getClass() const { return Class; }
7596

7697
/// Return all of the method entries.
77-
ArrayRef<Pair> getEntries() const { return {Entries, NumEntries}; }
98+
ArrayRef<Entry> getEntries() const { return {Entries, NumEntries}; }
7899

79100
/// Look up the implementation function for the given method.
80101
SILFunction *getImplementation(SILModule &M, SILDeclRef method) const;
81102

82103
/// Removes entries from the vtable.
83104
/// \p predicate Returns true if the passed entry should be removed.
84105
template <typename Predicate> void removeEntries_if(Predicate predicate) {
85-
Pair *end = std::remove_if(Entries, Entries + NumEntries,
86-
[&](Pair &entry) -> bool {
106+
Entry *end = std::remove_if(Entries, Entries + NumEntries,
107+
[&](Entry &entry) -> bool {
87108
if (predicate(entry)) {
88-
entry.second->decrementRefCount();
109+
entry.Implementation->decrementRefCount();
89110
removeFromVTableCache(entry);
90111
return true;
91112
}
@@ -102,7 +123,7 @@ class SILVTable : public llvm::ilist_node<SILVTable>,
102123
void dump() const;
103124

104125
private:
105-
void removeFromVTableCache(Pair &entry);
126+
void removeFromVTableCache(Entry &entry);
106127
};
107128

108129
} // end swift namespace

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
5454
/// in source control, you should also update the comment to briefly
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
57-
const uint16_t VERSION_MINOR = 304; // Last change: Archetype generic env
57+
const uint16_t VERSION_MINOR = 305; // Last change: linkage in SILVTable::Entry
5858

5959
using DeclID = PointerEmbeddedInt<unsigned, 31>;
6060
using DeclIDField = BCFixed<31>;

lib/Parse/ParseSIL.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4272,7 +4272,7 @@ bool Parser::parseSILVTable() {
42724272
Lexer::SILBodyRAII Tmp(*L);
42734273
Scope S(this, ScopeKind::TopLevel);
42744274
// Parse the entry list.
4275-
std::vector<SILVTable::Pair> vtableEntries;
4275+
std::vector<SILVTable::Entry> vtableEntries;
42764276
if (Tok.isNot(tok::r_brace)) {
42774277
do {
42784278
SILDeclRef Ref;
@@ -4281,10 +4281,12 @@ bool Parser::parseSILVTable() {
42814281
if (VTableState.parseSILDeclRef(Ref))
42824282
return true;
42834283
SILFunction *Func = nullptr;
4284+
Optional<SILLinkage> Linkage = SILLinkage::Private;
42844285
if (Tok.is(tok::kw_nil)) {
42854286
consumeToken();
42864287
} else {
42874288
if (parseToken(tok::colon, diag::expected_sil_vtable_colon) ||
4289+
parseSILLinkage(Linkage, *this) ||
42884290
VTableState.parseSILIdentifier(FuncName, FuncLoc,
42894291
diag::expected_sil_value_name))
42904292
return true;
@@ -4293,8 +4295,10 @@ bool Parser::parseSILVTable() {
42934295
diagnose(FuncLoc, diag::sil_vtable_func_not_found, FuncName);
42944296
return true;
42954297
}
4298+
if (!Linkage)
4299+
Linkage = stripExternalFromLinkage(Func->getLinkage());
42964300
}
4297-
vtableEntries.emplace_back(Ref, Func);
4301+
vtableEntries.emplace_back(Ref, Func, Linkage.getValue());
42984302
} while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof));
42994303
}
43004304

lib/SIL/Linker.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ SILVTable *SILLinkerVisitor::processClassDecl(const ClassDecl *C) {
139139
// Otherwise, add all the vtable functions in Vtbl to the function
140140
// processing list...
141141
for (auto &E : Vtbl->getEntries())
142-
Worklist.push_back(E.second);
142+
Worklist.push_back(E.Implementation);
143143

144144
// And then transitively deserialize all SIL referenced by those functions.
145145
process();
@@ -162,9 +162,9 @@ bool SILLinkerVisitor::linkInVTable(ClassDecl *D) {
162162
// for processing.
163163
bool Result = false;
164164
for (auto P : Vtbl->getEntries()) {
165-
if (P.second->isExternalDeclaration()) {
165+
if (P.Implementation->isExternalDeclaration()) {
166166
Result = true;
167-
addFunctionToWorklist(P.second);
167+
addFunctionToWorklist(P.Implementation);
168168
}
169169
}
170170
return Result;

lib/SIL/SILPrinter.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2141,9 +2141,14 @@ void SILVTable::print(llvm::raw_ostream &OS, bool Verbose) const {
21412141
OS << "sil_vtable " << getClass()->getName() << " {\n";
21422142
for (auto &entry : getEntries()) {
21432143
OS << " ";
2144-
entry.first.print(OS);
2145-
OS << ": " << entry.second->getName()
2146-
<< "\t// " << demangleSymbol(entry.second->getName()) << "\n";
2144+
entry.Method.print(OS);
2145+
OS << ": ";
2146+
if (entry.Linkage !=
2147+
stripExternalFromLinkage(entry.Implementation->getLinkage())) {
2148+
OS << getLinkageString(entry.Linkage);
2149+
}
2150+
OS << entry.Implementation->getName()
2151+
<< "\t// " << demangleSymbol(entry.Implementation->getName()) << "\n";
21472152
}
21482153
OS << "}\n\n";
21492154
}

lib/SIL/SILVTable.cpp

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,18 @@
2424
using namespace swift;
2525

2626
SILVTable *SILVTable::create(SILModule &M, ClassDecl *Class,
27-
ArrayRef<Pair> Entries) {
27+
ArrayRef<Entry> Entries) {
2828
// SILVTable contains one element declared in Entries. We must allocate
2929
// space for it, because its default ctor will write to it.
3030
unsigned NumTailElements = std::max((unsigned)Entries.size(), 1U)-1;
31-
void *buf = M.allocate(sizeof(SILVTable) + sizeof(Pair) * NumTailElements,
31+
void *buf = M.allocate(sizeof(SILVTable) + sizeof(Entry) * NumTailElements,
3232
alignof(SILVTable));
3333
SILVTable *vt = ::new (buf) SILVTable(Class, Entries);
3434
M.vtables.push_back(vt);
3535
M.VTableMap[Class] = vt;
3636
// Update the Module's cache with new vtable + vtable entries:
37-
for (auto &entry : Entries) {
38-
M.VTableEntryCache.insert({{vt, entry.first}, entry.second});
37+
for (const Entry &entry : Entries) {
38+
M.VTableEntryCache.insert({{vt, entry.Method}, entry.Implementation});
3939
}
4040
return vt;
4141
}
@@ -44,33 +44,33 @@ SILFunction *
4444
SILVTable::getImplementation(SILModule &M, SILDeclRef method) const {
4545
SILDeclRef m = method;
4646
do {
47-
auto entry = M.VTableEntryCache.find({this, m});
48-
if (entry != M.VTableEntryCache.end()) {
49-
return (*entry).second;
47+
auto entryIter = M.VTableEntryCache.find({this, m});
48+
if (entryIter != M.VTableEntryCache.end()) {
49+
return (*entryIter).second;
5050
}
5151
} while ((m = m.getOverridden()));
5252
return nullptr;
5353
}
5454

55-
void SILVTable::removeFromVTableCache(Pair &entry) {
56-
SILModule &M = entry.second->getModule();
57-
M.VTableEntryCache.erase({this, entry.first});
55+
void SILVTable::removeFromVTableCache(Entry &entry) {
56+
SILModule &M = entry.Implementation->getModule();
57+
M.VTableEntryCache.erase({this, entry.Method});
5858
}
5959

60-
SILVTable::SILVTable(ClassDecl *c, ArrayRef<Pair> entries)
60+
SILVTable::SILVTable(ClassDecl *c, ArrayRef<Entry> entries)
6161
: Class(c), NumEntries(entries.size())
6262
{
63-
memcpy(Entries, entries.begin(), sizeof(Pair) * NumEntries);
63+
memcpy(Entries, entries.begin(), sizeof(Entry) * NumEntries);
6464

6565
// Bump the reference count of functions referenced by this table.
66-
for (auto entry : getEntries()) {
67-
entry.second->incrementRefCount();
66+
for (const Entry &entry : getEntries()) {
67+
entry.Implementation->incrementRefCount();
6868
}
6969
}
7070

7171
SILVTable::~SILVTable() {
7272
// Drop the reference count of functions referenced by this table.
73-
for (auto entry : getEntries()) {
74-
entry.second->decrementRefCount();
73+
for (const Entry &entry : getEntries()) {
74+
entry.Implementation->decrementRefCount();
7575
}
7676
}

lib/SIL/SILVerifier.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3592,17 +3592,17 @@ void SILVTable::verify(const SILModule &M) const {
35923592
#ifndef NDEBUG
35933593
for (auto &entry : getEntries()) {
35943594
// All vtable entries must be decls in a class context.
3595-
assert(entry.first.hasDecl() && "vtable entry is not a decl");
3596-
auto baseInfo = M.Types.getConstantInfo(entry.first);
3597-
ValueDecl *decl = entry.first.getDecl();
3595+
assert(entry.Method.hasDecl() && "vtable entry is not a decl");
3596+
auto baseInfo = M.Types.getConstantInfo(entry.Method);
3597+
ValueDecl *decl = entry.Method.getDecl();
35983598

35993599
assert((!isa<FuncDecl>(decl)
36003600
|| !cast<FuncDecl>(decl)->isObservingAccessor())
36013601
&& "observing accessors shouldn't have vtable entries");
36023602

36033603
// For ivar destroyers, the decl is the class itself.
36043604
ClassDecl *theClass;
3605-
if (entry.first.kind == SILDeclRef::Kind::IVarDestroyer)
3605+
if (entry.Method.kind == SILDeclRef::Kind::IVarDestroyer)
36063606
theClass = dyn_cast<ClassDecl>(decl);
36073607
else
36083608
theClass = dyn_cast<ClassDecl>(decl->getDeclContext());
@@ -3622,22 +3622,22 @@ void SILVTable::verify(const SILModule &M) const {
36223622
assert(c && "vtable entry must refer to a member of the vtable's class");
36233623

36243624
// All function vtable entries must be at their natural uncurry level.
3625-
assert(!entry.first.isCurried && "vtable entry must not be curried");
3625+
assert(!entry.Method.isCurried && "vtable entry must not be curried");
36263626

36273627
// Foreign entry points shouldn't appear in vtables.
3628-
assert(!entry.first.isForeign && "vtable entry must not be foreign");
3628+
assert(!entry.Method.isForeign && "vtable entry must not be foreign");
36293629

36303630
// The vtable entry must be ABI-compatible with the overridden vtable slot.
36313631
SmallString<32> baseName;
36323632
{
36333633
llvm::raw_svector_ostream os(baseName);
3634-
entry.first.print(os);
3634+
entry.Method.print(os);
36353635
}
36363636

3637-
SILVerifier(*entry.second)
3637+
SILVerifier(*entry.Implementation)
36383638
.requireABICompatibleFunctionTypes(
36393639
baseInfo.getSILType().castTo<SILFunctionType>(),
3640-
entry.second->getLoweredFunctionType(),
3640+
entry.Implementation->getLoweredFunctionType(),
36413641
"vtable entry for " + baseName + " must be ABI-compatible");
36423642
}
36433643
#endif
@@ -3747,9 +3747,9 @@ void SILModule::verify() const {
37473747
vt.verify(*this);
37483748
// Check if there is a cache entry for each vtable entry
37493749
for (auto entry : vt.getEntries()) {
3750-
if (VTableEntryCache.find({&vt, entry.first}) == VTableEntryCache.end()) {
3751-
llvm::errs() << "Vtable entry for function: " << entry.second->getName()
3752-
<< "not in cache!\n";
3750+
if (VTableEntryCache.find({&vt, entry.Method}) == VTableEntryCache.end()) {
3751+
llvm::errs() << "Vtable entry for function: "
3752+
<< entry.Implementation->getName() << "not in cache!\n";
37533753
assert(false && "triggering standard assertion failure routine");
37543754
}
37553755
EntriesSZ++;

lib/SILGen/SILGen.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
172172
/// diverges from the overridden base method. If no thunking is needed,
173173
/// returns a static reference to the derived method.
174174
SILFunction *emitVTableMethod(SILDeclRef derived,
175-
SILDeclRef base);
175+
SILDeclRef base,
176+
SILLinkage &implLinkage);
176177

177178
/// True if a function has been emitted for a given SILDeclRef.
178179
bool hasFunction(SILDeclRef constant);

lib/SILGen/SILGenFunction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
651651
/// \param inputSubstType Formal AST type of base class method
652652
/// \param outputSubstType Formal AST type of derived class method
653653
void emitVTableThunk(SILDeclRef derived,
654+
SILFunction *implFn,
654655
AbstractionPattern inputOrigType,
655656
CanAnyFunctionType inputSubstType,
656657
CanAnyFunctionType outputSubstType);

lib/SILGen/SILGenPoly.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2891,6 +2891,7 @@ SILGenFunction::emitTransformedValue(SILLocation loc, RValue &&v,
28912891

28922892
void
28932893
SILGenFunction::emitVTableThunk(SILDeclRef derived,
2894+
SILFunction *implFn,
28942895
AbstractionPattern inputOrigType,
28952896
CanAnyFunctionType inputSubstType,
28962897
CanAnyFunctionType outputSubstType) {
@@ -2902,7 +2903,6 @@ SILGenFunction::emitVTableThunk(SILDeclRef derived,
29022903
cleanupLoc.markAutoGenerated();
29032904
Scope scope(Cleanups, cleanupLoc);
29042905

2905-
auto implFn = SGM.getFunction(derived, NotForDefinition);
29062906
auto fTy = implFn->getLoweredFunctionType();
29072907

29082908
ArrayRef<Substitution> subs;

0 commit comments

Comments
 (0)