Skip to content

Commit 8fa720d

Browse files
authored
Merge pull request #68729 from kubamracek/embedded-class-deinit
[embedded] Add test showcasing class and subclass deinit calls
2 parents 8633cae + d2b8d62 commit 8fa720d

File tree

4 files changed

+187
-4
lines changed

4 files changed

+187
-4
lines changed

test/embedded/Inputs/print.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
@_silgen_name("putchar")
2+
func putchar(_: UInt8)
3+
4+
public func print(_ s: StaticString, terminator: StaticString = "\n") {
5+
var p = s.utf8Start
6+
while p.pointee != 0 {
7+
putchar(p.pointee)
8+
p += 1
9+
}
10+
p = terminator.utf8Start
11+
while p.pointee != 0 {
12+
putchar(p.pointee)
13+
p += 1
14+
}
15+
}

test/embedded/Inputs/tiny-runtime-dummy-refcounting.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,24 @@
55

66
size_t _swiftEmptyArrayStorage[] = { /*isa*/0, /*refcount*/-1, /*count*/0, /*flags*/1 };
77

8+
typedef struct ClassMetadata ClassMetadata;
9+
typedef struct HeapObject HeapObject;
10+
11+
#if !__has_attribute(swiftcall)
12+
#error "The runtime must be built with a compiler that supports swiftcall."
13+
#endif
14+
15+
typedef struct ClassMetadata {
16+
ClassMetadata *superclassMetadata;
17+
void __attribute__((swiftcall)) (* destroy)(__attribute__((swift_context)) HeapObject *object);
18+
} ClassMetadata;
19+
820
typedef struct HeapObject {
9-
void *metadata;
21+
ClassMetadata *metadata;
1022
size_t refcount;
1123
} HeapObject;
1224

