Skip to content

Commit 9d954f0

Browse files
authored
Merge pull request #5705 from slavapestov/reflection-fixes
2 parents 71364d0 + db79762 commit 9d954f0

31 files changed

+275
-113
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,13 @@ class ReflectionContext
9393
// by looking at the size of the superclass
9494
bool valid;
9595
unsigned size, align;
96-
auto super =
97-
this->readSuperClassFromClassMetadata(MetadataAddress);
98-
if (super) {
99-
std::tie(valid, size, align) =
100-
this->readInstanceSizeAndAlignmentFromClassMetadata(super);
101-
102-
// Perform layout
103-
if (valid)
104-
TI = TC.getClassInstanceTypeInfo(TR, size, align);
105-
}
96+
std::tie(valid, size, align) =
97+
this->readInstanceSizeAndAlignmentFromClassMetadata(MetadataAddress);
98+
99+
// Perform layout
100+
if (valid)
101+
TI = TC.getClassInstanceTypeInfo(TR, size, align);
102+
106103
break;
107104
}
108105
default:

include/swift/Reflection/TypeLowering.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,9 @@ class TypeInfo {
117117
unsigned Size, unsigned Alignment,
118118
unsigned Stride, unsigned NumExtraInhabitants)
119119
: Kind(Kind), Size(Size), Alignment(Alignment), Stride(Stride),
120-
NumExtraInhabitants(NumExtraInhabitants) {}
120+
NumExtraInhabitants(NumExtraInhabitants) {
121+
assert(Alignment > 0);
122+
}
121123

122124
TypeInfoKind getKind() const { return Kind; }
123125

