Skip to content

Commit ae63e75

Browse files
committed
[embedded] Add support for (non-generic) classes in embedded Swift
- In embedded Swift, classes get a simplified metadata: Basically just a vtable + destructor + superclass pointer. - Only non-resilient (intended as permanent restriction), non-generic classes (for now) supported. - Relax the check that prohibits metadata emission and usage to allow classes.
1 parent ce11162 commit ae63e75

File tree

8 files changed

+106
-2
lines changed

8 files changed

+106
-2
lines changed

include/swift/IRGen/Linking.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ inline bool isEmbedded(CanType t) {
8989
return t->getASTContext().LangOpts.hasFeature(Feature::Embedded);
9090
}
9191

92+
inline bool isMetadataAllowedInEmbedded(CanType t) {
93+
return isa<ClassType>(t);
94+
}
95+
9296
inline bool isEmbedded(Decl *d) {
9397
return d->getASTContext().LangOpts.hasFeature(Feature::Embedded);
9498
}
@@ -840,7 +844,7 @@ class LinkEntity {
840844
static LinkEntity forTypeMetadata(CanType concreteType,
841845
TypeMetadataAddress addr) {
842846
assert(!isObjCImplementation(concreteType));
843-
assert(!isEmbedded(concreteType));
847+
assert(!isEmbedded(concreteType) || isMetadataAllowedInEmbedded(concreteType));
844848
LinkEntity entity;
845849
entity.setForType(Kind::TypeMetadata, concreteType);
846850
entity.Data |= LINKENTITY_SET_FIELD(MetadataAddress, unsigned(addr));

lib/IRGen/ClassMetadataVisitor.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ template <class Impl> class ClassMetadataVisitor
9999
addClassMembers(Target, Target);
100100
}
101101

102+
void embeddedLayout() {
103+
asImpl().noteAddressPoint();
104+
asImpl().addSuperclass();
105+
asImpl().addDestructorFunction();
106+
addEmbeddedClassMembers(Target);
107+
}
108+
102109
/// Notes the beginning of the field offset vector for a particular ancestor
103110
/// of a generic-layout class.
104111
void noteStartOfFieldOffsets(ClassDecl *whichClass) {}
@@ -185,6 +192,21 @@ template <class Impl> class ClassMetadataVisitor
185192
asImpl().addVTableEntries(theClass);
186193
}
187194

195+
/// Add fields associated with the given class and its bases.
196+
void addEmbeddedClassMembers(ClassDecl *theClass) {
197+
// Visit the superclass first.
198+
if (auto *superclassDecl = theClass->getSuperclassDecl()) {
199+
addEmbeddedClassMembers(superclassDecl);
200+
}
201+
202+
// Note that we have to emit a global variable storing the metadata
203+
// start offset, or access remaining fields relative to one.
204+
asImpl().noteStartOfImmediateMembers(theClass);
205+
206+
// Add vtable entries.
207+
asImpl().addVTableEntries(theClass);
208+
}
209+
188210
friend SILVTableVisitor<Impl>;
189211
void addMethod(SILDeclRef declRef) {
190212
// Does this method require a reified runtime vtable entry?

lib/IRGen/GenClass.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,8 @@ void IRGenModule::emitClassDecl(ClassDecl *D) {
10781078
if (!D->getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
10791079
emitClassMetadata(*this, D, fragileLayout, resilientLayout);
10801080
emitFieldDescriptor(D);
1081+
} else {
1082+
emitEmbeddedClassMetadata(*this, D, fragileLayout);
10811083
}
10821084

10831085
IRGen.addClassForEagerInitialization(D);

lib/IRGen/GenDecl.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4970,6 +4970,11 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
49704970
: LinkEntity::forTypeMetadata(
49714971
concreteType, TypeMetadataAddress::FullMetadata));
49724972

4973+
if (Context.LangOpts.hasFeature(Feature::Embedded)) {
4974+
entity = LinkEntity::forTypeMetadata(concreteType,
4975+
TypeMetadataAddress::AddressPoint);
4976+
}
4977+
49734978
auto DbgTy = DebugTypeInfo::getGlobalMetadata(
49744979
MetatypeType::get(concreteType),
49754980
entity.getDefaultDeclarationType(*this)->getPointerTo(), Size(0),
@@ -4991,6 +4996,10 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
49914996

49924997
LinkInfo link = LinkInfo::get(*this, entity, ForDefinition);
49934998
markGlobalAsUsedBasedOnLinkage(*this, link, var);
4999+
5000+
if (Context.LangOpts.hasFeature(Feature::Embedded)) {
5001+
return var;
5002+
}
49945003

49955004
/// For concrete metadata, we want to use the initializer on the
49965005
/// "full metadata", and define the "direct" address point as an alias.

lib/IRGen/GenMeta.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4967,6 +4967,35 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
49674967
}
49684968
}
49694969

