Skip to content

Commit 10690fb

Browse files
author
Brian King
committed
Naive implementation of support for VTable expansion in extensions
1 parent 0d0dc79 commit 10690fb

File tree

6 files changed

+84
-25
lines changed

6 files changed

+84
-25
lines changed

lib/SILGen/SILGen.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,8 @@ SILModule::constructSIL(ModuleDecl *mod, SILOptions &options, FileUnit *SF,
14661466
if (hasSIB)
14671467
M->getSILLoader()->getAllForModule(mod->getName(), nullptr);
14681468
}
1469+
1470+
SGM.emitVTables();
14691471

14701472
// Emit external definitions used by this module.
14711473
for (size_t i = 0, e = mod->getASTContext().LastCheckedExternalDefinition;

lib/SILGen/SILGen.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
6363
llvm::DenseMap<SILDeclRef, SILFunction*> emittedFunctions;
6464
/// Mapping from ProtocolConformances to emitted SILWitnessTables.
6565
llvm::DenseMap<ProtocolConformance*, SILWitnessTable*> emittedWitnessTables;
66+
67+
/// VTable entry storage that is built as the module is generated
68+
llvm::DenseMap<ClassDecl *, std::vector<SILVTable::Entry> *> VTableEntryMap;
69+
70+
/// Set of classes for which vtables need to be emitted.
71+
llvm::DenseSet<ClassDecl *> VTablesPending;
6672

6773
struct DelayedFunction {
6874
/// Insert the entity after the given function when it's emitted.
@@ -292,6 +298,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
292298
/// Add a global variable to the SILModule.
293299
void addGlobalVariable(VarDecl *global);
294300

301+
/// Emit SIL related to the processed VTables
302+
void emitVTables();
303+
295304
/// Emit SIL related to a Clang-imported declaration.
296305
void emitExternalDefinition(Decl *d);
297306

lib/SILGen/SILGenDecl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,14 @@ void SILGenModule::emitExternalWitnessTable(ProtocolConformance *c) {
12221222
lastEmittedConformance = root;
12231223
}
12241224

1225+
void SILGenModule::emitVTables() {
1226+
for (auto *c : VTablesPending) {
1227+
auto vtableEntries = VTableEntryMap[c];
1228+
ClassDecl *theClass = c;
1229+
SILVTable::create(M, theClass, *vtableEntries);
1230+
}
1231+
}
1232+
12251233
void SILGenModule::emitExternalDefinition(Decl *d) {
12261234
switch (d->getKind()) {
12271235
case DeclKind::Func: {

lib/SILGen/SILGenType.cpp

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -151,20 +151,27 @@ class SILGenVTable : public Lowering::ASTVisitor<SILGenVTable> {
151151
public:
152152
SILGenModule &SGM;
153153
ClassDecl *theClass;
154-
std::vector<SILVTable::Entry> vtableEntries;
154+
155+
std::vector<SILVTable::Entry> &getVTableEntries() {
156+
auto *entries = SGM.VTableEntryMap.lookup(theClass);
157+
if (!entries) {
158+
entries = new std::vector<SILVTable::Entry>();
159+
SGM.VTableEntryMap.insert({theClass, entries});
160+
}
161+
return *entries;
162+
}
155163

156164
SILGenVTable(SILGenModule &SGM, ClassDecl *theClass)
157-
: SGM(SGM), theClass(theClass)
158-
{
165+
: SGM(SGM), theClass(theClass) {}
166+
167+
void visitAncestors() {
159168
// Populate the superclass members, if any.
160169
Type super = theClass->getSuperclass();
161170
if (super && super->getClassOrBoundGenericClass())
162171
visitAncestor(super->getClassOrBoundGenericClass());
163-
}
164-
165-
~SILGenVTable() {
166-
// Create the vtable.
167-
SILVTable::create(SGM.M, theClass, vtableEntries);
172+
173+
// Store an iterable class
174+
SGM.VTablesPending.insert(theClass);
168175
}
169176

170177
void visitAncestor(ClassDecl *ancestor) {
@@ -204,7 +211,7 @@ class SILGenVTable : public Lowering::ASTVisitor<SILGenVTable> {
204211
// NB: Mutates vtableEntries in-place
205212
// FIXME: O(n^2)
206213
if (auto overridden = member.getNextOverriddenVTableEntry()) {
207-
for (SILVTable::Entry &entry : vtableEntries) {
214+
for (SILVTable::Entry &entry : getVTableEntries()) {
208215
SILDeclRef ref = overridden;
209216

210217
do {
@@ -230,7 +237,7 @@ class SILGenVTable : public Lowering::ASTVisitor<SILGenVTable> {
230237
return;
231238

232239
// Otherwise, introduce a new vtable entry.
233-
vtableEntries.push_back(getVtableEntry(member));
240+
getVTableEntries().push_back(getVtableEntry(member));
234241
}
235242

236243
// Default for members that don't require vtable entries.
@@ -325,8 +332,10 @@ class SILGenType : public TypeMemberVisitor<SILGenType> {
325332
/// Emit SIL functions for all the members of the type.
326333
void emitType() {
327334
// Start building a vtable if this is a class.
328-
if (auto theClass = dyn_cast<ClassDecl>(theType))
335+
if (auto theClass = dyn_cast<ClassDecl>(theType)) {
329336
genVTable.emplace(SGM, theClass);
337+
genVTable->visitAncestors();
338+
}
330339

331340
for (Decl *member : theType->getMembers()) {
332341
if (genVTable)
@@ -430,14 +439,24 @@ void SILGenModule::visitNominalTypeDecl(NominalTypeDecl *ntd) {
430439
class SILGenExtension : public TypeMemberVisitor<SILGenExtension> {
431440
public:
432441
SILGenModule &SGM;
442+
Optional<SILGenVTable> genVTable;
433443

434444
SILGenExtension(SILGenModule &SGM)
435445
: SGM(SGM) {}
436446

437447
/// Emit SIL functions for all the members of the extension.
438448
void emitExtension(ExtensionDecl *e) {
439-
for (Decl *member : e->getMembers())
449+
450+
if (auto theClass = e->getAsClassOrClassExtensionContext())
451+
genVTable.emplace(SGM, theClass);
452+
453+
for (Decl *member : e->getMembers()) {
454+
if (genVTable) {
455+
genVTable->visit(member);
456+
}
457+
440458
visit(member);
459+
}
441460

442461
if (!e->getExtendedType()->isExistentialType()) {
443462
// Emit witness tables for protocol conformances introduced by the

lib/Sema/TypeCheckDecl.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6046,14 +6046,14 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
60466046

60476047
// Non-Objective-C declarations in extensions cannot override or
60486048
// be overridden.
6049-
if ((base->getDeclContext()->isExtensionContext() ||
6050-
override->getDeclContext()->isExtensionContext()) &&
6051-
!base->isObjC() && !isKnownObjC) {
6052-
TC.diagnose(override, diag::override_decl_extension,
6053-
!override->getDeclContext()->isExtensionContext());
6054-
TC.diagnose(base, diag::overridden_here);
6055-
return true;
6056-
}
6049+
// if ((base->getDeclContext()->isExtensionContext() ||
6050+
// override->getDeclContext()->isExtensionContext()) &&
6051+
// !base->isObjC() && !isKnownObjC) {
6052+
// TC.diagnose(override, diag::override_decl_extension,
6053+
// !override->getDeclContext()->isExtensionContext());
6054+
// TC.diagnose(base, diag::overridden_here);
6055+
// return true;
6056+
// }
60576057

60586058
// If the overriding declaration does not have the 'override' modifier on
60596059
// it, complain.
@@ -6067,11 +6067,30 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
60676067
.fixItInsert(override->getStartLoc(), "override ");
60686068
else
60696069
TC.diagnose(override, diag::missing_override);
6070+
60706071
TC.diagnose(base, diag::overridden_here);
60716072
override->getAttrs().add(
60726073
new (TC.Context) OverrideAttr(SourceLoc()));
60736074
}
60746075

6076+
// If the overridden method is declared in a Swift Class Declaration,
6077+
// dispatch will use table dispatch. If the override is in an extension
6078+
// warn, since it is not added to the class vtable.
6079+
//
6080+
// FIXME: Only warn if the extension is in another module, and if
6081+
// it is in the same module, update the vtable.
6082+
// if (auto *baseDecl = dyn_cast<ClassDecl>(base->getDeclContext())) {
6083+
// if (baseDecl->hasKnownSwiftImplementation() &&
6084+
// !base->isDynamic() &&
6085+
// override->getDeclContext()->isExtensionContext()) {
6086+
// // For compatibility, only generate a warning in Swift 3
6087+
// TC.diagnose(override, (TC.Context.isSwiftVersion3()
6088+
// ? diag::override_class_declaration_in_extension_warning
6089+
// : diag::override_class_declaration_in_extension));
6090+
// TC.diagnose(base, diag::overridden_here);
6091+
// }
6092+
// }
6093+
60756094
// If the overriding declaration is 'throws' but the base is not,
60766095
// complain.
60776096
if (auto overrideFn = dyn_cast<AbstractFunctionDecl>(override)) {

test/SILGen/vtables.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ import gizmo
99

1010
// Test for compilation order independence
1111
class C : B {
12-
// foo inherited from B
13-
override func bar() {}
14-
// bas inherited from A
15-
override func qux() {}
16-
1712
// zim inherited from B
1813
override func zang() {}
1914

@@ -22,6 +17,13 @@ class C : B {
2217
func flopsy() {}
2318
func mopsy() {}
2419
}
20+
21+
extension C {
22+
// foo inherited from B
23+
override func bar() {}
24+
// bas inherited from A
25+
override func qux() {}
26+
}
2527
// CHECK: sil_vtable C {
2628
// CHECK: #A.foo!1: _TFC7vtables1B3foo
2729
// CHECK: #A.bar!1: _TFC7vtables1C3bar

0 commit comments

Comments
 (0)