include/swift/Remote/MetadataReader.h

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -564,33 +564,90 @@ class MetadataReader {
564564
/// instance size and alignment.
565565
std::tuple<bool, unsigned, unsigned>
566566
readInstanceSizeAndAlignmentFromClassMetadata(StoredPointer MetadataAddress) {
567-
auto superMeta = readMetadata(MetadataAddress);
568-
if (!superMeta || superMeta->getKind() != MetadataKind::Class)
567+
auto meta = readMetadata(MetadataAddress);
568+
if (!meta || meta->getKind() != MetadataKind::Class)
569569
return std::make_tuple(false, 0, 0);
570570

571-
auto super = cast<TargetClassMetadata<Runtime>>(superMeta);
571+
auto classMeta = cast<TargetClassMetadata<Runtime>>(meta);
572572

573573
// See swift_initClassMetadata_UniversalStrategy()
574574
uint32_t size, align;
575-
if (super->isTypeMetadata()) {
576-
size = super->getInstanceSize();
577-
align = super->getInstanceAlignMask() + 1;
578-
} else {
575+
576+
// If this class is defined in Objective-C, return the value of the
577+
// InstanceStart field from the ROData.
578+
if (!classMeta->isTypeMetadata()) {
579579
// The following algorithm only works on the non-fragile Apple runtime.
580580

581581
// Grab the RO-data pointer. This part is not ABI.
582582
StoredPointer roDataPtr = readObjCRODataPtr(MetadataAddress);
583583
if (!roDataPtr)
584584
return std::make_tuple(false, 0, 0);
585585

586-
auto address = roDataPtr + sizeof(uint32_t) * 2;
586+
// Get the address of the InstanceStart field.
587+
auto address = roDataPtr + sizeof(uint32_t) * 1;
587588

588-
align = 16; // malloc alignment guarantee
589+
align = 16;
589590

590591
if (!Reader->readInteger(RemoteAddress(address), &size))
591592
return std::make_tuple(false, 0, 0);
593+
594+
assert((size & (align - 1)) == 0);
595+
return std::make_tuple(true, size, align);
596+
}
597+
598+
// Otherwise, it is a Swift class. Get the superclass.
599+
auto superAddr = readSuperClassFromClassMetadata(MetadataAddress);
600+
if (superAddr) {
601+
auto superMeta = readMetadata(superAddr);
602+
if (!superMeta || superMeta->getKind() != MetadataKind::Class)
603+
return std::make_tuple(false, 0, 0);
604+
605+
auto superclassMeta = cast<TargetClassMetadata<Runtime>>(superMeta);
606+
607+
// If the superclass is an Objective-C class, we start layout
608+
// from the InstanceSize of the superclass, aligned up to
609+
// 16 bytes.
610+
if (superclassMeta->isTypeMetadata()) {
611+
// Superclass is a Swift class. Get the size of an instance,
612+
// and start layout from that.
613+
size = superclassMeta->getInstanceSize();
614+
align = 1;
615+
616+
return std::make_tuple(true, size, align);
617+
}
618+
619+
std::string superName;
620+
if (!readObjCClassName(superAddr, superName))
621+
return std::make_tuple(false, 0, 0);
622+
623+
if (superName != "SwiftObject") {
624+
// Grab the RO-data pointer. This part is not ABI.
625+
StoredPointer roDataPtr = readObjCRODataPtr(superAddr);
626+
if (!roDataPtr)
627+
return std::make_tuple(false, 0, 0);
628+
629+
// Get the address of the InstanceSize field.
630+
auto address = roDataPtr + sizeof(uint32_t) * 2;
631+
632+
// malloc alignment boundary.
633+
align = 16;
634+
635+
if (!Reader->readInteger(RemoteAddress(address), &size))
636+
return std::make_tuple(false, 0, 0);
637+
638+
// Round up to the alignment boundary.
639+
size = (size + (align - 1)) & ~(align - 1);
640+
641+
return std::make_tuple(true, size, align);
642+
}
643+
644+
// Fall through.
592645
}
593646

647+
// No superclass, just an object header. 12 bytes on 32-bit, 16 on 64-bit
648+
size = Reader->getPointerSize() + sizeof(uint64_t);
649+
align = 1;
650+
594651
return std::make_tuple(true, size, align);
595652
}
596653

stdlib/public/Reflection/TypeLowering.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,8 @@ class ExistentialTypeInfoBuilder {
378378
unsigned RecordTypeInfoBuilder::addField(unsigned fieldSize,
379379
unsigned fieldAlignment,
380380
unsigned numExtraInhabitants) {
381+
assert(fieldAlignment > 0);
382+
381383
// Align the current size appropriately
382384
Size = ((Size + fieldAlignment - 1) & ~(fieldAlignment - 1));
383385

@@ -873,7 +875,7 @@ class EnumTypeInfoBuilder {
873875

874876
public:
875877
EnumTypeInfoBuilder(TypeConverter &TC)
876-
: TC(TC), Size(0), Alignment(0), NumExtraInhabitants(0),
878+
: TC(TC), Size(0), Alignment(1), NumExtraInhabitants(0),
877879
Kind(RecordKind::Invalid), Invalid(false) {}
878880

879881
const TypeInfo *build(const TypeRef *TR, const FieldDescriptor *FD) {
@@ -1264,9 +1266,9 @@ const TypeInfo *TypeConverter::getClassInstanceTypeInfo(const TypeRef *TR,
12641266
// TypeRef to make field types concrete.
12651267
RecordTypeInfoBuilder builder(*this, RecordKind::ClassInstance);
12661268

1267-
// Start layout from the given instance start offset.
1268-
// Extra inhabitants do not matter for a class instance payload.
1269-
builder.addField(start, align, /*numExtraInhabitants=*/0);
1269+
// Start layout from the given instance start offset. This should
1270+
// be the superclass instance size.
1271+
builder.addField(start, 1, /*numExtraInhabitants=*/0);
12701272

12711273
for (auto Field : getBuilder().getFieldTypeRefs(TR, FD))
12721274
builder.addField(Field.Name, Field.TR);

test/Reflection/typeref_lowering.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -913,11 +913,11 @@ V12TypeLowering10EnumStruct
913913
// CHECK-64: (struct TypeLowering.EnumStruct)
914914
// CHECK-64-NEXT: (struct size=81 alignment=8 stride=88 num_extra_inhabitants=0
915915
// CHECK-64-NEXT: (field name=empty offset=0
916-
// CHECK-64-NEXT: (no_payload_enum size=0 alignment=0 stride=1 num_extra_inhabitants=0))
916+
// CHECK-64-NEXT: (no_payload_enum size=0 alignment=1 stride=1 num_extra_inhabitants=0))
917917
// CHECK-64-NEXT: (field name=noPayload offset=0
918-
// CHECK-64-NEXT: (no_payload_enum size=1 alignment=0 stride=1 num_extra_inhabitants=0))
919-
// CHECK-64-NEXT: (field name=sillyNoPayload offset=0
920-
// CHECK-64-NEXT: (no_payload_enum size=1 alignment=0 stride=1 num_extra_inhabitants=0))
918+
// CHECK-64-NEXT: (no_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=0))
919+
// CHECK-64-NEXT: (field name=sillyNoPayload offset=1
920+
// CHECK-64-NEXT: (no_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=0))
921921
// CHECK-64-NEXT: (field name=singleton offset=8
922922
// CHECK-64-NEXT: (reference kind=strong refcounting=native))
923923
// CHECK-64-NEXT: (field name=singlePayload offset=16

validation-test/Reflection/functions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,14 @@ class CapturingClass {
164164
// CHECK-64: (class functions.CapturingClass)
165165

166166
// CHECK-64: Type info:
167-
// CHECK-64: (class_instance size=16 alignment=16 stride=16
167+
// CHECK-64: (class_instance size=16 alignment=1 stride=16
168168

169169
// CHECK-32: Reflecting an object.
170170
// CHECK-32: Type reference:
171171
// CHECK-32: (class functions.CapturingClass)
172172

173173
// CHECK-32: Type info:
174-
// CHECK-32: (class_instance size=12 alignment=16 stride=16
174+
// CHECK-32: (class_instance size=12 alignment=1 stride=12
175175
@_semantics("optimize.sil.never")
176176
func arity0Capture1() -> () -> () {
177177
let closure = {

validation-test/Reflection/inherits_NSObject.swift

Lines changed: 56 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,62 +9,80 @@ import Foundation
99

1010
import SwiftReflectionTest
1111

12-
class InheritsNSObject : NSObject {}
13-
class ContainsInheritsNSObject : NSObject {
14-
var a: InheritsNSObject
15-
var _b: InheritsNSObject
16-
17-
var b: InheritsNSObject {
18-
get { return _b }
19-
set (newVal) { _b = newVal }
20-
}
21-
22-
override init() {
23-
a = InheritsNSObject()
24-
_b = InheritsNSObject()
25-
}
12+
class BaseNSClass : NSObject {
13+
var w: Int = 0
14+
var x: Bool = false
2615
}
2716

28-
let inheritsNSObject = InheritsNSObject()
29-
reflect(object: inheritsNSObject)
17+
class DerivedNSClass : BaseNSClass {
18+
var y: Bool = false
19+
var z: Int = 0
20+
}
21+
22+
let baseClass = BaseNSClass()
23+
reflect(object: baseClass)
3024

3125
// CHECK-64: Reflecting an object.
3226
// CHECK-64: Type reference:
33-
// CHECK-64: (class inherits_NSObject.InheritsNSObject)
27+
// CHECK-64: (class inherits_NSObject.BaseNSClass)
3428

3529
// CHECK-64: Type info:
36-
// CHECK-64: (class_instance size=8 alignment=16 stride=16 num_extra_inhabitants=0)
30+
// CHECK-64-NEXT: (class_instance size=25 alignment=8 stride=32 num_extra_inhabitants=0
31+
// CHECK-64-NEXT: (field name=w offset=16
32+
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0
33+
// CHECK-64-NEXT: (field name=_value offset=0
34+
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0))))
35+
// CHECK-64-NEXT: (field name=x offset=24
36+
// CHECK-64-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254
37+
// CHECK-64-NEXT: (field name=_value offset=0
38+
// CHECK-64-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254)))))
3739

3840
// CHECK-32: Reflecting an object.
3941
// CHECK-32: Type reference:
40-
// CHECK-32: (class inherits_NSObject.InheritsNSObject)
42+
// CHECK-32: (class inherits_NSObject.BaseNSClass)
4143

4244
// CHECK-32: Type info:
43-
// CHECK-32: (class_instance size=4 alignment=16 stride=16 num_extra_inhabitants=0)
44-
45-
let sc = ContainsInheritsNSObject()
46-
reflect(object: sc)
45+
// CHECK-32-NEXT: (class_instance size=21 alignment=4 stride=24 num_extra_inhabitants=0
46+
// CHECK-32-NEXT: (field name=w offset=16
47+
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0
48+
// CHECK-32-NEXT: (field name=_value offset=0
49+
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0))))
50+
// CHECK-32-NEXT: (field name=x offset=20
51+
// CHECK-32-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254
52+
// CHECK-32-NEXT: (field name=_value offset=0
53+
// CHECK-32-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254)))))
54+
55+
let derivedClass = DerivedNSClass()
56+
reflect(object: derivedClass)
4757

4858
// CHECK-64: Reflecting an object.
4959
// CHECK-64: Type reference:
50-
// CHECK-64: (class inherits_NSObject.ContainsInheritsNSObject)
60+
// CHECK-64: (class inherits_NSObject.DerivedNSClass)
5161

52-
// CHECK-64: Type info:
53-
// CHECK-64: (class_instance size=24 alignment=16 stride=32 num_extra_inhabitants=0
54-
// CHECK-64-NEXT: (field name=a offset=8
55-
// CHECK-64-NEXT: (reference kind=strong refcounting=unknown))
56-
// CHECK-64-NEXT: (field name=_b offset=16
57-
// CHECK-64-NEXT: (reference kind=strong refcounting=unknown)))
62+
// CHECK-64: Type info:
63+
// CHECK-64-NEXT: (class_instance size=40 alignment=8 stride=40 num_extra_inhabitants=0
64+
// CHECK-64-NEXT: (field name=y offset=25
65+
// CHECK-64-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254
66+
// CHECK-64-NEXT: (field name=_value offset=0
67+
// CHECK-64-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254))))
68+
// CHECK-64-NEXT: (field name=z offset=32
69+
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0
70+
// CHECK-64-NEXT: (field name=_value offset=0
71+
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))))
5872

