mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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 <julian.lettner@apple.com>
This commit is contained in:
@@ -125,41 +125,33 @@ computeMallocTypeSummary(const HeapMetadata *heapMetadata) {
|
|||||||
auto *classMetadata = heapMetadata->getClassObject();
|
auto *classMetadata = heapMetadata->getClassObject();
|
||||||
auto *typeDesc = heapMetadata->getTypeContextDescriptor();
|
auto *typeDesc = heapMetadata->getTypeContextDescriptor();
|
||||||
|
|
||||||
malloc_type_summary_t summary = {};
|
// Pruned metadata or unclassified
|
||||||
|
if (!classMetadata || !typeDesc)
|
||||||
|
return {.type_kind = MALLOC_TYPE_KIND_SWIFT};
|
||||||
|
|
||||||
// Objc
|
// Objc
|
||||||
if (classMetadata && classMetadata->isPureObjC()) {
|
if (classMetadata->isPureObjC())
|
||||||
summary.type_kind = MALLOC_TYPE_KIND_OBJC;
|
return {.type_kind = MALLOC_TYPE_KIND_OBJC};
|
||||||
return summary;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Runtime internal and unclassified
|
malloc_type_summary_t summary = {.type_kind = MALLOC_TYPE_KIND_SWIFT};
|
||||||
if (!typeDesc) {
|
summary.layout_semantics.reference_count =
|
||||||
summary.type_kind = MALLOC_TYPE_KIND_CXX;
|
(classMetadata->getFlags() & ClassFlags::UsesSwiftRefcounting);
|
||||||
return summary;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swift
|
auto *fieldDesc = typeDesc->Fields.get();
|
||||||
summary.type_kind = MALLOC_TYPE_KIND_SWIFT;
|
if (!fieldDesc)
|
||||||
|
return summary;
|
||||||
|
|
||||||
bool isGenericData = true;
|
bool isGenericData = true;
|
||||||
if (auto *fieldDesc = typeDesc->Fields.get()) {
|
for (auto &field : *fieldDesc) {
|
||||||
for (auto &field : *fieldDesc) {
|
if (field.isIndirectCase()) {
|
||||||
if (field.isIndirectCase()) {
|
isGenericData = false;
|
||||||
isGenericData = false;
|
if (field.isVar())
|
||||||
if (field.isVar())
|
summary.layout_semantics.data_pointer = true;
|
||||||
summary.layout_semantics.data_pointer = true;
|
else
|
||||||
else
|
summary.layout_semantics.immutable_pointer = true;
|
||||||
summary.layout_semantics.immutable_pointer = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
summary.layout_semantics.generic_data = isGenericData;
|
||||||
if (classMetadata->Flags & ClassFlags::UsesSwiftRefcounting) {
|
|
||||||
summary.layout_semantics.reference_count = true;
|
|
||||||
} else {
|
|
||||||
summary.layout_semantics.generic_data = isGenericData;
|
|
||||||
}
|
|
||||||
|
|
||||||
return summary;
|
return summary;
|
||||||
|
|
||||||
|
|||||||
133
test/stdlib/MetadataPruning.swift
Normal file
133
test/stdlib/MetadataPruning.swift
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
// RUN: %target-run-simple-swift
|
||||||
|
// RUN: %target-run-simple-swift(-Xfrontend -disable-reflection-metadata)
|
||||||
|
// RUN: %target-run-simple-swift(-Xfrontend -reflection-metadata-for-debugger-only)
|
||||||
|
// RUN: %target-run-simple-swift(-Xfrontend -disable-reflection-names)
|
||||||
|
//
|
||||||
|
// REQUIRES: executable_test
|
||||||
|
|
||||||
|
import StdlibUnittest
|
||||||
|
|
||||||
|
var tests = TestSuite("MetadataPruning")
|
||||||
|
|
||||||
|
struct TestStruct {
|
||||||
|
var int = 0
|
||||||
|
var double = 0.0
|
||||||
|
var bool = false
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GenericStruct<T> {
|
||||||
|
var int = 0
|
||||||
|
var first: T
|
||||||
|
var second: T
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TestEnum {
|
||||||
|
case one
|
||||||
|
case two
|
||||||
|
case three(TestStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
class BaseClass {
|
||||||
|
var superInt = 0
|
||||||
|
init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestClass: BaseClass {
|
||||||
|
var int = 0
|
||||||
|
var double = 0.0
|
||||||
|
var bool = false
|
||||||
|
override init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestSubclass: TestClass {
|
||||||
|
var strings: [String] = []
|
||||||
|
override init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GenericClass<T, U>: BaseClass {
|
||||||
|
var first: T
|
||||||
|
var second: U
|
||||||
|
|
||||||
|
init(_ t: T, _ u: U) {
|
||||||
|
self.first = t
|
||||||
|
self.second = u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GenericSubclass<V, W>: GenericClass<V, Bool> {
|
||||||
|
var third: W
|
||||||
|
|
||||||
|
init(_ v: V, _ w: W) {
|
||||||
|
self.third = w
|
||||||
|
super.init(v, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OwnershipTestClass: BaseClass {
|
||||||
|
weak var test1: TestClass?
|
||||||
|
unowned var test2: TestClass
|
||||||
|
unowned(unsafe) var test3: TestClass
|
||||||
|
|
||||||
|
init(_ t: TestClass) {
|
||||||
|
self.test1 = t
|
||||||
|
self.test2 = t
|
||||||
|
self.test3 = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ContainsObject {
|
||||||
|
var obj: TestClass
|
||||||
|
}
|
||||||
|
|
||||||
|
#if _runtime(_ObjC)
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class NSObjectSubclass: NSObject {
|
||||||
|
var point: (Double, Double)
|
||||||
|
|
||||||
|
init(x: Double, y: Double) {
|
||||||
|
self.point = (x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EmptyNSObject: NSObject {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
func printAddress(_ obj: AnyObject) {
|
||||||
|
print("\(obj) address: \(Unmanaged.passUnretained(obj).toOpaque())")
|
||||||
|
}
|
||||||
|
|
||||||
|
tests.test("Allocate types without metadata") {
|
||||||
|
let testStruct = TestStruct()
|
||||||
|
let genericStruct = GenericStruct<Double>(first: 1.3, second: 3.7)
|
||||||
|
let testEnum = TestEnum.three(testStruct)
|
||||||
|
let baseClass = BaseClass()
|
||||||
|
let testClass = TestClass()
|
||||||
|
let testSubclass = TestSubclass()
|
||||||
|
let genericClass = GenericClass<Int, String>(5, "bla")
|
||||||
|
let genericSubclass = GenericSubclass<Double, TestClass>(1.1, testClass)
|
||||||
|
let ownershipTestClass = OwnershipTestClass(testClass)
|
||||||
|
let containsObject = ContainsObject(obj: testClass)
|
||||||
|
|
||||||
|
print("\(testStruct)")
|
||||||
|
print("\(genericStruct)")
|
||||||
|
print("\(testEnum)")
|
||||||
|
printAddress(baseClass)
|
||||||
|
printAddress(testClass)
|
||||||
|
printAddress(testSubclass)
|
||||||
|
printAddress(genericClass)
|
||||||
|
printAddress(genericSubclass)
|
||||||
|
printAddress(ownershipTestClass)
|
||||||
|
print("\(containsObject)")
|
||||||
|
|
||||||
|
#if _runtime(_ObjC)
|
||||||
|
let nsObjectSubclass = NSObjectSubclass(x: 1.2, y: 3.4)
|
||||||
|
let emptyNSObject = EmptyNSObject()
|
||||||
|
|
||||||
|
printAddress(nsObjectSubclass)
|
||||||
|
printAddress(emptyNSObject)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
runAllTests()
|
||||||
Reference in New Issue
Block a user