[embedded] Add IVarDestroyers into class metadata, add support for throws in initializers

This commit is contained in:
Kuba Mracek
2024-03-22 14:23:46 -07:00
parent 55c4956fba
commit b8bd832fba
9 changed files with 128 additions and 10 deletions

View File

@@ -76,6 +76,7 @@ public:
asImpl().noteAddressPoint();
asImpl().addEmbeddedSuperclass(classTy);
asImpl().addDestructorFunction();
asImpl().addIVarDestroyer();
addEmbeddedClassMembers(Target);
}
@@ -87,6 +88,7 @@ public:
asImpl().noteAddressPoint();
asImpl().addSuperclass();
asImpl().addDestructorFunction();
asImpl().addIVarDestroyer();
addEmbeddedClassMembers(Target);
return;
}

View File

@@ -4023,6 +4023,23 @@ namespace {
}
void addIVarDestroyer() {
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
llvm::Constant *ptr = nullptr;
for (const SILVTable::Entry &entry : VTable->getEntries()) {
if (entry.getMethod().kind == SILDeclRef::Kind::IVarDestroyer) {
ptr = IGM.getAddrOfSILFunction(entry.getImplementation(), NotForDefinition);
break;
}
}
if (ptr) {
B.addSignedPointer(ptr, IGM.getOptions().PointerAuth.HeapDestructors,
PointerAuthEntity::Special::HeapDestructor);
} else {
B.addNullPointer(IGM.FunctionPtrTy);
}
return;
}
if (asImpl().getFieldLayout().hasObjCImplementation())
return;

View File

@@ -62,6 +62,20 @@ _swift_embedded_invoke_heap_object_destroy(void *object) {
#endif
}
static inline void
_swift_embedded_invoke_heap_object_ivardestroyer(void *object, void *metadata) {
void **ivardestroyer_location = &((void **)metadata)[2];
#if __has_feature(ptrauth_calls)
(*(HeapObjectDestroyer __ptrauth(0, 1, 0xbbbf) *)ivardestroyer_location)(object);
#else
(*(HeapObjectDestroyer *)ivardestroyer_location)(object);
#endif
}
static inline void *_swift_embedded_get_heap_object_metadata_pointer(void *object) {
return ((EmbeddedHeapObject *)object)->metadata;
}
static inline void _swift_embedded_set_heap_object_metadata_pointer(void *object, void *metadata) {
((EmbeddedHeapObject *)object)->metadata = metadata;
}

View File

