Skip to content

Commit dc6d784

Browse files
authored
Merge pull request #68434 from kubamracek/embedded-classes
[embedded] Add support for (non-generic) classes in embedded Swift
2 parents 93c332b + 51f54b4 commit dc6d784

File tree

9 files changed

+148
-2
lines changed

9 files changed

+148
-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: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ template <class Impl> class ClassMetadataVisitor
6868
static_assert(MetadataAdjustmentIndex::Class == 3,
6969
"Adjustment index must be synchronized with this layout");
7070

71+
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
72+
asImpl().noteAddressPoint();
73+
asImpl().addSuperclass();
74+
asImpl().addDestructorFunction();
75+
addEmbeddedClassMembers(Target);
76+
return;
77+
}
78+
7179
// Pointer to layout string
7280
asImpl().addLayoutStringPointer();
7381

@@ -185,6 +193,21 @@ template <class Impl> class ClassMetadataVisitor
185193
asImpl().addVTableEntries(theClass);
186194
}
187195

196+
/// Add fields associated with the given class and its bases.
197+
void addEmbeddedClassMembers(ClassDecl *theClass) {
198+
// Visit the superclass first.
199+
if (auto *superclassDecl = theClass->getSuperclassDecl()) {
200+
addEmbeddedClassMembers(superclassDecl);
201+
}
202+
203+
// Note that we have to emit a global variable storing the metadata
204+
// start offset, or access remaining fields relative to one.
205+
asImpl().noteStartOfImmediateMembers(theClass);
206+
207+
// Add vtable entries.
208+
asImpl().addVTableEntries(theClass);
209+
}
210+
188211
friend SILVTableVisitor<Impl>;
189212
void addMethod(SILDeclRef declRef) {
190213
// 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: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3949,6 +3949,12 @@ namespace {
39493949
}
39503950

39513951
void addDestructorFunction() {
3952+
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
3953+
auto dtorRef = SILDeclRef(Target->getDestructor(), SILDeclRef::Kind::Deallocator);
3954+
addReifiedVTableEntry(dtorRef);
3955+
return;
3956+
}
3957+
39523958
if (asImpl().getFieldLayout().hasObjCImplementation())
39533959
return;
39543960

@@ -4967,6 +4973,36 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
49674973
}
49684974
}
49694975

4976+
void irgen::emitEmbeddedClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
4977+
const ClassLayout &fragileLayout) {
4978+
PrettyStackTraceDecl stackTraceRAII("emitting metadata for", classDecl);
4979+
assert(!classDecl->isForeign());
4980+
4981+
// Set up a dummy global to stand in for the metadata object while we produce
4982+
// relative references.
4983+
ConstantInitBuilder builder(IGM);
4984+
auto init = builder.beginStruct();
4985+
init.setPacked(true);
4986+
4987+
auto strategy = IGM.getClassMetadataStrategy(classDecl);
4988+
assert(strategy == ClassMetadataStrategy::FixedOrUpdate ||
4989+
strategy == ClassMetadataStrategy::Fixed);
4990+
4991+
FixedClassMetadataBuilder metadataBuilder(IGM, classDecl, init,
4992+
fragileLayout);
4993+
metadataBuilder.layout();
4994+
bool canBeConstant = metadataBuilder.canBeConstant();
4995+
metadataBuilder.createMetadataAccessFunction();
4996+
4997+
CanType declaredType = classDecl->getDeclaredType()->getCanonicalType();
4998+
4999+
StringRef section{};
5000+
bool isPattern = false;
5001+
auto var = IGM.defineTypeMetadata(declaredType, isPattern, canBeConstant,
5002+
init.finishAndCreateFuture(), section);
5003+
(void)var;
5004+
}
5005+
49705006
void irgen::emitSpecializedGenericClassMetadata(IRGenModule &IGM, CanType type,
49715007
ClassDecl &decl) {
49725008
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");
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %target-swift-emit-ir %s -parse-stdlib -enable-experimental-feature Embedded -target arm64e-apple-none | %FileCheck %s
2+
3+
public class MyClass {
4+
func foo() { }
5+
func bar() { }
6+
}
7+
8+
public class MySubClass: MyClass {
9+
override func foo() { }
10+
}
11+
12+
// CHECK: @"$s4main7MyClassCN" = {{.*}}<{ ptr, ptr, ptr, ptr, ptr }> <{ ptr null, ptr @"$s4main7MyClassCfD", ptr @"$s4main7MyClassC3fooyyF", ptr @"$s4main7MyClassC3baryyF", ptr @"$s4main7MyClassCACycfC" }>
13+
// CHECK: @"$s4main10MySubClassCN" = {{.*}}<{ ptr, ptr, ptr, ptr, ptr }> <{ ptr @"$s4main7MyClassCN", ptr @"$s4main10MySubClassCfD", ptr @"$s4main10MySubClassC3fooyyF", ptr @"$s4main7MyClassC3baryyF", ptr @"$s4main10MySubClassCACycfC" }>
14+
15+
// CHECK: define {{.*}}void @"$s4main4test1xyAA7MyClassC_tF"(ptr %0)
16+
public func test(x: MyClass) {
17+
18+
x.foo() // goes through the vtable
19+
// CHECK: %1 = load ptr, ptr %0
20+
// CHECK: %2 = getelementptr inbounds ptr, ptr %1, i64 2
21+
// CHECK: %3 = load ptr, ptr %2
22+
// CHECK: call swiftcc void %3(ptr swiftself %0)
23+
24+
x.bar() // does not go through the vtable
25+
// CHECK: call swiftcc void @"$s4main7MyClassC3baryyF"
26+
27+
let y = MySubClass()
28+
// CHECK: call swiftcc %swift.metadata_response @"$s4main10MySubClassCMa"
29+
// CHECK: call swiftcc ptr @"$s4main10MySubClassCACycfC"
30+
31+
y.foo() // does not go through the vtable
32+
// CHECK: call swiftcc void @"$s4main10MySubClassC3fooyyF"
33+
34+
y.bar() // does not go through the vtable
35+
// CHECK: call swiftcc void @"$s4main7MyClassC3baryyF"
36+
37+
}

test/embedded/classes-no-stdlib.swift

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

0 commit comments

Comments
 (0)