-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[embedded] Add support for (non-generic) classes in embedded Swift #68434
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3949,6 +3949,12 @@ namespace { | |
} | ||
|
||
void addDestructorFunction() { | ||
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) { | ||
auto dtorRef = SILDeclRef(Target->getDestructor(), SILDeclRef::Kind::Deallocator); | ||
addReifiedVTableEntry(dtorRef); | ||
return; | ||
} | ||
|
||
if (asImpl().getFieldLayout().hasObjCImplementation()) | ||
return; | ||
|
||
|
@@ -4967,6 +4973,36 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl, | |
} | ||
} | ||
|
||
void irgen::emitEmbeddedClassMetadata(IRGenModule &IGM, ClassDecl *classDecl, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need class embedded class metadata at all? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, and that's what this function is trying to do (to emit a simple metadata record with a vtable + superclass pointer), I think the only extra leftover is |
||
const ClassLayout &fragileLayout) { | ||
PrettyStackTraceDecl stackTraceRAII("emitting metadata for", classDecl); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you put this above the assertion? If the assertion fires, might be nice to have this diagnostic :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done! |
||
assert(!classDecl->isForeign()); | ||
|
||
// 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 strategy = IGM.getClassMetadataStrategy(classDecl); | ||
assert(strategy == ClassMetadataStrategy::FixedOrUpdate || | ||
strategy == ClassMetadataStrategy::Fixed); | ||
|
||
FixedClassMetadataBuilder metadataBuilder(IGM, classDecl, init, | ||
fragileLayout); | ||
metadataBuilder.layout(); | ||
bool canBeConstant = metadataBuilder.canBeConstant(); | ||
metadataBuilder.createMetadataAccessFunction(); | ||
|
||
CanType declaredType = classDecl->getDeclaredType()->getCanonicalType(); | ||
|
||
StringRef section{}; | ||
bool isPattern = false; | ||
auto var = IGM.defineTypeMetadata(declaredType, isPattern, canBeConstant, | ||
init.finishAndCreateFuture(), section); | ||
(void)var; | ||
} | ||
|
||
void irgen::emitSpecializedGenericClassMetadata(IRGenModule &IGM, CanType type, | ||
ClassDecl &decl) { | ||
assert(decl.isGenericContext()); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// RUN: %target-swift-emit-ir %s -parse-stdlib -enable-experimental-feature Embedded -target arm64e-apple-none | %FileCheck %s | ||
|
||
public class MyClass { | ||
func foo() { } | ||
func bar() { } | ||
} | ||
|
||
public class MySubClass: MyClass { | ||
override func foo() { } | ||
} | ||
|
||
// CHECK: @"$s4main7MyClassCN" = {{.*}}<{ ptr, ptr, ptr, ptr, ptr }> <{ ptr null, ptr @"$s4main7MyClassCfD", ptr @"$s4main7MyClassC3fooyyF", ptr @"$s4main7MyClassC3baryyF", ptr @"$s4main7MyClassCACycfC" }> | ||
// CHECK: @"$s4main10MySubClassCN" = {{.*}}<{ ptr, ptr, ptr, ptr, ptr }> <{ ptr @"$s4main7MyClassCN", ptr @"$s4main10MySubClassCfD", ptr @"$s4main10MySubClassC3fooyyF", ptr @"$s4main7MyClassC3baryyF", ptr @"$s4main10MySubClassCACycfC" }> | ||
|
||
// CHECK: define {{.*}}void @"$s4main4test1xyAA7MyClassC_tF"(ptr %0) | ||
public func test(x: MyClass) { | ||
|
||
x.foo() // goes through the vtable | ||
// CHECK: %1 = load ptr, ptr %0 | ||
// CHECK: %2 = getelementptr inbounds ptr, ptr %1, i64 2 | ||
// CHECK: %3 = load ptr, ptr %2 | ||
// CHECK: call swiftcc void %3(ptr swiftself %0) | ||
|
||
x.bar() // does not go through the vtable | ||
// CHECK: call swiftcc void @"$s4main7MyClassC3baryyF" | ||
|
||
let y = MySubClass() | ||
// CHECK: call swiftcc %swift.metadata_response @"$s4main10MySubClassCMa" | ||
// CHECK: call swiftcc ptr @"$s4main10MySubClassCACycfC" | ||
|
||
y.foo() // does not go through the vtable | ||
// CHECK: call swiftcc void @"$s4main10MySubClassC3fooyyF" | ||
|
||
y.bar() // does not go through the vtable | ||
// CHECK: call swiftcc void @"$s4main7MyClassC3baryyF" | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// RUN: %target-swift-emit-ir %s -parse-stdlib -enable-experimental-feature Embedded -target arm64e-apple-none | %FileCheck %s | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test for calling methods? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added! |
||
|
||
public class MyClass {} | ||
|
||
// CHECK-DAG: @"$s4main7MyClassCN" = {{.*}}<{ ptr, ptr, ptr }> <{ ptr null, ptr @"$s4main7MyClassCfD", ptr @"$s4main7MyClassCACycfC" }> | ||
// CHECK-DAG: define {{.*}}ptr @"$s4main7MyClassCfd" | ||
// CHECK-DAG: define {{.*}}void @"$s4main7MyClassCfD" | ||
// CHECK-DAG: define {{.*}}ptr @"$s4main7MyClassCACycfC" | ||
// CHECK-DAG: define {{.*}}ptr @"$s4main7MyClassCACycfc" | ||
// CHECK-DAG: define {{.*}}%swift.metadata_response @"$s4main7MyClassCMa" | ||
|
||
public func foo() -> MyClass { | ||
return MyClass() | ||
} | ||
// CHECK-DAG: define {{.*}}ptr @"$s4main3fooAA7MyClassCyF" | ||
|
||
public class MySubClass: MyClass {} | ||
|
||
// CHECK-DAG: @"$s4main10MySubClassCN" = {{.*}}<{ ptr, ptr, ptr }> <{ ptr @"$s4main7MyClassCN", ptr @"$s4main10MySubClassCfD", ptr @"$s4main10MySubClassCACycfC" }> | ||
// CHECK-DAG: define {{.*}}ptr @"$s4main10MySubClassCACycfC" | ||
// CHECK-DAG: define {{.*}}ptr @"$s4main10MySubClassCACycfc" | ||
// CHECK-DAG: define {{.*}}ptr @"$s4main10MySubClassCfd" | ||
// CHECK-DAG: define {{.*}}void @"$s4main10MySubClassCfD" | ||
// CHECK-DAG: define {{.*}}%swift.metadata_response @"$s4main10MySubClassCMa" | ||
|
||
public func bar() -> MyClass { | ||
return MySubClass() | ||
} | ||
// CHECK-DAG: define {{.*}}ptr @"$s4main3barAA7MyClassCyF" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want the full vtable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we be more lazy and just emit the methods that are used? Or are we assuming that lto will strip them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm actually assuming that SILOptimizer (namely PruneVTables and DeadFunctionElimination) will take care of that, because we can internalize public declarations in embedded Swift.