13-
void *swift_allocObject(void *metadata, size_t requiredSize, size_t requiredAlignmentMask) {
25+
void *swift_allocObject(ClassMetadata *metadata, size_t requiredSize, size_t requiredAlignmentMask) {
1426
void *r = NULL;
1527
posix_memalign(&r, requiredAlignmentMask + 1, requiredSize);
1628
bzero(r, requiredSize);
@@ -24,7 +36,7 @@ void swift_deallocClassInstance(HeapObject *object, size_t allocatedSize, size_t
2436
free(object);
2537
}
2638

27-
HeapObject *swift_initStackObject(void *metadata, HeapObject *object) {
39+
HeapObject *swift_initStackObject(ClassMetadata *metadata, HeapObject *object) {
2840
object->metadata = metadata;
2941
object->refcount = -1;
3042
return object;
@@ -35,11 +47,12 @@ bool swift_isUniquelyReferenced_nonNull_native(HeapObject *object) {
3547
}
3648

3749
void swift_release(HeapObject *object) {
50+
if (object == NULL) return;
3851
if (object->refcount == -1) return;
3952

4053
object->refcount -= 1;
4154
if (object->refcount == 0) {
42-
free(object);
55+
object->metadata->destroy(object);
4356
}
4457
}
4558

@@ -49,3 +62,13 @@ HeapObject *swift_retain(HeapObject *object) {
4962
object->refcount += 1;
5063
return object;
5164
}
65+
66+
void swift_beginAccess(void *pointer, void *buffer, uintptr_t flags, void *pc) { }
67+
void swift_endAccess(void *buffer) { }
68+
69+
void swift_once(uintptr_t *predicate, void (*fn)(void *), void *context) {
70+
if (!*predicate) {
71+
*predicate = 1;
72+
fn(context);
73+
}
74+
}

test/embedded/classes-arrays.swift

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s %S/Inputs/print.swift -enable-experimental-feature Embedded -c -o %t/main.o
3+
// RUN: %target-clang -x c -c %S/Inputs/tiny-runtime-dummy-refcounting.c -o %t/runtime.o
4+
// RUN: %target-clang %t/main.o %t/runtime.o -o %t/a.out -dead_strip
5+
// RUN: %target-run %t/a.out | %FileCheck %s
6+
7+
// REQUIRES: executable_test
8+
// REQUIRES: optimized_stdlib
9+
// REQUIRES: VENDOR=apple
10+
// REQUIRES: OS=macosx
11+
12+
class MyClass {
13+
init() { print("MyClass.init") }
14+
deinit { print("MyClass.deinit") }
15+
func foo() { print("MyClass.foo") }
16+
}
17+
18+
class MySubClass: MyClass {
19+
override init() { print("MySubClass.init") }
20+
deinit { print("MySubClass.deinit") }
21+
override func foo() { print("MySubClass.foo") }
22+
}
23+
24+
class MySubSubClass: MySubClass {
25+
override init() { print("MySubSubClass.init") }
26+
deinit { print("MySubSubClass.deinit") }
27+
override func foo() { print("MySubSubClass.foo") }
28+
}
29+
30+
@main
31+
struct Main {
32+
static var objects: [MyClass] = []
33+
static func main() {
34+
print("1") // CHECK: 1
35+
objects.append(MyClass())
36+
// CHECK: MyClass.init
37+
print("")
38+
39+
print("2") // CHECK: 2
40+
objects.append(MySubClass())
41+
// CHECK: MySubClass.init
42+
// CHECK: MyClass.init
43+
print("")
44+
45+
print("3") // CHECK: 3
46+
objects.append(MySubSubClass())
47+
// CHECK: MySubSubClass.init
48+
// CHECK: MySubClass.init
49+
// CHECK: MyClass.init
50+
print("")
51+
52+
print("4") // CHECK: 4
53+
for o in objects {
54+
o.foo()
55+
// CHECK: MyClass.foo
56+
// CHECK: MySubClass.foo
57+
// CHECK: MySubSubClass.foo
58+
}
59+
print("")
60+
61+
print("5") // CHECK: 5
62+
objects = []
63+
// CHECK: MyClass.deinit
64+
// CHECK: MySubClass.deinit
65+
// CHECK: MyClass.deinit
66+
// CHECK: MySubSubClass.deinit
67+
// CHECK: MySubClass.deinit
68+
// CHECK: MyClass.deinit
69+
print("")
70+
}
71+
}

test/embedded/classes.swift

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s %S/Inputs/print.swift -enable-experimental-feature Embedded -c -o %t/main.o
3+
// RUN: %target-clang -x c -c %S/Inputs/tiny-runtime-dummy-refcounting.c -o %t/runtime.o
4+
// RUN: %target-clang %t/main.o %t/runtime.o -o %t/a.out -dead_strip
5+
// RUN: %target-run %t/a.out | %FileCheck %s
6+
7+
// REQUIRES: executable_test
8+
// REQUIRES: optimized_stdlib
9+
// REQUIRES: VENDOR=apple
10+
// REQUIRES: OS=macosx
11+
12+
class MyClass {
13+
init() { print("MyClass.init") }
14+
deinit { print("MyClass.deinit") }
15+
func foo() { print("MyClass.foo") }
16+
}
17+
18+
class MySubClass: MyClass {
19+
override init() { print("MySubClass.init") }
20+
deinit { print("MySubClass.deinit") }
21+
override func foo() { print("MySubClass.foo") }
22+
}
23+
24+
class MySubSubClass: MySubClass {
25+
override init() { print("MySubSubClass.init") }
26+
deinit { print("MySubSubClass.deinit") }
27+
override func foo() { print("MySubSubClass.foo") }
28+
}
29+
30+
@main
31+
struct Main {
32+
static var o: (MyClass?, MyClass?, MyClass?) = (nil, nil, nil)
33+
34+
static func main() {
35+
print("1") // CHECK: 1
36+
o.0 = MyClass()
37+
// CHECK: MyClass.init
38+
print("")
39+
40+
print("2") // CHECK: 2
41+
o.1 = MySubClass()
42+
// CHECK: MySubClass.init
43+
// CHECK: MyClass.init
44+
print("")
45+
46+
print("3") // CHECK: 3
47+
o.2 = MySubSubClass()
48+
// CHECK: MySubSubClass.init
49+
// CHECK: MySubClass.init
50+
// CHECK: MyClass.init
51+
print("")
52+
53+
print("4") // CHECK: 4
54+
o.0!.foo()
55+
o.1!.foo()
56+
o.2!.foo()
57+
// CHECK: MyClass.foo
58+
// CHECK: MySubClass.foo
59+
// CHECK: MySubSubClass.foo
60+
print("")
61+
62+
print("5") // CHECK: 5
63+
o.0 = nil
64+
// CHECK: MyClass.deinit
65+
o.1 = nil
66+
// CHECK: MySubClass.deinit
67+
// CHECK: MyClass.deinit
68+
o.2 = nil
69+
// CHECK: MySubSubClass.deinit
70+
// CHECK: MySubClass.deinit
71+
// CHECK: MyClass.deinit
72+
print("")
73+
}
74+
}

0 commit comments

Comments
 (0)