5973
// CHECK-32: Reflecting an object.
6074
// CHECK-32: Type reference:
61-
// CHECK-32: (class inherits_NSObject.ContainsInheritsNSObject)
62-
63-
// CHECK-32: Type info:
64-
// CHECK-32: (class_instance size=12 alignment=16 stride=16 num_extra_inhabitants=0
65-
// CHECK-32-NEXT: (field name=a offset=4
66-
// CHECK-32-NEXT: (reference kind=strong refcounting=unknown))
67-
// CHECK-32-NEXT: (field name=_b offset=8
68-
// CHECK-32-NEXT: (reference kind=strong refcounting=unknown)))
75+
// CHECK-32: (class inherits_NSObject.DerivedNSClass)
76+
77+
// CHECK-32: Type info:
78+
// CHECK-32-NEXT: (class_instance size=24 alignment=4 stride=24 num_extra_inhabitants=0
79+
// CHECK-32-NEXT: (field name=y offset=17
80+
// CHECK-32-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254
81+
// CHECK-32-NEXT: (field name=_value offset=0
82+
// CHECK-32-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254))))
83+
// CHECK-32-NEXT: (field name=z offset=20
84+
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0
85+
// CHECK-32-NEXT: (field name=_value offset=0
86+
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))))
6987

7088
doneReflecting()

0 commit comments

Comments
 (0)