diff --git a/lib/IRGen/ClassMetadataVisitor.h b/lib/IRGen/ClassMetadataVisitor.h index b96fccfa153..43ebc794d95 100644 --- a/lib/IRGen/ClassMetadataVisitor.h +++ b/lib/IRGen/ClassMetadataVisitor.h @@ -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; } diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 40f67e18c7f..821ecde7d6f 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -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; diff --git a/stdlib/public/SwiftShims/swift/shims/EmbeddedShims.h b/stdlib/public/SwiftShims/swift/shims/EmbeddedShims.h index 718779670ec..a72cf6b5479 100644 --- a/stdlib/public/SwiftShims/swift/shims/EmbeddedShims.h +++ b/stdlib/public/SwiftShims/swift/shims/EmbeddedShims.h @@ -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; } diff --git a/stdlib/public/core/EmbeddedRuntime.swift b/stdlib/public/core/EmbeddedRuntime.swift index 3471ef6ff5b..18b76151b5b 100644 --- a/stdlib/public/core/EmbeddedRuntime.swift +++ b/stdlib/public/core/EmbeddedRuntime.swift @@ -17,10 +17,15 @@ import SwiftShims public struct ClassMetadata { var superclassMetadata: UnsafeMutablePointer? - // 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, 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(object), metadata: UnsafeMutablePointer(metadata), allocatedSize: allocatedSize, allocatedAlignMask: allocatedAlignMask) +} + +func swift_deallocPartialClassInstance(object: UnsafeMutablePointer, metadata: UnsafeMutablePointer, 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(metadata), object: UnsafeMutablePointer(object))._rawValue diff --git a/test/embedded/classes-generic-no-stdlib.swift b/test/embedded/classes-generic-no-stdlib.swift index 8351c48d676..3d4ee28e7b1 100644 --- a/test/embedded/classes-generic-no-stdlib.swift +++ b/test/embedded/classes-generic-no-stdlib.swift @@ -50,8 +50,8 @@ public func bar(t: T2) -> MyClass { // 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) diff --git a/test/embedded/classes-methods-no-stdlib.swift b/test/embedded/classes-methods-no-stdlib.swift index c6d5cea2b7c..c036ab8d054 100644 --- a/test/embedded/classes-methods-no-stdlib.swift +++ b/test/embedded/classes-methods-no-stdlib.swift @@ -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) diff --git a/test/embedded/classes-no-stdlib.swift b/test/embedded/classes-no-stdlib.swift index ae575c4d198..4edbca34ba5 100644 --- a/test/embedded/classes-no-stdlib.swift +++ b/test/embedded/classes-no-stdlib.swift @@ -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" diff --git a/test/embedded/init-throwing.swift b/test/embedded/init-throwing.swift new file mode 100644 index 00000000000..b20d209750e --- /dev/null +++ b/test/embedded/init-throwing.swift @@ -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 diff --git a/test/embedded/managed-buffer.swift b/test/embedded/managed-buffer.swift index de129ed9f5b..e66591003d4 100644 --- a/test/embedded/managed-buffer.swift +++ b/test/embedded/managed-buffer.swift @@ -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 { }