4970+
void irgen::emitEmbeddedClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
4971+
const ClassLayout &fragileLayout) {
4972+
assert(!classDecl->isForeign());
4973+
PrettyStackTraceDecl stackTraceRAII("emitting metadata for", classDecl);
4974+
4975+
// Set up a dummy global to stand in for the metadata object while we produce
4976+
// relative references.
4977+
ConstantInitBuilder builder(IGM);
4978+
auto init = builder.beginStruct();
4979+
init.setPacked(true);
4980+
4981+
auto strategy = IGM.getClassMetadataStrategy(classDecl);
4982+
assert(strategy == ClassMetadataStrategy::FixedOrUpdate ||
4983+
strategy == ClassMetadataStrategy::Fixed);
4984+
4985+
FixedClassMetadataBuilder metadataBuilder(IGM, classDecl, init,
4986+
fragileLayout);
4987+
metadataBuilder.embeddedLayout();
4988+
bool canBeConstant = metadataBuilder.canBeConstant();
4989+
metadataBuilder.createMetadataAccessFunction();
4990+
4991+
CanType declaredType = classDecl->getDeclaredType()->getCanonicalType();
4992+
4993+
StringRef section{};
4994+
bool isPattern = false;
4995+
auto var = IGM.defineTypeMetadata(declaredType, isPattern, canBeConstant,
4996+
init.finishAndCreateFuture(), section);
4997+
}
4998+
49704999
void irgen::emitSpecializedGenericClassMetadata(IRGenModule &IGM, CanType type,
49715000
ClassDecl &decl) {
49725001
assert(decl.isGenericContext());

lib/IRGen/GenMeta.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ namespace irgen {
5959
const ClassLayout &fragileLayout,
6060
const ClassLayout &resilientLayout);
6161

62+
/// Emit "embedded Swift" class metadata (a simple vtable) for the given class
63+
/// declaration.
64+
void emitEmbeddedClassMetadata(IRGenModule &IGM, ClassDecl *theClass,
65+
const ClassLayout &fragileLayout);
66+
6267
/// Emit the constant initializer of the type metadata candidate for
6368
/// the given foreign class declaration.
6469
llvm::Constant *emitForeignTypeMetadataInitializer(IRGenModule &IGM,

lib/IRGen/MetadataRequest.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3303,7 +3303,8 @@ llvm::Value *IRGenFunction::emitTypeMetadataRef(CanType type) {
33033303
MetadataResponse
33043304
IRGenFunction::emitTypeMetadataRef(CanType type,
33053305
DynamicMetadataRequest request) {
3306-
if (type->getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
3306+
if (type->getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
3307+
!isMetadataAllowedInEmbedded(type)) {
33073308
llvm::errs() << "Metadata pointer requested in embedded Swift for type "
33083309
<< type << "\n";
33093310
assert(0 && "metadata used in embedded mode");

test/embedded/classes-no-stdlib.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-swift-emit-ir %s -parse-stdlib -enable-experimental-feature Embedded -target arm64e-apple-none | %FileCheck %s
2+
3+
// TODO: investigate why windows is generating more metadata.
4+
// XFAIL: OS=windows-msvc
5+
6+
public class MyClass {}
7+
8+
// CHECK-DAG: @"$s4main7MyClassCN" = {{.*}}<{ ptr, ptr, ptr }> <{ ptr null, ptr @"$s4main7MyClassCfD", ptr @"$s4main7MyClassCACycfC" }>
9+
// CHECK-DAG: define {{.*}}ptr @"$s4main7MyClassCfd"
10+
// CHECK-DAG: define {{.*}}void @"$s4main7MyClassCfD"
11+
// CHECK-DAG: define {{.*}}ptr @"$s4main7MyClassCACycfC"
12+
// CHECK-DAG: define {{.*}}ptr @"$s4main7MyClassCACycfc"
13+
// CHECK-DAG: define {{.*}}%swift.metadata_response @"$s4main7MyClassCMa"
14+
15+
public func foo() -> MyClass {
16+
return MyClass()
17+
}
18+
// CHECK-DAG: define {{.*}}ptr @"$s4main3fooAA7MyClassCyF"
19+
20+
public class MySubClass: MyClass {}
21+
22+
// CHECK-DAG: @"$s4main10MySubClassCN" = {{.*}}<{ ptr, ptr, ptr }> <{ ptr @"$s4main7MyClassCN", ptr @"$s4main10MySubClassCfD", ptr @"$s4main10MySubClassCACycfC" }>
23+
// CHECK-DAG: define {{.*}}ptr @"$s4main10MySubClassCACycfC"
24+
// CHECK-DAG: define {{.*}}ptr @"$s4main10MySubClassCACycfc"
25+
// CHECK-DAG: define {{.*}}ptr @"$s4main10MySubClassCfd"
26+
// CHECK-DAG: define {{.*}}void @"$s4main10MySubClassCfD"
27+
// CHECK-DAG: define {{.*}}%swift.metadata_response @"$s4main10MySubClassCMa"
28+
29+
public func bar() -> MyClass {
30+
return MySubClass()
31+
}
32+
// CHECK-DAG: define {{.*}}ptr @"$s4main3barAA7MyClassCyF"

0 commit comments

Comments
 (0)