Skip to content

Commit 3eb0b65

Browse files
committed
[embedded] Serialize+deserialize vtables, fix using non-generic classes from other modules in embedded Swift
1 parent f7a8bc2 commit 3eb0b65

File tree

8 files changed

+149
-38
lines changed

8 files changed

+149
-38
lines changed

lib/IRGen/GenClass.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2901,6 +2901,9 @@ CanType irgen::getSuperclassForMetadata(IRGenModule &IGM, CanType type,
29012901

29022902
ClassMetadataStrategy
29032903
IRGenModule::getClassMetadataStrategy(const ClassDecl *theClass) {
2904+
if (Context.LangOpts.hasFeature(Feature::Embedded))
2905+
return ClassMetadataStrategy::Fixed;
2906+
29042907
SILType selfType = getSelfType(theClass);
29052908
auto &selfTI = getTypeInfo(selfType).as<ClassTypeInfo>();
29062909

lib/IRGen/GenDecl.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1436,6 +1436,7 @@ void IRGenerator::emitLazyDefinitions() {
14361436
assert(LazyWitnessTables.empty());
14371437
assert(LazyCanonicalSpecializedMetadataAccessors.empty());
14381438
assert(LazyMetadataAccessors.empty());
1439+
// LazyClassMetadata is allowed
14391440
// LazySpecializedClassMetadata is allowed
14401441
}
14411442

@@ -1446,7 +1447,9 @@ void IRGenerator::emitLazyDefinitions() {
14461447
!LazyFunctionDefinitions.empty() || !LazyWitnessTables.empty() ||
14471448
!LazyCanonicalSpecializedMetadataAccessors.empty() ||
14481449
!LazyMetadataAccessors.empty() ||
1449-
!LazySpecializedClassMetadata.empty()) {
1450+
!LazyClassMetadata.empty() ||
1451+
!LazySpecializedClassMetadata.empty()
1452+
) {
14501453
// Emit any lazy type metadata we require.
14511454
while (!LazyTypeMetadata.empty()) {
14521455
NominalTypeDecl *type = LazyTypeMetadata.pop_back_val();
@@ -1544,6 +1547,12 @@ void IRGenerator::emitLazyDefinitions() {
15441547
emitLazyMetadataAccessor(*IGM.get(), nominal);
15451548
}
15461549

1550+
while (!LazyClassMetadata.empty()) {
1551+
CanType classType = LazyClassMetadata.pop_back_val();
1552+
CurrentIGMPtr IGM = getGenModule(classType->getClassOrBoundGenericClass());
1553+
emitLazyClassMetadata(*IGM.get(), classType);
1554+
}
1555+
15471556
while (!LazySpecializedClassMetadata.empty()) {
15481557
CanType classType = LazySpecializedClassMetadata.pop_back_val();
15491558
CurrentIGMPtr IGM = getGenModule(classType->getClassOrBoundGenericClass());
@@ -1636,6 +1645,12 @@ bool IRGenerator::hasLazyMetadata(TypeDecl *type) {
16361645
return isLazy;
16371646
}
16381647

1648+
void IRGenerator::noteUseOfClassMetadata(CanType classType) {
1649+
if (LazilyEmittedClassMetadata.insert(classType.getPointer()).second) {
1650+
LazyClassMetadata.push_back(classType);
1651+
}
1652+
}
1653+
16391654
void IRGenerator::noteUseOfSpecializedClassMetadata(CanType classType) {
16401655
if (LazilyEmittedSpecializedClassMetadata.insert(classType.getPointer()).second) {
16411656
LazySpecializedClassMetadata.push_back(classType);
@@ -5151,6 +5166,8 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
51515166
if (auto *classDecl = dyn_cast<ClassDecl>(nominal)) {
51525167
if (classDecl->isGenericContext()) {
51535168
IRGen.noteUseOfSpecializedClassMetadata(concreteType);
5169+
} else {
5170+
IRGen.noteUseOfClassMetadata(concreteType);
51545171
}
51555172
}
51565173
}

lib/IRGen/GenMeta.cpp

Lines changed: 47 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4996,64 +4996,74 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
49964996
}
49974997
}
49984998

4999-
void irgen::emitEmbeddedClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
5000-
const ClassLayout &fragileLayout) {
5001-
PrettyStackTraceDecl stackTraceRAII("emitting metadata for", classDecl);
5002-
assert(!classDecl->isForeign());
4999+
static void emitEmbeddedVTable(IRGenModule &IGM, CanType classTy,
5000+
SILVTable *vtable) {
5001+
SILType classType = SILType::getPrimitiveObjectType(classTy);
5002+
auto &classTI = IGM.getTypeInfo(classType).as<ClassTypeInfo>();
50035003

5004-
// Set up a dummy global to stand in for the metadata object while we produce
5005-
// relative references.
5006-
ConstantInitBuilder builder(IGM);
5007-
auto init = builder.beginStruct();
5008-
init.setPacked(true);
5004+
auto &fragileLayout =
5005+
classTI.getClassLayout(IGM, classType, /*forBackwardDeployment=*/true);
50095006

5007+
ClassDecl *classDecl = classType.getClassOrBoundGenericClass();
50105008
auto strategy = IGM.getClassMetadataStrategy(classDecl);
50115009
assert(strategy == ClassMetadataStrategy::FixedOrUpdate ||
50125010
strategy == ClassMetadataStrategy::Fixed);
50135011

5014-
FixedClassMetadataBuilder metadataBuilder(IGM, classDecl, init,
5015-
fragileLayout);
5016-
metadataBuilder.layout();
5017-
bool canBeConstant = metadataBuilder.canBeConstant();
5012+
ConstantInitBuilder initBuilder(IGM);
5013+
auto init = initBuilder.beginStruct();
5014+
init.setPacked(true);
5015+
5016+
assert(vtable);
50185017

5019-
CanType declaredType = classDecl->getDeclaredType()->getCanonicalType();
5018+
FixedClassMetadataBuilder builder(IGM, classDecl, init, fragileLayout,
5019+
vtable);
5020+
builder.layout();
5021+
bool canBeConstant = builder.canBeConstant();
50205022

50215023
StringRef section{};
5022-
bool isPattern = false;
5023-
auto var = IGM.defineTypeMetadata(declaredType, isPattern, canBeConstant,
5024+
auto var = IGM.defineTypeMetadata(classTy, /*isPattern*/ false, canBeConstant,
50245025
init.finishAndCreateFuture(), section);
50255026
(void)var;
50265027
}
50275028

5028-
void irgen::emitLazySpecializedClassMetadata(IRGenModule &IGM,
5029-
CanType classTy) {
5029+
void irgen::emitEmbeddedClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
5030+
const ClassLayout &fragileLayout) {
5031+
PrettyStackTraceDecl stackTraceRAII("emitting metadata for", classDecl);
5032+
assert(!classDecl->isForeign());
5033+
CanType declaredType = classDecl->getDeclaredType()->getCanonicalType();
5034+
SILVTable *vtable = IGM.getSILModule().lookUpVTable(classDecl);
5035+
emitEmbeddedVTable(IGM, declaredType, vtable);
5036+
}
5037+
5038+
void irgen::emitLazyClassMetadata(IRGenModule &IGM, CanType classTy) {
5039+
// Might already be emitted, skip if that's the case.
5040+
auto entity =
5041+
LinkEntity::forTypeMetadata(classTy, TypeMetadataAddress::AddressPoint);
5042+
auto *existingVar = cast<llvm::GlobalVariable>(
5043+
IGM.getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo()));
5044+
if (!existingVar->isDeclaration()) {
5045+
return;
5046+
}
5047+
50305048
auto &context = classTy->getNominalOrBoundGenericNominal()->getASTContext();
50315049
PrettyStackTraceType stackTraceRAII(
5032-
context, "emitting lazy specialized class metadata for", classTy);
5050+
context, "emitting lazy class metadata for", classTy);
50335051

50345052
SILType classType = SILType::getPrimitiveObjectType(classTy);
5035-
auto &classTI = IGM.getTypeInfo(classType).as<ClassTypeInfo>();
5036-
5037-
auto &fragileLayout =
5038-
classTI.getClassLayout(IGM, classType, /*forBackwardDeployment=*/true);
5039-
50405053
ClassDecl *classDecl = classType.getClassOrBoundGenericClass();
5054+
SILVTable *vtable = IGM.getSILModule().lookUpVTable(classDecl);
5055+
emitEmbeddedVTable(IGM, classTy, vtable);
5056+
}
50415057

5042-
ConstantInitBuilder initBuilder(IGM);
5043-
auto init = initBuilder.beginStruct();
5044-
init.setPacked(true);
5058+
void irgen::emitLazySpecializedClassMetadata(IRGenModule &IGM,
5059+
CanType classTy) {
5060+
auto &context = classTy->getNominalOrBoundGenericNominal()->getASTContext();
5061+
PrettyStackTraceType stackTraceRAII(
5062+
context, "emitting lazy specialized class metadata for", classTy);
50455063

5064+
SILType classType = SILType::getPrimitiveObjectType(classTy);
50465065
SILVTable *vtable = IGM.getSILModule().lookUpSpecializedVTable(classType);
5047-
assert(vtable);
5048-
5049-
FixedClassMetadataBuilder builder(IGM, classDecl, init, fragileLayout, vtable);
5050-
builder.layout();
5051-
bool canBeConstant = builder.canBeConstant();
5052-
5053-
StringRef section{};
5054-
auto var = IGM.defineTypeMetadata(classTy, false, canBeConstant,
5055-
init.finishAndCreateFuture(), section);
5056-
(void)var;
5066+
emitEmbeddedVTable(IGM, classTy, vtable);
50575067
}
50585068

50595069
void irgen::emitSpecializedGenericClassMetadata(IRGenModule &IGM, CanType type,

lib/IRGen/GenMeta.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ namespace irgen {
8383
/// Emit the type metadata accessor for a type for which it might be used.
8484
void emitLazyMetadataAccessor(IRGenModule &IGM, NominalTypeDecl *type);
8585

86+
void emitLazyClassMetadata(IRGenModule &IGM, CanType classType);
87+
8688
void emitLazySpecializedClassMetadata(IRGenModule &IGM, CanType classType);
8789

8890
void emitLazyCanonicalSpecializedMetadataAccessor(IRGenModule &IGM,

lib/IRGen/IRGenModule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,10 @@ class IRGenerator {
327327
/// The queue of lazy witness tables to emit.
328328
llvm::SmallVector<SILWitnessTable *, 4> LazyWitnessTables;
329329

330+
llvm::SmallVector<CanType, 4> LazyClassMetadata;
331+
332+
llvm::SmallPtrSet<TypeBase *, 4> LazilyEmittedClassMetadata;
333+
330334
llvm::SmallVector<CanType, 4> LazySpecializedClassMetadata;
331335

332336
llvm::SmallPtrSet<TypeBase *, 4> LazilyEmittedSpecializedClassMetadata;
@@ -476,6 +480,7 @@ class IRGenerator {
476480
}
477481
}
478482

483+
void noteUseOfClassMetadata(CanType classType);
479484
void noteUseOfSpecializedClassMetadata(CanType classType);
480485

481486
void noteUseOfTypeMetadata(NominalTypeDecl *type) {

lib/SIL/IR/SILModule.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,17 @@ SILVTable *SILModule::lookUpVTable(const ClassDecl *C,
518518
if (!Vtbl)
519519
return nullptr;
520520

521+
if (C->walkSuperclasses([&](ClassDecl *S) {
522+
SILVTable *Vtbl = getSILLoader()->lookupVTable(S);
523+
if (!Vtbl) {
524+
return TypeWalker::Action::Stop;
525+
}
526+
VTableMap[C] = Vtbl;
527+
return TypeWalker::Action::Continue;
528+
})) {
529+
return nullptr;
530+
}
531+
521532
// If we succeeded, map C -> VTbl in the table and return VTbl.
522533
VTableMap[C] = Vtbl;
523534
return Vtbl;

lib/SILOptimizer/IPO/CrossModuleOptimization.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,30 @@ void CrossModuleOptimization::makeDeclUsableFromInline(ValueDecl *decl) {
611611
auto &ctx = decl->getASTContext();
612612
auto *attr = new (ctx) UsableFromInlineAttr(/*implicit=*/true);
613613
decl->getAttrs().add(attr);
614+
615+
if (everything) {
616+
// Serialize vtables, their superclass vtables, and make all vfunctions
617+
// usable from inline.
618+
if (auto *classDecl = dyn_cast<ClassDecl>(decl)) {
619+
auto *vTable = M.lookUpVTable(classDecl);
620+
vTable->setSerialized(IsSerialized);
621+
for (auto &entry : vTable->getEntries()) {
622+
makeFunctionUsableFromInline(entry.getImplementation());
623+
}
624+
625+
classDecl->walkSuperclasses([&](ClassDecl *superClassDecl) {
626+
auto *vTable = M.lookUpVTable(superClassDecl);
627+
if (!vTable) {
628+
return TypeWalker::Action::Stop;
629+
}
630+
vTable->setSerialized(IsSerialized);
631+
for (auto &entry : vTable->getEntries()) {
632+
makeFunctionUsableFromInline(entry.getImplementation());
633+
}
634+
return TypeWalker::Action::Continue;
635+
});
636+
}
637+
}
614638
}
615639
if (auto *nominalCtx = dyn_cast<NominalTypeDecl>(decl->getDeclContext())) {
616640
makeDeclUsableFromInline(nominalCtx);

test/embedded/modules-classes.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %{python} %utils/split_file.py -o %t %s
3+
4+
// RUN: %target-swift-frontend -emit-module -o %t/MyModule.swiftmodule %t/MyModule.swift %S/Inputs/print.swift -enable-experimental-feature Embedded -parse-as-library
5+
// RUN: %target-swift-frontend -c -I %t %t/Main.swift -enable-experimental-feature Embedded -o %t/a.o
6+
// RUN: %target-clang -x c -c %S/Inputs/print.c -o %t/print.o
7+
// RUN: %target-clang %t/a.o %t/print.o -o %t/a.out
8+
// RUN: %target-run %t/a.out | %FileCheck %s
9+
10+
// REQUIRES: executable_test
11+
// REQUIRES: VENDOR=apple
12+
// REQUIRES: OS=macosx
13+
14+
// BEGIN MyModule.swift
15+
16+
internal class BaseClass {
17+
18+
}
19+
20+
final internal class MyClass: BaseClass {
21+
func foo() { print("MyClass.foo") }
22+
}
23+
24+
public func foo() {
25+
let o = MyClass()
26+
o.foo()
27+
}
28+
29+
// BEGIN Main.swift
30+
31+
import MyModule
32+
33+
func test() {
34+
foo()
35+
}
36+
37+
test()
38+
39+
// CHECK: MyClass.foo

0 commit comments

Comments
 (0)