mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[embedded] Serialize+deserialize vtables, fix using non-generic classes from other modules in embedded Swift
This commit is contained in:
@@ -2901,6 +2901,9 @@ CanType irgen::getSuperclassForMetadata(IRGenModule &IGM, CanType type,
|
||||
|
||||
ClassMetadataStrategy
|
||||
IRGenModule::getClassMetadataStrategy(const ClassDecl *theClass) {
|
||||
if (Context.LangOpts.hasFeature(Feature::Embedded))
|
||||
return ClassMetadataStrategy::Fixed;
|
||||
|
||||
SILType selfType = getSelfType(theClass);
|
||||
auto &selfTI = getTypeInfo(selfType).as<ClassTypeInfo>();
|
||||
|
||||
|
||||
@@ -1436,6 +1436,7 @@ void IRGenerator::emitLazyDefinitions() {
|
||||
assert(LazyWitnessTables.empty());
|
||||
assert(LazyCanonicalSpecializedMetadataAccessors.empty());
|
||||
assert(LazyMetadataAccessors.empty());
|
||||
// LazyClassMetadata is allowed
|
||||
// LazySpecializedClassMetadata is allowed
|
||||
}
|
||||
|
||||
@@ -1446,7 +1447,9 @@ void IRGenerator::emitLazyDefinitions() {
|
||||
!LazyFunctionDefinitions.empty() || !LazyWitnessTables.empty() ||
|
||||
!LazyCanonicalSpecializedMetadataAccessors.empty() ||
|
||||
!LazyMetadataAccessors.empty() ||
|
||||
!LazySpecializedClassMetadata.empty()) {
|
||||
!LazyClassMetadata.empty() ||
|
||||
!LazySpecializedClassMetadata.empty()
|
||||
) {
|
||||
// Emit any lazy type metadata we require.
|
||||
while (!LazyTypeMetadata.empty()) {
|
||||
NominalTypeDecl *type = LazyTypeMetadata.pop_back_val();
|
||||
@@ -1544,6 +1547,12 @@ void IRGenerator::emitLazyDefinitions() {
|
||||
emitLazyMetadataAccessor(*IGM.get(), nominal);
|
||||
}
|
||||
|
||||
while (!LazyClassMetadata.empty()) {
|
||||
CanType classType = LazyClassMetadata.pop_back_val();
|
||||
CurrentIGMPtr IGM = getGenModule(classType->getClassOrBoundGenericClass());
|
||||
emitLazyClassMetadata(*IGM.get(), classType);
|
||||
}
|
||||
|
||||
while (!LazySpecializedClassMetadata.empty()) {
|
||||
CanType classType = LazySpecializedClassMetadata.pop_back_val();
|
||||
CurrentIGMPtr IGM = getGenModule(classType->getClassOrBoundGenericClass());
|
||||
@@ -1636,6 +1645,12 @@ bool IRGenerator::hasLazyMetadata(TypeDecl *type) {
|
||||
return isLazy;
|
||||
}
|
||||
|
||||
void IRGenerator::noteUseOfClassMetadata(CanType classType) {
|
||||
if (LazilyEmittedClassMetadata.insert(classType.getPointer()).second) {
|
||||
LazyClassMetadata.push_back(classType);
|
||||
}
|
||||
}
|
||||
|
||||
void IRGenerator::noteUseOfSpecializedClassMetadata(CanType classType) {
|
||||
if (LazilyEmittedSpecializedClassMetadata.insert(classType.getPointer()).second) {
|
||||
LazySpecializedClassMetadata.push_back(classType);
|
||||
@@ -5151,6 +5166,8 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
|
||||
if (auto *classDecl = dyn_cast<ClassDecl>(nominal)) {
|
||||
if (classDecl->isGenericContext()) {
|
||||
IRGen.noteUseOfSpecializedClassMetadata(concreteType);
|
||||
} else {
|
||||
IRGen.noteUseOfClassMetadata(concreteType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4996,35 +4996,65 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
|
||||
}
|
||||
}
|
||||
|
||||
void irgen::emitEmbeddedClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
|
||||
const ClassLayout &fragileLayout) {
|
||||
PrettyStackTraceDecl stackTraceRAII("emitting metadata for", classDecl);
|
||||
assert(!classDecl->isForeign());
|
||||
static void emitEmbeddedVTable(IRGenModule &IGM, CanType classTy,
|
||||
SILVTable *vtable) {
|
||||
SILType classType = SILType::getPrimitiveObjectType(classTy);
|
||||
auto &classTI = IGM.getTypeInfo(classType).as<ClassTypeInfo>();
|
||||
|
||||
// Set up a dummy global to stand in for the metadata object while we produce
|
||||
// relative references.
|
||||
ConstantInitBuilder builder(IGM);
|
||||
auto init = builder.beginStruct();
|
||||
init.setPacked(true);
|
||||
auto &fragileLayout =
|
||||
classTI.getClassLayout(IGM, classType, /*forBackwardDeployment=*/true);
|
||||
|
||||
ClassDecl *classDecl = classType.getClassOrBoundGenericClass();
|
||||
auto strategy = IGM.getClassMetadataStrategy(classDecl);
|
||||
assert(strategy == ClassMetadataStrategy::FixedOrUpdate ||
|
||||
strategy == ClassMetadataStrategy::Fixed);
|
||||
|
||||
FixedClassMetadataBuilder metadataBuilder(IGM, classDecl, init,
|
||||
fragileLayout);
|
||||
metadataBuilder.layout();
|
||||
bool canBeConstant = metadataBuilder.canBeConstant();
|
||||
ConstantInitBuilder initBuilder(IGM);
|
||||
auto init = initBuilder.beginStruct();
|
||||
init.setPacked(true);
|
||||
|
||||
CanType declaredType = classDecl->getDeclaredType()->getCanonicalType();
|
||||
assert(vtable);
|
||||
|
||||
FixedClassMetadataBuilder builder(IGM, classDecl, init, fragileLayout,
|
||||
vtable);
|
||||
builder.layout();
|
||||
bool canBeConstant = builder.canBeConstant();
|
||||
|
||||
StringRef section{};
|
||||
bool isPattern = false;
|
||||
auto var = IGM.defineTypeMetadata(declaredType, isPattern, canBeConstant,
|
||||
auto var = IGM.defineTypeMetadata(classTy, /*isPattern*/ false, canBeConstant,
|
||||
init.finishAndCreateFuture(), section);
|
||||
(void)var;
|
||||
}
|
||||
|
||||
void irgen::emitEmbeddedClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
|
||||
const ClassLayout &fragileLayout) {
|
||||
PrettyStackTraceDecl stackTraceRAII("emitting metadata for", classDecl);
|
||||
assert(!classDecl->isForeign());
|
||||
CanType declaredType = classDecl->getDeclaredType()->getCanonicalType();
|
||||
SILVTable *vtable = IGM.getSILModule().lookUpVTable(classDecl);
|
||||
emitEmbeddedVTable(IGM, declaredType, vtable);
|
||||
}
|
||||
|
||||
void irgen::emitLazyClassMetadata(IRGenModule &IGM, CanType classTy) {
|
||||
// Might already be emitted, skip if that's the case.
|
||||
auto entity =
|
||||
LinkEntity::forTypeMetadata(classTy, TypeMetadataAddress::AddressPoint);
|
||||
auto *existingVar = cast<llvm::GlobalVariable>(
|
||||
IGM.getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo()));
|
||||
if (!existingVar->isDeclaration()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto &context = classTy->getNominalOrBoundGenericNominal()->getASTContext();
|
||||
PrettyStackTraceType stackTraceRAII(
|
||||
context, "emitting lazy class metadata for", classTy);
|
||||
|
||||
SILType classType = SILType::getPrimitiveObjectType(classTy);
|
||||
ClassDecl *classDecl = classType.getClassOrBoundGenericClass();
|
||||
SILVTable *vtable = IGM.getSILModule().lookUpVTable(classDecl);
|
||||
emitEmbeddedVTable(IGM, classTy, vtable);
|
||||
}
|
||||
|
||||
void irgen::emitLazySpecializedClassMetadata(IRGenModule &IGM,
|
||||
CanType classTy) {
|
||||
auto &context = classTy->getNominalOrBoundGenericNominal()->getASTContext();
|
||||
@@ -5032,28 +5062,8 @@ void irgen::emitLazySpecializedClassMetadata(IRGenModule &IGM,
|
||||
context, "emitting lazy specialized class metadata for", classTy);
|
||||
|
||||
SILType classType = SILType::getPrimitiveObjectType(classTy);
|
||||
auto &classTI = IGM.getTypeInfo(classType).as<ClassTypeInfo>();
|
||||
|
||||
auto &fragileLayout =
|
||||
classTI.getClassLayout(IGM, classType, /*forBackwardDeployment=*/true);
|
||||
|
||||
ClassDecl *classDecl = classType.getClassOrBoundGenericClass();
|
||||
|
||||
ConstantInitBuilder initBuilder(IGM);
|
||||
auto init = initBuilder.beginStruct();
|
||||
init.setPacked(true);
|
||||
|
||||
SILVTable *vtable = IGM.getSILModule().lookUpSpecializedVTable(classType);
|
||||
assert(vtable);
|
||||
|
||||
FixedClassMetadataBuilder builder(IGM, classDecl, init, fragileLayout, vtable);
|
||||
builder.layout();
|
||||
bool canBeConstant = builder.canBeConstant();
|
||||
|
||||
StringRef section{};
|
||||
auto var = IGM.defineTypeMetadata(classTy, false, canBeConstant,
|
||||
init.finishAndCreateFuture(), section);
|
||||
(void)var;
|
||||
emitEmbeddedVTable(IGM, classTy, vtable);
|
||||
}
|
||||
|
||||
void irgen::emitSpecializedGenericClassMetadata(IRGenModule &IGM, CanType type,
|
||||
|
||||
@@ -83,6 +83,8 @@ namespace irgen {
|
||||
/// Emit the type metadata accessor for a type for which it might be used.
|
||||
void emitLazyMetadataAccessor(IRGenModule &IGM, NominalTypeDecl *type);
|
||||
|
||||
void emitLazyClassMetadata(IRGenModule &IGM, CanType classType);
|
||||
|
||||
void emitLazySpecializedClassMetadata(IRGenModule &IGM, CanType classType);
|
||||
|
||||
void emitLazyCanonicalSpecializedMetadataAccessor(IRGenModule &IGM,
|
||||
|
||||
@@ -327,6 +327,10 @@ private:
|
||||
/// The queue of lazy witness tables to emit.
|
||||
llvm::SmallVector<SILWitnessTable *, 4> LazyWitnessTables;
|
||||
|
||||
llvm::SmallVector<CanType, 4> LazyClassMetadata;
|
||||
|
||||
llvm::SmallPtrSet<TypeBase *, 4> LazilyEmittedClassMetadata;
|
||||
|
||||
llvm::SmallVector<CanType, 4> LazySpecializedClassMetadata;
|
||||
|
||||
llvm::SmallPtrSet<TypeBase *, 4> LazilyEmittedSpecializedClassMetadata;
|
||||
@@ -476,6 +480,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void noteUseOfClassMetadata(CanType classType);
|
||||
void noteUseOfSpecializedClassMetadata(CanType classType);
|
||||
|
||||
void noteUseOfTypeMetadata(NominalTypeDecl *type) {
|
||||
|
||||
@@ -518,6 +518,17 @@ SILVTable *SILModule::lookUpVTable(const ClassDecl *C,
|
||||
if (!Vtbl)
|
||||
return nullptr;
|
||||
|
||||
if (C->walkSuperclasses([&](ClassDecl *S) {
|
||||
SILVTable *Vtbl = getSILLoader()->lookupVTable(S);
|
||||
if (!Vtbl) {
|
||||
return TypeWalker::Action::Stop;
|
||||
}
|
||||
VTableMap[C] = Vtbl;
|
||||
return TypeWalker::Action::Continue;
|
||||
})) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If we succeeded, map C -> VTbl in the table and return VTbl.
|
||||
VTableMap[C] = Vtbl;
|
||||
return Vtbl;
|
||||
|
||||
@@ -611,6 +611,30 @@ void CrossModuleOptimization::makeDeclUsableFromInline(ValueDecl *decl) {
|
||||
auto &ctx = decl->getASTContext();
|
||||
auto *attr = new (ctx) UsableFromInlineAttr(/*implicit=*/true);
|
||||
decl->getAttrs().add(attr);
|
||||
|
||||
if (everything) {
|
||||
// Serialize vtables, their superclass vtables, and make all vfunctions
|
||||
// usable from inline.
|
||||
if (auto *classDecl = dyn_cast<ClassDecl>(decl)) {
|
||||
auto *vTable = M.lookUpVTable(classDecl);
|
||||
vTable->setSerialized(IsSerialized);
|
||||
for (auto &entry : vTable->getEntries()) {
|
||||
makeFunctionUsableFromInline(entry.getImplementation());
|
||||
}
|
||||
|
||||
classDecl->walkSuperclasses([&](ClassDecl *superClassDecl) {
|
||||
auto *vTable = M.lookUpVTable(superClassDecl);
|
||||
if (!vTable) {
|
||||
return TypeWalker::Action::Stop;
|
||||
}
|
||||
vTable->setSerialized(IsSerialized);
|
||||
for (auto &entry : vTable->getEntries()) {
|
||||
makeFunctionUsableFromInline(entry.getImplementation());
|
||||
}
|
||||
return TypeWalker::Action::Continue;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (auto *nominalCtx = dyn_cast<NominalTypeDecl>(decl->getDeclContext())) {
|
||||
makeDeclUsableFromInline(nominalCtx);
|
||||
|
||||
39
test/embedded/modules-classes.swift
Normal file
39
test/embedded/modules-classes.swift
Normal file
@@ -0,0 +1,39 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %{python} %utils/split_file.py -o %t %s
|
||||
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/MyModule.swiftmodule %t/MyModule.swift %S/Inputs/print.swift -enable-experimental-feature Embedded -parse-as-library
|
||||
// RUN: %target-swift-frontend -c -I %t %t/Main.swift -enable-experimental-feature Embedded -o %t/a.o
|
||||
// RUN: %target-clang -x c -c %S/Inputs/print.c -o %t/print.o
|
||||
// RUN: %target-clang %t/a.o %t/print.o -o %t/a.out
|
||||
// RUN: %target-run %t/a.out | %FileCheck %s
|
||||
|
||||
// REQUIRES: executable_test
|
||||
// REQUIRES: VENDOR=apple
|
||||
// REQUIRES: OS=macosx
|
||||
|
||||
// BEGIN MyModule.swift
|
||||
|
||||
internal class BaseClass {
|
||||
|
||||
}
|
||||
|
||||
final internal class MyClass: BaseClass {
|
||||
func foo() { print("MyClass.foo") }
|
||||
}
|
||||
|
||||
public func foo() {
|
||||
let o = MyClass()
|
||||
o.foo()
|
||||
}
|
||||
|
||||
// BEGIN Main.swift
|
||||
|
||||
import MyModule
|
||||
|
||||
func test() {
|
||||
foo()
|
||||
}
|
||||
|
||||
test()
|
||||
|
||||
// CHECK: MyClass.foo
|
||||
Reference in New Issue
Block a user