Skip to content

Commit 23c7fc5

Browse files
authored
Merge pull request #32296 from davezarzycki/pr32296
[SIL] NFC: Make SILVTable follow C++ and LLVM best practices
2 parents 8d79ec1 + e077b6f commit 23c7fc5

File tree

11 files changed

+156
-140
lines changed

11 files changed

+156
-140
lines changed

include/swift/SIL/SILVTable.h

Lines changed: 62 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -39,43 +39,54 @@ enum IsSerialized_t : unsigned char;
3939
class SILFunction;
4040
class SILModule;
4141

42+
// TODO: Entry should include substitutions needed to invoke an overridden
43+
// generic base class method.
44+
class SILVTableEntry {
45+
/// The declaration reference to the least-derived method visible through
46+
/// the class.
47+
SILDeclRef Method;
48+
49+
/// The function which implements the method for the class and the entry kind.
50+
llvm::PointerIntPair<SILFunction *, 2, unsigned> ImplAndKind;
51+
52+
public:
53+
enum Kind : uint8_t {
54+
/// The vtable entry is for a method defined directly in this class.
55+
Normal,
56+
/// The vtable entry is for a method defined directly in this class, and is
57+
/// never overridden by subclasses.
58+
NormalNonOverridden,
59+
/// The vtable entry is inherited from the superclass.
60+
Inherited,
61+
/// The vtable entry is inherited from the superclass, and overridden
62+
/// in this class.
63+
Override,
64+
65+
// Please update the PointerIntPair above if you add/remove enums.
66+
};
67+
68+
SILVTableEntry() : ImplAndKind(nullptr, Kind::Normal) {}
69+
70+
SILVTableEntry(SILDeclRef Method, SILFunction *Implementation, Kind TheKind)
71+
: Method(Method), ImplAndKind(Implementation, TheKind) {}
72+
73+
SILDeclRef getMethod() const { return Method; }
74+
75+
Kind getKind() const { return Kind(ImplAndKind.getInt()); }
76+
void setKind(Kind kind) { ImplAndKind.setInt(kind); }
77+
78+
SILFunction *getImplementation() const { return ImplAndKind.getPointer(); }
79+
};
80+
4281
/// A mapping from each dynamically-dispatchable method of a class to the
4382
/// SILFunction that implements the method for that class.
4483
/// Note that dead methods are completely removed from the vtable.
45-
class SILVTable : public SILAllocated<SILVTable> {
84+
class SILVTable final : public SILAllocated<SILVTable>,
85+
llvm::TrailingObjects<SILVTable, SILVTableEntry> {
86+
friend TrailingObjects;
87+
4688
public:
47-
// TODO: Entry should include substitutions needed to invoke an overridden
48-
// generic base class method.
49-
struct Entry {
50-
enum Kind : uint8_t {
51-
/// The vtable entry is for a method defined directly in this class.
52-
Normal,
53-
/// The vtable entry is for a method defined directly in this class, and is never overridden
54-
/// by subclasses.
55-
NormalNonOverridden,
56-
/// The vtable entry is inherited from the superclass.
57-
Inherited,
58-
/// The vtable entry is inherited from the superclass, and overridden
59-
/// in this class.
60-
Override,
61-
};
62-
63-
Entry()
64-
: Implementation(nullptr), TheKind(Kind::Normal) { }
65-
66-
Entry(SILDeclRef Method, SILFunction *Implementation, Kind TheKind)
67-
: Method(Method), Implementation(Implementation), TheKind(TheKind) { }
68-
69-
/// The declaration reference to the least-derived method visible through
70-
/// the class.
71-
SILDeclRef Method;
72-
73-
/// The function which implements the method for the class.
74-
SILFunction *Implementation;
75-
76-
/// The entry kind.
77-
Kind TheKind;
78-
};
89+
using Entry = SILVTableEntry;
7990

8091
// Disallow copying into temporary objects.
8192
SILVTable(const SILVTable &other) = delete;
@@ -92,9 +103,6 @@ class SILVTable : public SILAllocated<SILVTable> {
92103
/// The number of SILVTables entries.
93104
unsigned NumEntries : 31;
94105

95-
/// Tail-allocated SILVTable entries.
96-
Entry Entries[1];
97-
98106
/// Private constructor. Create SILVTables by calling SILVTable::create.
99107
SILVTable(ClassDecl *c, IsSerialized_t serialized, ArrayRef<Entry> entries);
100108

@@ -123,29 +131,34 @@ class SILVTable : public SILAllocated<SILVTable> {
123131
}
124132

125133
/// Return all of the method entries.
126-
ArrayRef<Entry> getEntries() const { return {Entries, NumEntries}; }
134+
ArrayRef<Entry> getEntries() const {
135+
return {getTrailingObjects<SILVTableEntry>(), NumEntries};
136+
}
127137

128138
/// Return all of the method entries mutably.
129-
MutableArrayRef<Entry> getMutableEntries() { return {Entries, NumEntries}; }
139+
MutableArrayRef<Entry> getMutableEntries() {
140+
return {getTrailingObjects<SILVTableEntry>(), NumEntries};
141+
}
130142

131143
/// Look up the implementation function for the given method.
132144
Optional<Entry> getEntry(SILModule &M, SILDeclRef method) const;
133145

134146
/// Removes entries from the vtable.
135147
/// \p predicate Returns true if the passed entry should be removed.
136148
template <typename Predicate> void removeEntries_if(Predicate predicate) {
137-
Entry *end = std::remove_if(Entries, Entries + NumEntries,
138-
[&](Entry &entry) -> bool {
139-
if (predicate(entry)) {
140-
entry.Implementation->decrementRefCount();
141-
removeFromVTableCache(entry);
142-
return true;
143-
}
144-
return false;
145-
});
146-
NumEntries = end - Entries;
149+
auto Entries = getMutableEntries();
150+
Entry *end = std::remove_if(
151+
Entries.begin(), Entries.end(), [&](Entry &entry) -> bool {
152+
if (predicate(entry)) {
153+
entry.getImplementation()->decrementRefCount();
154+
removeFromVTableCache(entry);
155+
return true;
156+
}
157+
return false;
158+
});
159+
NumEntries = std::distance(Entries.begin(), end);
147160
}
148-
161+
149162
/// Verify that the vtable is well-formed for the given class.
150163
void verify(const SILModule &M) const;
151164

lib/IRGen/GenMeta.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,8 +1577,8 @@ namespace {
15771577
descriptor.addInt(IGM.Int32Ty, flags.getIntValue());
15781578

15791579
if (auto entry = VTable->getEntry(IGM.getSILModule(), fn)) {
1580-
assert(entry->TheKind == SILVTable::Entry::Kind::Normal);
1581-
auto *implFn = IGM.getAddrOfSILFunction(entry->Implementation,
1580+
assert(entry->getKind() == SILVTable::Entry::Kind::Normal);
1581+
auto *implFn = IGM.getAddrOfSILFunction(entry->getImplementation(),
15821582
NotForDefinition);
15831583
descriptor.addRelativeAddress(implFn);
15841584
} else {
@@ -1625,8 +1625,8 @@ namespace {
16251625

16261626
// The implementation of the override.
16271627
if (auto entry = VTable->getEntry(IGM.getSILModule(), baseRef)) {
1628-
assert(entry->TheKind == SILVTable::Entry::Kind::Override);
1629-
auto *implFn = IGM.getAddrOfSILFunction(entry->Implementation,
1628+
assert(entry->getKind() == SILVTable::Entry::Kind::Override);
1629+
auto *implFn = IGM.getAddrOfSILFunction(entry->getImplementation(),
16301630
NotForDefinition);
16311631
descriptor.addRelativeAddress(implFn);
16321632
} else {
@@ -2981,7 +2981,7 @@ namespace {
29812981
// The class is fragile. Emit a direct reference to the vtable entry.
29822982
llvm::Constant *ptr;
29832983
if (entry) {
2984-
ptr = IGM.getAddrOfSILFunction(entry->Implementation,
2984+
ptr = IGM.getAddrOfSILFunction(entry->getImplementation(),
29852985
NotForDefinition);
29862986
} else {
29872987
// The method is removed by dead method elimination.

lib/SIL/IR/Linker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ void SILLinkerVisitor::linkInVTable(ClassDecl *D) {
154154
for (auto P : Vtbl->getEntries()) {
155155
// Deserialize and recursively walk any vtable entries that do not have
156156
// bodies yet.
157-
maybeAddFunctionToWorklist(P.Implementation);
157+
maybeAddFunctionToWorklist(P.getImplementation());
158158
}
159159
}
160160

lib/SIL/IR/SILModule.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ lookUpFunctionInVTable(ClassDecl *Class, SILDeclRef Member) {
593593
// Ok, we have a VTable. Try to lookup the SILFunction implementation from
594594
// the VTable.
595595
if (auto E = Vtbl->getEntry(*this, Member))
596-
return E->Implementation;
596+
return E->getImplementation();
597597

598598
return nullptr;
599599
}

lib/SIL/IR/SILPrinter.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3106,11 +3106,11 @@ void SILVTable::print(llvm::raw_ostream &OS, bool Verbose) const {
31063106
PrintOptions QualifiedSILTypeOptions = PrintOptions::printQualifiedSILType();
31073107
for (auto &entry : getEntries()) {
31083108
OS << " ";
3109-
entry.Method.print(OS);
3109+
entry.getMethod().print(OS);
31103110
OS << ": ";
31113111

31123112
bool HasSingleImplementation = false;
3113-
switch (entry.Method.kind) {
3113+
switch (entry.getMethod().kind) {
31143114
default:
31153115
break;
31163116
case SILDeclRef::Kind::IVarDestroyer:
@@ -3122,13 +3122,13 @@ void SILVTable::print(llvm::raw_ostream &OS, bool Verbose) const {
31223122
// single implementation, e.g. for destructors.
31233123
if (!HasSingleImplementation) {
31243124
QualifiedSILTypeOptions.CurrentModule =
3125-
entry.Method.getDecl()->getDeclContext()->getParentModule();
3126-
entry.Method.getDecl()->getInterfaceType().print(OS,
3127-
QualifiedSILTypeOptions);
3125+
entry.getMethod().getDecl()->getDeclContext()->getParentModule();
3126+
entry.getMethod().getDecl()->getInterfaceType().print(
3127+
OS, QualifiedSILTypeOptions);
31283128
OS << " : ";
31293129
}
3130-
OS << '@' << entry.Implementation->getName();
3131-
switch (entry.TheKind) {
3130+
OS << '@' << entry.getImplementation()->getName();
3131+
switch (entry.getKind()) {
31323132
case SILVTable::Entry::Kind::Normal:
31333133
break;
31343134
case SILVTable::Entry::Kind::NormalNonOverridden:
@@ -3141,7 +3141,7 @@ void SILVTable::print(llvm::raw_ostream &OS, bool Verbose) const {
31413141
OS << " [override]";
31423142
break;
31433143
}
3144-
OS << "\t// " << demangleSymbol(entry.Implementation->getName());
3144+
OS << "\t// " << demangleSymbol(entry.getImplementation()->getName());
31453145
OS << "\n";
31463146
}
31473147
OS << "}\n\n";

lib/SIL/IR/SILVTable.cpp

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,14 @@ using namespace swift;
2626
SILVTable *SILVTable::create(SILModule &M, ClassDecl *Class,
2727
IsSerialized_t Serialized,
2828
ArrayRef<Entry> Entries) {
29-
// SILVTable contains one element declared in Entries. We must allocate
30-
// space for it, because its default ctor will write to it.
31-
unsigned NumTailElements = std::max((unsigned)Entries.size(), 1U)-1;
32-
void *buf = M.allocate(sizeof(SILVTable) + sizeof(Entry) * NumTailElements,
33-
alignof(SILVTable));
29+
auto size = totalSizeToAlloc<Entry>(Entries.size());
30+
auto buf = M.allocate(size, alignof(SILVTable));
3431
SILVTable *vt = ::new (buf) SILVTable(Class, Serialized, Entries);
3532
M.vtables.push_back(vt);
3633
M.VTableMap[Class] = vt;
3734
// Update the Module's cache with new vtable + vtable entries:
3835
for (const Entry &entry : Entries) {
39-
M.VTableEntryCache.insert({{vt, entry.Method}, entry});
36+
M.VTableEntryCache.insert({{vt, entry.getMethod()}, entry});
4037
}
4138
return vt;
4239
}
@@ -54,24 +51,25 @@ SILVTable::getEntry(SILModule &M, SILDeclRef method) const {
5451
}
5552

5653
void SILVTable::removeFromVTableCache(Entry &entry) {
57-
SILModule &M = entry.Implementation->getModule();
58-
M.VTableEntryCache.erase({this, entry.Method});
54+
SILModule &M = entry.getImplementation()->getModule();
55+
M.VTableEntryCache.erase({this, entry.getMethod()});
5956
}
6057

6158
SILVTable::SILVTable(ClassDecl *c, IsSerialized_t serialized,
6259
ArrayRef<Entry> entries)
6360
: Class(c), Serialized(serialized), NumEntries(entries.size()) {
64-
memcpy(Entries, entries.begin(), sizeof(Entry) * NumEntries);
65-
61+
std::uninitialized_copy(entries.begin(), entries.end(),
62+
getTrailingObjects<Entry>());
63+
6664
// Bump the reference count of functions referenced by this table.
6765
for (const Entry &entry : getEntries()) {
68-
entry.Implementation->incrementRefCount();
66+
entry.getImplementation()->incrementRefCount();
6967
}
7068
}
7169

7270
SILVTable::~SILVTable() {
7371
// Drop the reference count of functions referenced by this table.
7472
for (const Entry &entry : getEntries()) {
75-
entry.Implementation->decrementRefCount();
73+
entry.getImplementation()->decrementRefCount();
7674
}
7775
}

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5378,18 +5378,18 @@ void SILVTable::verify(const SILModule &M) const {
53785378
auto &entry = getEntries()[i];
53795379

53805380
// All vtable entries must be decls in a class context.
5381-
assert(entry.Method.hasDecl() && "vtable entry is not a decl");
5382-
auto baseInfo =
5383-
M.Types.getConstantInfo(TypeExpansionContext::minimal(), entry.Method);
5384-
ValueDecl *decl = entry.Method.getDecl();
5381+
assert(entry.getMethod().hasDecl() && "vtable entry is not a decl");
5382+
auto baseInfo = M.Types.getConstantInfo(TypeExpansionContext::minimal(),
5383+
entry.getMethod());
5384+
ValueDecl *decl = entry.getMethod().getDecl();
53855385

53865386
assert((!isa<AccessorDecl>(decl)
53875387
|| !cast<AccessorDecl>(decl)->isObservingAccessor())
53885388
&& "observing accessors shouldn't have vtable entries");
53895389

53905390
// For ivar destroyers, the decl is the class itself.
53915391
ClassDecl *theClass;
5392-
if (entry.Method.kind == SILDeclRef::Kind::IVarDestroyer)
5392+
if (entry.getMethod().kind == SILDeclRef::Kind::IVarDestroyer)
53935393
theClass = dyn_cast<ClassDecl>(decl);
53945394
else
53955395
theClass = dyn_cast<ClassDecl>(decl->getDeclContext());
@@ -5401,29 +5401,29 @@ void SILVTable::verify(const SILModule &M) const {
54015401
"vtable entry must refer to a member of the vtable's class");
54025402

54035403
// Foreign entry points shouldn't appear in vtables.
5404-
assert(!entry.Method.isForeign && "vtable entry must not be foreign");
5405-
5404+
assert(!entry.getMethod().isForeign && "vtable entry must not be foreign");
5405+
54065406
// The vtable entry must be ABI-compatible with the overridden vtable slot.
54075407
SmallString<32> baseName;
54085408
{
54095409
llvm::raw_svector_ostream os(baseName);
5410-
entry.Method.print(os);
5410+
entry.getMethod().print(os);
54115411
}
54125412

54135413
if (M.getStage() != SILStage::Lowered) {
5414-
SILVerifier(*entry.Implementation)
5414+
SILVerifier(*entry.getImplementation())
54155415
.requireABICompatibleFunctionTypes(
54165416
baseInfo.getSILType().castTo<SILFunctionType>(),
5417-
entry.Implementation->getLoweredFunctionType(),
5417+
entry.getImplementation()->getLoweredFunctionType(),
54185418
"vtable entry for " + baseName + " must be ABI-compatible",
5419-
*entry.Implementation);
5419+
*entry.getImplementation());
54205420
}
54215421

54225422
// Validate the entry against its superclass vtable.
54235423
if (!superclass) {
54245424
// Root methods should not have inherited or overridden entries.
54255425
bool validKind;
5426-
switch (entry.TheKind) {
5426+
switch (entry.getKind()) {
54275427
case Entry::Normal:
54285428
case Entry::NormalNonOverridden:
54295429
validKind = true;
@@ -5441,13 +5441,14 @@ void SILVTable::verify(const SILModule &M) const {
54415441

54425442
const Entry *superEntry = nullptr;
54435443
for (auto &se : superVTable->getEntries()) {
5444-
if (se.Method.getOverriddenVTableEntry() == entry.Method.getOverriddenVTableEntry()) {
5444+
if (se.getMethod().getOverriddenVTableEntry() ==
5445+
entry.getMethod().getOverriddenVTableEntry()) {
54455446
superEntry = &se;
54465447
break;
54475448
}
54485449
}
5449-
5450-
switch (entry.TheKind) {
5450+
5451+
switch (entry.getKind()) {
54515452
case Entry::Normal:
54525453
case Entry::NormalNonOverridden:
54535454
assert(!superEntry && "non-root vtable entry must be inherited or override");
@@ -5461,8 +5462,9 @@ void SILVTable::verify(const SILModule &M) const {
54615462
break;
54625463

54635464
// The superclass entry must not prohibit overrides.
5464-
assert(superEntry->TheKind != Entry::NormalNonOverridden
5465-
&& "vtable entry overrides an entry that claims to have no overrides");
5465+
assert(
5466+
superEntry->getKind() != Entry::NormalNonOverridden &&
5467+
"vtable entry overrides an entry that claims to have no overrides");
54665468
// TODO: Check the root vtable entry for the method too.
54675469
break;
54685470
}
@@ -5590,9 +5592,11 @@ void SILModule::verify() const {
55905592
vt->verify(*this);
55915593
// Check if there is a cache entry for each vtable entry
55925594
for (auto entry : vt->getEntries()) {
5593-
if (VTableEntryCache.find({vt, entry.Method}) == VTableEntryCache.end()) {
5595+
if (VTableEntryCache.find({vt, entry.getMethod()}) ==
5596+
VTableEntryCache.end()) {
55945597
llvm::errs() << "Vtable entry for function: "
5595-
<< entry.Implementation->getName() << "not in cache!\n";
5598+
<< entry.getImplementation()->getName()
5599+
<< "not in cache!\n";
55965600
assert(false && "triggering standard assertion failure routine");
55975601
}
55985602
++EntriesSZ;

0 commit comments

Comments
 (0)