Skip to content

Commit 79fcb5e

Browse files
authored
Merge pull request #71579 from eeckstein/fix-embedded-classes
embedded: Fix a few problems with vtable specialization
2 parents 38fdb5b + 75e2f36 commit 79fcb5e

File tree

10 files changed

+118
-23
lines changed

10 files changed

+118
-23
lines changed

docs/SIL.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,6 +1608,7 @@ VTables
16081608

16091609
decl ::= sil-vtable
16101610
sil-vtable ::= 'sil_vtable' identifier '{' sil-vtable-entry* '}'
1611+
sil-vtable ::= 'sil_vtable' sil-type '{' sil-vtable-entry* '}'
16111612

16121613
sil-vtable-entry ::= sil-decl-ref ':' sil-linkage? sil-function-name
16131614

@@ -1670,6 +1671,13 @@ class (such as ``C.bas`` in ``C``'s vtable).
16701671
In case the SIL function is a thunk, the function name is preceded with the
16711672
linkage of the original implementing function.
16721673

1674+
If the vtable refers to a specialized class, a SIL type specifies the bound
1675+
generic class type::
1676+
1677+
sil_vtable $G<Int> {
1678+
// ...
1679+
}
1680+
16731681
Witness Tables
16741682
~~~~~~~~~~~~~~
16751683
::

include/swift/SIL/SILVTable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ class SILVTable final : public SILAllocated<SILVTable>,
115115
/// The ClassDecl mapped to this VTable.
116116
ClassDecl *Class;
117117

118+
/// The class type if this is a specialized vtable, otherwise null.
118119
SILType classType;
119120

120121
/// Whether or not this vtable is serialized, which allows

lib/SIL/IR/SILPrinter.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3988,7 +3988,12 @@ void SILVTable::print(llvm::raw_ostream &OS, bool Verbose) const {
39883988
OS << "sil_vtable ";
39893989
if (isSerialized())
39903990
OS << "[serialized] ";
3991-
OS << getClass()->getName() << " {\n";
3991+
if (SILType classTy = getClassType()) {
3992+
OS << classTy;
3993+
} else {
3994+
OS << getClass()->getName();
3995+
}
3996+
OS << " {\n";
39923997

39933998
for (auto &entry : getEntries()) {
39943999
OS << " ";

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7452,27 +7452,39 @@ bool SILParserState::parseSILVTable(Parser &P) {
74527452
nullptr, nullptr, VTableState, M))
74537453
return true;
74547454

7455-
// Parse the class name.
7456-
Identifier Name;
7457-
SourceLoc Loc;
7458-
if (VTableState.parseSILIdentifier(Name, Loc,
7459-
diag::expected_sil_value_name))
7460-
return true;
74617455

7462-
// Find the class decl.
7463-
llvm::PointerUnion<ValueDecl*, ModuleDecl *> Res =
7464-
lookupTopDecl(P, Name, /*typeLookup=*/true);
7465-
assert(Res.is<ValueDecl*>() && "Class look-up should return a Decl");
7466-
ValueDecl *VD = Res.get<ValueDecl*>();
7467-
if (!VD) {
7468-
P.diagnose(Loc, diag::sil_vtable_class_not_found, Name);
7469-
return true;
7470-
}
7456+
ClassDecl *theClass = nullptr;
7457+
SILType specializedClassTy;
7458+
if (P.Tok.isNot(tok::sil_dollar)) {
7459+
// Parse the class name.
7460+
Identifier Name;
7461+
SourceLoc Loc;
7462+
if (VTableState.parseSILIdentifier(Name, Loc,
7463+
diag::expected_sil_value_name))
7464+
return true;
74717465

7472-
auto *theClass = dyn_cast<ClassDecl>(VD);
7473-
if (!theClass) {
7474-
P.diagnose(Loc, diag::sil_vtable_class_not_found, Name);
7475-
return true;
7466+
// Find the class decl.
7467+
llvm::PointerUnion<ValueDecl*, ModuleDecl *> Res =
7468+
lookupTopDecl(P, Name, /*typeLookup=*/true);
7469+
assert(Res.is<ValueDecl*>() && "Class look-up should return a Decl");
7470+
ValueDecl *VD = Res.get<ValueDecl*>();
7471+
if (!VD) {
7472+
P.diagnose(Loc, diag::sil_vtable_class_not_found, Name);
7473+
return true;
7474+
}
7475+
7476+
theClass = dyn_cast<ClassDecl>(VD);
7477+
if (!theClass) {
7478+
P.diagnose(Loc, diag::sil_vtable_class_not_found, Name);
7479+
return true;
7480+
}
7481+
} else {
7482+
if (SILParser(P).parseSILType(specializedClassTy))
7483+
return true;
7484+
theClass = specializedClassTy.getClassOrBoundGenericClass();
7485+
if (!theClass) {
7486+
return true;
7487+
}
74767488
}
74777489

74787490
SourceLoc LBraceLoc = P.Tok.getLoc();
@@ -7540,7 +7552,7 @@ bool SILParserState::parseSILVTable(Parser &P) {
75407552
P.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
75417553
LBraceLoc);
75427554

7543-
SILVTable::create(M, theClass, Serialized, vtableEntries);
7555+
SILVTable::create(M, theClass, specializedClassTy, Serialized, vtableEntries);
75447556
return false;
75457557
}
75467558

lib/SILOptimizer/Transforms/VTableSpecializer.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ namespace {
3838

3939
class VTableSpecializer : public SILModuleTransform {
4040
bool specializeVTables(SILModule &module);
41+
bool specializeVTablesOfSuperclasses(SILModule &module);
4142

4243
/// The entry point to the transformation.
4344
void run() override {
@@ -85,9 +86,11 @@ static bool specializeVTablesInFunction(SILFunction &func, SILModule &module,
8586
bool VTableSpecializer::specializeVTables(SILModule &module) {
8687
bool changed = false;
8788
for (SILFunction &func : module) {
88-
specializeVTablesInFunction(func, module, this);
89+
changed |= specializeVTablesInFunction(func, module, this);
8990
}
9091

92+
changed |= specializeVTablesOfSuperclasses(module);
93+
9194
for (SILVTable *vtable : module.getVTables()) {
9295
if (vtable->getClass()->isGenericContext()) continue;
9396

@@ -112,6 +115,28 @@ bool VTableSpecializer::specializeVTables(SILModule &module) {
112115
return changed;
113116
}
114117

118+
bool VTableSpecializer::specializeVTablesOfSuperclasses(SILModule &module) {
119+
bool changed = false;
120+
// The module's vtable table can grow while we are specializing superclass vtables.
121+
for (unsigned i = 0; i < module.getVTables().size(); ++i) {
122+
SILVTable *vtable = module.getVTables()[i];
123+
if (vtable->getClass()->isGenericContext() && !vtable->getClassType())
124+
continue;
125+
126+
SILType superClassTy;
127+
if (SILType classTy = vtable->getClassType()) {
128+
superClassTy = classTy.getSuperclass();
129+
} else {
130+
if (Type superTy = vtable->getClass()->getSuperclass())
131+
superClassTy = SILType::getPrimitiveObjectType(superTy->getCanonicalType());
132+
}
133+
if (superClassTy) {
134+
changed |= (specializeVTableForType(superClassTy, module, this) != nullptr);
135+
}
136+
}
137+
return changed;
138+
}
139+
115140
SILVTable *swift::specializeVTableForType(SILType classTy, SILModule &module,
116141
SILTransform *transform) {
117142
CanType astType = classTy.getASTType();

stdlib/public/core/ManagedBuffer.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,21 @@ open class ManagedBuffer<Header, Element> {
4444
/// reading the `header` property during `ManagedBuffer.create` is undefined.
4545
public final var header: Header
4646

47+
#if $Embedded
48+
// In embedded mode this initializer has to be public, otherwise derived
49+
// classes cannot be specialized.
50+
public init(_doNotCallMe: ()) {
51+
_internalInvariantFailure("Only initialize these by calling create")
52+
}
53+
#else
4754
// This is really unfortunate. In Swift 5.0, the method descriptor for this
4855
// initializer was public and subclasses would "inherit" it, referencing its
4956
// method descriptor from their class override table.
5057
@usableFromInline
5158
internal init(_doNotCallMe: ()) {
5259
_internalInvariantFailure("Only initialize these by calling create")
5360
}
61+
#endif
5462

5563
@inlinable
5664
deinit {}

test/SIL/Parser/basic.sil

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1807,3 +1807,14 @@ sil_vtable Foo2 {
18071807
#Foo.subscript!getter: @Foo_subscript_getter [inherited] [nonoverridden]
18081808
#Foo.subscript!setter: @Foo_subscript_setter [override]
18091809
}
1810+
1811+
class GenKlass<T> {}
1812+
1813+
// CHECK-LABEL: sil_vtable GenKlass {
1814+
sil_vtable GenKlass {
1815+
}
1816+
1817+
// CHECK-LABEL: sil_vtable $GenKlass<Int> {
1818+
sil_vtable $GenKlass<Int> {
1819+
}
1820+

test/embedded/classes-generic-no-stdlib.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public func bar(t: T2) -> MyClass<T2> {
4141
// CHECK-SIL: #MyClass.deinit!deallocator: @$s4main7MyClassCfDAA2T1V_Tg5 // specialized MyClass.__deallocating_deinit
4242
// CHECK-SIL: }
4343

44-
// CHECK-SIL: sil_vtable MyClass {
44+
// CHECK-SIL: sil_vtable $MyClass<T2> {
4545
// CHECK-SIL: #MyClass.t!getter: <T> (MyClass<T>) -> () -> T : @$s4main7MyClassC1txvgAA2T2V_Tg5 // specialized MyClass.t.getter
4646
// CHECK-SIL: #MyClass.t!setter: <T> (MyClass<T>) -> (T) -> () : @$s4main7MyClassC1txvsAA2T2V_Tg5 // specialized MyClass.t.setter
4747
// CHECK-SIL: #MyClass.t!modify: <T> (MyClass<T>) -> () -> () : @$s4main7MyClassC1txvMAA2T2V_Tg5 // specialized MyClass.t.modify

test/embedded/generic-classes.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,31 @@ func makeItFoo<F: Fooable>(f: F) {
2222
f.foo()
2323
}
2424

25+
class BaseClass<A> {
26+
func test() {}
27+
}
28+
29+
class SubClass1<B>: BaseClass<Int> {
30+
override func test() {}
31+
}
32+
33+
class SubClass2 : SubClass1<Int> {
34+
override func test() { print("SubClass2") }
35+
}
36+
2537
@main
2638
struct Main {
2739
static func main() {
2840
let f = GenericFooableClass<Int>()
2941
makeItFoo(f: f)
3042
let g: GenericFooableClass = GenericFooableSubClass<Int>()
3143
makeItFoo(f: g)
44+
let x = SubClass2()
45+
x.test()
3246
}
3347
}
3448

3549
// CHECK: GenericFooableClass<T>.foo
3650
// CHECK: GenericFooableSubClass<T>.foo
51+
// CHECK: SubClass2
3752

test/embedded/managed-buffer.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %target-swift-emit-ir %s -module-name=main -enable-experimental-feature Embedded | %FileCheck %s
2+
3+
// REQUIRES: swift_in_compiler
4+
// REQUIRES: OS=macosx || OS=linux-gnu
5+
6+
// CHECK: @"$s4main8MyBufferCN" = {{.*global.*}} <{ ptr @"$ss13ManagedBufferCySis5UInt8VGN", ptr @"$s4main8MyBufferCfD", ptr @"$s4main8MyBufferC12_doNotCallMeACyt_tcfC" }>
7+
// CHECK: @"$ss13ManagedBufferCySis5UInt8VGN" = {{.*global.*}} <{ ptr null, ptr @"$ss13ManagedBufferCfDSi_s5UInt8VTg5", ptr @"$ss13ManagedBufferC12_doNotCallMeAByxq_Gyt_tcfCSi_s5UInt8VTg5" }>
8+
final public class MyBuffer: ManagedBuffer<Int, UInt8> {
9+
}
10+

0 commit comments

Comments
 (0)