Skip to content

Commit a60d354

Browse files
ylnJulian Lettner
andauthored
[SUA] Add test for allocation of classes without metadata (#63759)
Add test for allocating classes with pruned metadata and refactor `computeMallocTypeSummary()` to make it easier to understand: * Use early returns for error (metadata absent) conditions * Remove reliance on implicit dependency---having a type descriptor currently implies that there is also class metadata---in case this ever changes Co-authored-by: Julian Lettner <[email protected]>
1 parent 24d8ec5 commit a60d354

File tree

2 files changed

+152
-27
lines changed

2 files changed

+152
-27
lines changed

stdlib/public/runtime/HeapObject.cpp

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -125,41 +125,33 @@ computeMallocTypeSummary(const HeapMetadata *heapMetadata) {
125125
auto *classMetadata = heapMetadata->getClassObject();
126126
auto *typeDesc = heapMetadata->getTypeContextDescriptor();
127127

128-
malloc_type_summary_t summary = {};
128+
// Pruned metadata or unclassified
129+
if (!classMetadata || !typeDesc)
130+
return {.type_kind = MALLOC_TYPE_KIND_SWIFT};
129131

130132
// Objc
131-
if (classMetadata && classMetadata->isPureObjC()) {
132-
summary.type_kind = MALLOC_TYPE_KIND_OBJC;
133-
return summary;
134-
}
133+
if (classMetadata->isPureObjC())
134+
return {.type_kind = MALLOC_TYPE_KIND_OBJC};
135135

136-
// Runtime internal and unclassified
137-
if (!typeDesc) {
138-
summary.type_kind = MALLOC_TYPE_KIND_CXX;
139-
return summary;
140-
}
136+
malloc_type_summary_t summary = {.type_kind = MALLOC_TYPE_KIND_SWIFT};
137+
summary.layout_semantics.reference_count =
138+
(classMetadata->getFlags() & ClassFlags::UsesSwiftRefcounting);
141139

142-
// Swift
143-
summary.type_kind = MALLOC_TYPE_KIND_SWIFT;
140+
auto *fieldDesc = typeDesc->Fields.get();
141+
if (!fieldDesc)
142+
return summary;
144143

145144
bool isGenericData = true;
146-
if (auto *fieldDesc = typeDesc->Fields.get()) {
147-
for (auto &field : *fieldDesc) {
148-
if (field.isIndirectCase()) {
149-
isGenericData = false;
150-
if (field.isVar())
151-
summary.layout_semantics.data_pointer = true;
152-
else
153-
summary.layout_semantics.immutable_pointer = true;
154-
}
145+
for (auto &field : *fieldDesc) {
146+
if (field.isIndirectCase()) {
147+
isGenericData = false;
148+
if (field.isVar())
149+
summary.layout_semantics.data_pointer = true;
150+
else
151+
summary.layout_semantics.immutable_pointer = true;
155152
}
156153
}
157-
158-
if (classMetadata->Flags & ClassFlags::UsesSwiftRefcounting) {
159-
summary.layout_semantics.reference_count = true;
160-
} else {
161-
summary.layout_semantics.generic_data = isGenericData;
162-
}
154+
summary.layout_semantics.generic_data = isGenericData;
163155

164156
return summary;
165157

test/stdlib/MetadataPruning.swift

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// RUN: %target-run-simple-swift
2+
// RUN: %target-run-simple-swift(-Xfrontend -disable-reflection-metadata)
3+
// RUN: %target-run-simple-swift(-Xfrontend -reflection-metadata-for-debugger-only)
4+
// RUN: %target-run-simple-swift(-Xfrontend -disable-reflection-names)
5+
//
6+
// REQUIRES: executable_test
7+
8+
import StdlibUnittest
9+
10+
var tests = TestSuite("MetadataPruning")
11+
12+
struct TestStruct {
13+
var int = 0
14+
var double = 0.0
15+
var bool = false
16+
}
17+
18+
struct GenericStruct<T> {
19+
var int = 0
20+
var first: T
21+
var second: T
22+
}
23+
24+
enum TestEnum {
25+
case one
26+
case two
27+
case three(TestStruct)
28+
}
29+
30+
class BaseClass {
31+
var superInt = 0
32+
init() {}
33+
}
34+
35+
class TestClass: BaseClass {
36+
var int = 0
37+
var double = 0.0
38+
var bool = false
39+
override init() {}
40+
}
41+
42+
class TestSubclass: TestClass {
43+
var strings: [String] = []
44+
override init() {}
45+
}
46+
47+
class GenericClass<T, U>: BaseClass {
48+
var first: T
49+
var second: U
50+
51+
init(_ t: T, _ u: U) {
52+
self.first = t
53+
self.second = u
54+
}
55+
}
56+
57+
class GenericSubclass<V, W>: GenericClass<V, Bool> {
58+
var third: W
59+
60+
init(_ v: V, _ w: W) {
61+
self.third = w
62+
super.init(v, false)
63+
}
64+
}
65+
66+
class OwnershipTestClass: BaseClass {
67+
weak var test1: TestClass?
68+
unowned var test2: TestClass
69+
unowned(unsafe) var test3: TestClass
70+
71+
init(_ t: TestClass) {
72+
self.test1 = t
73+
self.test2 = t
74+
self.test3 = t
75+
}
76+
}
77+
78+
struct ContainsObject {
79+
var obj: TestClass
80+
}
81+
82+
#if _runtime(_ObjC)
83+
import Foundation
84+
85+
class NSObjectSubclass: NSObject {
86+
var point: (Double, Double)
87+
88+
init(x: Double, y: Double) {
89+
self.point = (x, y)
90+
}
91+
}
92+
93+
class EmptyNSObject: NSObject {}
94+
#endif
95+
96+
97+
func printAddress(_ obj: AnyObject) {
98+
print("\(obj) address: \(Unmanaged.passUnretained(obj).toOpaque())")
99+
}
100+
101+
tests.test("Allocate types without metadata") {
102+
let testStruct = TestStruct()
103+
let genericStruct = GenericStruct<Double>(first: 1.3, second: 3.7)
104+
let testEnum = TestEnum.three(testStruct)
105+
let baseClass = BaseClass()
106+
let testClass = TestClass()
107+
let testSubclass = TestSubclass()
108+
let genericClass = GenericClass<Int, String>(5, "bla")
109+
let genericSubclass = GenericSubclass<Double, TestClass>(1.1, testClass)
110+
let ownershipTestClass = OwnershipTestClass(testClass)
111+
let containsObject = ContainsObject(obj: testClass)
112+
113+
print("\(testStruct)")
114+
print("\(genericStruct)")
115+
print("\(testEnum)")
116+
printAddress(baseClass)
117+
printAddress(testClass)
118+
printAddress(testSubclass)
119+
printAddress(genericClass)
120+
printAddress(genericSubclass)
121+
printAddress(ownershipTestClass)
122+
print("\(containsObject)")
123+
124+
#if _runtime(_ObjC)
125+
let nsObjectSubclass = NSObjectSubclass(x: 1.2, y: 3.4)
126+
let emptyNSObject = EmptyNSObject()
127+
128+
printAddress(nsObjectSubclass)
129+
printAddress(emptyNSObject)
130+
#endif
131+
}
132+
133+
runAllTests()

0 commit comments

Comments
 (0)