@@ -17,10 +17,15 @@ import SwiftShims
public struct ClassMetadata {
var superclassMetadata: UnsafeMutablePointer<ClassMetadata>?
// There is no way to express the actual calling convention on the heap desroy
// There is no way to express the actual calling convention on this
// function (swiftcc with 'self') currently, so let's use UnsafeRawPointer
// and a helper function in C (_swift_embedded_invoke_heap_object_destroy).
var destroy: UnsafeRawPointer
// There is no way to express the actual calling convention on this
// function (swiftcc with 'self') currently, so let's use UnsafeRawPointer
// and a helper function in C (_swift_embedded_invoke_heap_object_ivardestroyer).
var ivarDestroyer: UnsafeRawPointer
}
public struct HeapObject {
@@ -116,6 +121,20 @@ func swift_deallocClassInstance(object: UnsafeMutablePointer<HeapObject>, alloca
free(object._rawValue)
}
@_cdecl("swift_deallocPartialClassInstance")
public func swift_deallocPartialClassInstance(object: Builtin.RawPointer, metadata: Builtin.RawPointer, allocatedSize: Int, allocatedAlignMask: Int) {
swift_deallocPartialClassInstance(object: UnsafeMutablePointer<HeapObject>(object), metadata: UnsafeMutablePointer<ClassMetadata>(metadata), allocatedSize: allocatedSize, allocatedAlignMask: allocatedAlignMask)
}
func swift_deallocPartialClassInstance(object: UnsafeMutablePointer<HeapObject>, metadata: UnsafeMutablePointer<ClassMetadata>, allocatedSize: Int, allocatedAlignMask: Int) {
var classMetadata = _swift_embedded_get_heap_object_metadata_pointer(object).assumingMemoryBound(to: ClassMetadata.self)
while classMetadata != metadata {
_swift_embedded_invoke_heap_object_ivardestroyer(object, classMetadata)
guard let superclassMetadata = classMetadata.pointee.superclassMetadata else { break }
classMetadata = superclassMetadata
}
}
@_cdecl("swift_initStaticObject")
public func swift_initStaticObject(metadata: Builtin.RawPointer, object: Builtin.RawPointer) -> Builtin.RawPointer {
return swift_initStaticObject(metadata: UnsafeMutablePointer<ClassMetadata>(metadata), object: UnsafeMutablePointer<HeapObject>(object))._rawValue

View File

@@ -50,8 +50,8 @@ public func bar(t: T2) -> MyClass<T2> {
// CHECK-SIL: }
// CHECK-IR: @"$s4main7MyClassCyAA2T2VGN" = {{.*}}<{ ptr, ptr, ptr, ptr, ptr, ptr }> <{ ptr null, ptr @"$s4main7MyClassCfDAA2T2V_Tg5", ptr @"$s4main7MyClassC1txvgAA2T2V_Tg5", ptr @"$s4main7MyClassC1txvsAA2T2V_Tg5", ptr @"$s4main7MyClassC1txvMAA2T2V_Tg5", ptr @"$s4main7MyClassC1tACyxGx_tcfCAA2T2V_Tg5" }>
// CHECK-IR: @"$s4main7MyClassCyAA2T1VGN" = {{.*}}<{ ptr, ptr, ptr, ptr, ptr, ptr }> <{ ptr null, ptr @"$s4main7MyClassCfDAA2T1V_Tg5", ptr @"$s4main7MyClassC1txvgAA2T1V_Tg5", ptr @"$s4main7MyClassC1txvsAA2T1V_Tg5", ptr @"$s4main7MyClassC1txvMAA2T1V_Tg5", ptr @"$s4main7MyClassC1tACyxGx_tcfCAA2T1V_Tg5" }>
// CHECK-IR: @"$s4main7MyClassCyAA2T2VGN" = {{.*}}<{ ptr, ptr, ptr, ptr, ptr, ptr, ptr }> <{ ptr null, ptr @"$s4main7MyClassCfDAA2T2V_Tg5", ptr null, ptr @"$s4main7MyClassC1txvgAA2T2V_Tg5", ptr @"$s4main7MyClassC1txvsAA2T2V_Tg5", ptr @"$s4main7MyClassC1txvMAA2T2V_Tg5", ptr @"$s4main7MyClassC1tACyxGx_tcfCAA2T2V_Tg5" }>
// CHECK-IR: @"$s4main7MyClassCyAA2T1VGN" = {{.*}}<{ ptr, ptr, ptr, ptr, ptr, ptr, ptr }> <{ ptr null, ptr @"$s4main7MyClassCfDAA2T1V_Tg5", ptr null, ptr @"$s4main7MyClassC1txvgAA2T1V_Tg5", ptr @"$s4main7MyClassC1txvsAA2T1V_Tg5", ptr @"$s4main7MyClassC1txvMAA2T1V_Tg5", ptr @"$s4main7MyClassC1tACyxGx_tcfCAA2T1V_Tg5" }>
// CHECK-IR-DAG: define {{.*}}void @"$s4main7MyClassC1txvgAA2T1V_Tg5"(ptr swiftself %0)
// CHECK-IR-DAG: define {{.*}}i1 @"$s4main7MyClassC1txvgAA2T2V_Tg5"(ptr swiftself %0)

View File

@@ -11,15 +11,15 @@ public class MySubClass: MyClass {
override func foo() { }
}
// CHECK: @"$s4main7MyClassCN" = {{.*}}<{ ptr, ptr, ptr, ptr, ptr }> <{ ptr null, ptr @"$s4main7MyClassCfD", ptr @"$s4main7MyClassC3fooyyF", ptr @"$s4main7MyClassC3baryyF", ptr @swift_deletedMethodError }>
// CHECK: @"$s4main10MySubClassCN" = {{.*}}<{ ptr, ptr, ptr, ptr, ptr }> <{ ptr @"$s4main7MyClassCN", ptr @"$s4main10MySubClassCfD", ptr @"$s4main10MySubClassC3fooyyF", ptr @"$s4main7MyClassC3baryyF", ptr @"$s4main10MySubClassCACycfC" }>
// CHECK: @"$s4main7MyClassCN" = {{.*}}<{ ptr, ptr, ptr, ptr, ptr, ptr }> <{ ptr null, ptr @"$s4main7MyClassCfD", ptr null, ptr @"$s4main7MyClassC3fooyyF", ptr @"$s4main7MyClassC3baryyF", ptr @swift_deletedMethodError }>
// CHECK: @"$s4main10MySubClassCN" = {{.*}}<{ ptr, ptr, ptr, ptr, ptr, ptr }> <{ ptr @"$s4main7MyClassCN", ptr @"$s4main10MySubClassCfD", ptr null, 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: %2 = getelementptr inbounds ptr, ptr %1, i64 3
// CHECK: %3 = load ptr, ptr %2
// CHECK: call swiftcc void %3(ptr swiftself %0)

View File

@@ -4,7 +4,7 @@
public class MyClass {}
// CHECK-DAG: @"$s4main7MyClassCN" = {{.*}}<{ ptr, ptr, ptr }> <{ ptr null, ptr @"$s4main7MyClassCfD", ptr @"$s4main7MyClassCACycfC" }>
// CHECK-DAG: @"$s4main7MyClassCN" = {{.*}}<{ ptr, ptr, ptr, ptr }> <{ ptr null, ptr @"$s4main7MyClassCfD", ptr null, ptr @"$s4main7MyClassCACycfC" }>
// CHECK-DAG: define {{.*}}ptr @"$s4main7MyClassCfd"
// CHECK-DAG: define {{.*}}void @"$s4main7MyClassCfD"
// CHECK-DAG: define {{.*}}ptr @"$s4main7MyClassCACycfC"
@@ -17,7 +17,7 @@ public func foo() -> MyClass {
public class MySubClass: MyClass {}
// CHECK-DAG: @"$s4main10MySubClassCN" = {{.*}}<{ ptr, ptr, ptr }> <{ ptr @"$s4main7MyClassCN", ptr @"$s4main10MySubClassCfD", ptr @"$s4main10MySubClassCACycfC" }>
// CHECK-DAG: @"$s4main10MySubClassCN" = {{.*}}<{ ptr, ptr, ptr, ptr }> <{ ptr @"$s4main7MyClassCN", ptr @"$s4main10MySubClassCfD", ptr null, ptr @"$s4main10MySubClassCACycfC" }>
// CHECK-DAG: define {{.*}}ptr @"$s4main10MySubClassCACycfC"
// CHECK-DAG: define {{.*}}ptr @"$s4main10MySubClassCACycfc"
// CHECK-DAG: define {{.*}}ptr @"$s4main10MySubClassCfd"

View File

@@ -0,0 +1,66 @@
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -runtime-compatibility-version none -wmo -Xfrontend -disable-objc-interop) | %FileCheck %s
// REQUIRES: swift_in_compiler
// REQUIRES: executable_test
// REQUIRES: optimized_stdlib
// REQUIRES: OS=macosx || OS=linux-gnu
public struct FooError: Error {}
public class PrintingClass {
init() { print("PrintingClass.init") }
deinit { print("PrintingClass.deinit") }
}
public class Foo {
var a: PrintingClass
var b: PrintingClass
init(shouldThrow: Bool) throws(FooError) {
a = PrintingClass()
if shouldThrow { throw FooError() }
b = PrintingClass()
}
}
_ = try? Foo(shouldThrow: true)
print("OK 1")
// CHECK: PrintingClass.init
// CHECK: PrintingClass.deinit
// CHECK: OK 1
_ = try? Foo(shouldThrow: false)
print("OK 2")
// CHECK: PrintingClass.init
// CHECK: PrintingClass.init
// CHECK: PrintingClass.deinit
// CHECK: PrintingClass.deinit
// CHECK: OK 2
public class Base {
var baseMember: PrintingClass
init(shouldThrow: Bool) throws(FooError) {
if shouldThrow { throw FooError() }
baseMember = PrintingClass()
}
}
class SubClass: Base {
var subClassMember: PrintingClass = PrintingClass()
override init(shouldThrow: Bool) throws(FooError) {
try super.init(shouldThrow: shouldThrow)
}
}
_ = try? SubClass(shouldThrow: true)
print("OK 3")
// CHECK: PrintingClass.init
// CHECK: PrintingClass.deinit
// CHECK: OK 3
_ = try? SubClass(shouldThrow: false)
print("OK 4")
// CHECK: PrintingClass.init
// CHECK: PrintingClass.init
// CHECK: PrintingClass.deinit
// CHECK: PrintingClass.deinit
// CHECK: OK 4

View File

@@ -3,8 +3,8 @@
// REQUIRES: swift_in_compiler
// REQUIRES: OS=macosx || OS=linux-gnu
// CHECK: @"$s4main8MyBufferCN" = {{.*global.*}} <{ ptr @"$ss13ManagedBufferCySis5UInt8VGN", ptr @"$s4main8MyBufferCfD{{[^"]*}}", ptr @"$s4main8MyBufferC12_doNotCallMeACyt_tcfC{{[^"]*}}" }>
// CHECK: @"$ss13ManagedBufferCySis5UInt8VGN" = {{.*global.*}} <{ ptr null, ptr @"$ss13ManagedBufferCfDSi_s5UInt8VTg5{{[^"]*}}", ptr @"$ss13ManagedBufferC12_doNotCallMeAByxq_Gyt_tcfCSi_s5UInt8VTg5{{[^"]*}}" }>
// CHECK: @"$s4main8MyBufferCN" = {{.*global.*}} <{ ptr @"$ss13ManagedBufferCySis5UInt8VGN", ptr @"$s4main8MyBufferCfD{{[^"]*}}", ptr null, ptr @"$s4main8MyBufferC12_doNotCallMeACyt_tcfC{{[^"]*}}" }>
// CHECK: @"$ss13ManagedBufferCySis5UInt8VGN" = {{.*global.*}} <{ ptr null, ptr @"$ss13ManagedBufferCfDSi_s5UInt8VTg5{{[^"]*}}", ptr null, ptr @"$ss13ManagedBufferC12_doNotCallMeAByxq_Gyt_tcfCSi_s5UInt8VTg5{{[^"]*}}" }>
final public class MyBuffer: ManagedBuffer<Int, UInt8> {
}