Skip to content

Commit 3663c36

Browse files
committed
IRGen: Begin NSObject subclass layout with an NSObject 'isa' header only.
We would lay out all classes starting with a Swift-style two-word header, even classes that inherit NSObject and therefore don't have Swift refcounting. The ObjC runtime would slide our ivars down for us at realization time, but it's nice to avoid unnecessarily dirtying memory in the not-uncommon case of direct NSObject subclasses.
1 parent 1ca7f68 commit 3663c36

7 files changed

+61
-34
lines changed

lib/IRGen/GenClass.cpp

+23-6
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,30 @@ namespace {
181181
// If not, we can have to access stored properties through the field
182182
// offset vector in the instantiated type metadata.
183183
bool ClassHasConcreteLayout = true;
184-
184+
185185
public:
186-
ClassLayoutBuilder(IRGenModule &IGM, SILType classType)
186+
ClassLayoutBuilder(IRGenModule &IGM, SILType classType,
187+
ReferenceCounting refcounting)
187188
: StructLayoutBuilder(IGM)
188189
{
189190
// Start by adding a heap header.
190-
addHeapHeader();
191-
191+
switch (refcounting) {
192+
case swift::irgen::ReferenceCounting::Native:
193+
// For native classes, place a full object header.
194+
addHeapHeader();
195+
break;
196+
case swift::irgen::ReferenceCounting::ObjC:
197+
// For ObjC-inheriting classes, we don't reliably know the size of the
198+
// base class, but NSObject only has an `isa` pointer at most.
199+
addNSObjectHeader();
200+
break;
201+
case swift::irgen::ReferenceCounting::Block:
202+
case swift::irgen::ReferenceCounting::Unknown:
203+
case swift::irgen::ReferenceCounting::Bridge:
204+
case swift::irgen::ReferenceCounting::Error:
205+
llvm_unreachable("not a class refcounting kind");
206+
}
207+
192208
// Next, add the fields for the given class.
193209
auto theClass = classType.getClassOrBoundGenericClass();
194210
assert(theClass);
@@ -382,7 +398,7 @@ void ClassTypeInfo::generateLayout(IRGenModule &IGM, SILType classType) const {
382398
"already generated layout");
383399

384400
// Add the heap header.
385-
ClassLayoutBuilder builder(IGM, classType);
401+
ClassLayoutBuilder builder(IGM, classType, Refcount);
386402

387403
// generateLayout can call itself recursively in order to compute a layout
388404
// for the abstract type. If classType shares an exemplar types with the
@@ -409,7 +425,8 @@ void ClassTypeInfo::generateLayout(IRGenModule &IGM, SILType classType) const {
409425
const StructLayout &
410426
ClassTypeInfo::getLayout(IRGenModule &IGM, SILType classType) const {
411427
// Return the cached layout if available.
412-
if (Layout) return *Layout;
428+
if (Layout)
429+
return *Layout;
413430

414431
generateLayout(IGM, classType);
415432
return *Layout;

lib/IRGen/StructLayout.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,13 @@ void StructLayoutBuilder::addHeapHeader() {
189189
StructFields.push_back(IGM.RefCountedStructTy);
190190
}
191191

192+
void StructLayoutBuilder::addNSObjectHeader() {
193+
assert(StructFields.empty() && "adding heap header at a non-zero offset");
194+
CurSize = IGM.getPointerSize();
195+
CurAlignment = IGM.getPointerAlignment();
196+
StructFields.push_back(IGM.ObjCClassPtrTy);
197+
}
198+
192199
bool StructLayoutBuilder::addFields(llvm::MutableArrayRef<ElementLayout> elts,
193200
LayoutStrategy strategy) {
194201
// Track whether we've added any storage to our layout.

lib/IRGen/StructLayout.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,12 @@ class StructLayoutBuilder {
233233
StructLayoutBuilder(IRGenModule &IGM) : IGM(IGM) {}
234234

235235
/// Add a swift heap header to the layout. This must be the first
236-
/// call to the layout.
236+
/// thing added to the layout.
237237
void addHeapHeader();
238-
238+
/// Add the NSObject object header to the layout. This must be the first
239+
/// thing added to the layout.
240+
void addNSObjectHeader();
241+
239242
/// Add a number of fields to the layout. The field layouts need
240243
/// only have the TypeInfo set; the rest will be filled out.
241244
///

test/IRGen/objc_attr_NSManaged.sil

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ sil_vtable X {}
2727
// The getter/setter should not show up in the Swift metadata.
2828
/* FIXME: sil_vtable parser picks the wrong 'init' overload. Both vtable entries
2929
ought to be nonnull here. rdar://problem/19572342 */
30-
// CHECK: @_T019objc_attr_NSManaged10SwiftGizmoCMf = internal global <{ {{.*}} }> <{ void (%T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoCfD, i8** @_T0BOWV, i64 ptrtoint (%objc_class* @"OBJC_METACLASS_$__TtC19objc_attr_NSManaged10SwiftGizmo" to i64), %objc_class* @"OBJC_CLASS_$_Gizmo", %swift.opaque* @_objc_empty_cache, %swift.opaque* null, i64 add (i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, { i32, i32, [2 x { i8*, i8*, i8* }] }*, i8*, i8*, i8*, { i32, i32, [1 x { i8*, i8* }] }* }* @_DATA__TtC19objc_attr_NSManaged10SwiftGizmo to i64), i64 1), i32 1, i32 0, i32 16, i16 7, i16 0, i32 112, i32 16, {{.*}}* @_T019objc_attr_NSManaged10SwiftGizmoCMn {{.*}}, i8* null, %T19objc_attr_NSManaged10SwiftGizmoC* (i64, %T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoCACSi7bellsOn_tcfc, i8* bitcast (void ()* @swift_deletedMethodError to i8*) }>
30+
// CHECK: @_T019objc_attr_NSManaged10SwiftGizmoCMf = internal global <{ {{.*}} }> <{ void (%T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoCfD, i8** @_T0BOWV, i64 ptrtoint (%objc_class* @"OBJC_METACLASS_$__TtC19objc_attr_NSManaged10SwiftGizmo" to i64), %objc_class* @"OBJC_CLASS_$_Gizmo", %swift.opaque* @_objc_empty_cache, %swift.opaque* null, i64 add (i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, { i32, i32, [2 x { i8*, i8*, i8* }] }*, i8*, i8*, i8*, { i32, i32, [1 x { i8*, i8* }] }* }* @_DATA__TtC19objc_attr_NSManaged10SwiftGizmo to i64), i64 1), i32 1, i32 0, i32 8, i16 7, i16 0, i32 112, i32 16, {{.*}}* @_T019objc_attr_NSManaged10SwiftGizmoCMn {{.*}}, i8* null, %T19objc_attr_NSManaged10SwiftGizmoC* (i64, %T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoCACSi7bellsOn_tcfc, i8* bitcast (void ()* @swift_deletedMethodError to i8*) }>
3131

3232
@objc class SwiftGizmo : Gizmo {
3333
@objc @NSManaged var x: X

test/IRGen/objc_subclass.swift

+7-7
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
// REQUIRES: objc_interop
66

77
// CHECK: [[SGIZMO:T13objc_subclass10SwiftGizmoC]] = type
8-
// CHECK: [[TYPE:%swift.type]] = type
9-
// CHECK: [[INT:%TSi]] = type <{ [[LLVM_PTRSIZE_INT:i(32|64)]] }>
108
// CHECK: [[OBJC_CLASS:%objc_class]] = type
119
// CHECK: [[OPAQUE:%swift.opaque]] = type
10+
// CHECK: [[INT:%TSi]] = type <{ [[LLVM_PTRSIZE_INT:i(32|64)]] }>
11+
// CHECK: [[TYPE:%swift.type]] = type
1212
// CHECK: [[GIZMO:%TSo5GizmoC]] = type opaque
1313
// CHECK: [[OBJC:%objc_object]] = type opaque
1414

15-
// CHECK-32: @_T013objc_subclass10SwiftGizmoC1xSivWvd = hidden global i32 12, align [[WORD_SIZE_IN_BYTES:4]]
16-
// CHECK-64: @_T013objc_subclass10SwiftGizmoC1xSivWvd = hidden global i64 16, align [[WORD_SIZE_IN_BYTES:8]]
15+
// CHECK-32: @_T013objc_subclass10SwiftGizmoC1xSivWvd = hidden global i32 4, align [[WORD_SIZE_IN_BYTES:4]]
16+
// CHECK-64: @_T013objc_subclass10SwiftGizmoC1xSivWvd = hidden global i64 8, align [[WORD_SIZE_IN_BYTES:8]]
1717
// CHECK: @"OBJC_METACLASS_$__TtC13objc_subclass10SwiftGizmo" = hidden global [[OBJC_CLASS]] { [[OBJC_CLASS]]* @"OBJC_METACLASS_$_NSObject", [[OBJC_CLASS]]* @"OBJC_METACLASS_$_Gizmo", [[OPAQUE]]* @_objc_empty_cache, [[OPAQUE]]* null, [[LLVM_PTRSIZE_INT]] ptrtoint ({{.*}} @_METACLASS_DATA__TtC13objc_subclass10SwiftGizmo to [[LLVM_PTRSIZE_INT]]) }
1818

1919
// CHECK: [[STRING_SWIFTGIZMO:@.*]] = private unnamed_addr constant [32 x i8] c"_TtC13objc_subclass10SwiftGizmo\00"
@@ -183,8 +183,8 @@
183183

184184
// CHECK-32: @_DATA__TtC13objc_subclass10SwiftGizmo = private constant { {{.*}}* } {
185185
// CHECK-32: i32 132,
186-
// CHECK-32: i32 12,
187-
// CHECK-32: i32 16,
186+
// CHECK-32: i32 4,
187+
// CHECK-32: i32 8,
188188
// CHECK-32: i8* null,
189189
// CHECK-32: i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* [[STRING_SWIFTGIZMO]], i32 0, i32 0),
190190
// CHECK-32: @_INSTANCE_METHODS__TtC13objc_subclass10SwiftGizmo,
@@ -196,8 +196,8 @@
196196

197197
// CHECK-64: @_DATA__TtC13objc_subclass10SwiftGizmo = private constant { {{.*}}* } {
198198
// CHECK-64: i32 132,
199+
// CHECK-64: i32 8,
199200
// CHECK-64: i32 16,
200-
// CHECK-64: i32 24,
201201
// CHECK-64: i32 0,
202202
// CHECK-64: i8* null,
203203
// CHECK-64: i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* [[STRING_SWIFTGIZMO]], i64 0, i64 0),

validation-test/Reflection/inherits_NSObject.swift

+16-16
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ reflect(object: baseClass)
2323
// CHECK-64: (class inherits_NSObject.BaseNSClass)
2424

2525
// CHECK-64: Type info:
26-
// CHECK-64-NEXT: (class_instance size=25 alignment=8 stride=32 num_extra_inhabitants=0
27-
// CHECK-64-NEXT: (field name=w offset=16
26+
// CHECK-64-NEXT: (class_instance size=17 alignment=8 stride=24 num_extra_inhabitants=0
27+
// CHECK-64-NEXT: (field name=w offset=8
2828
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0
2929
// CHECK-64-NEXT: (field name=_value offset=0
3030
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0))))
31-
// CHECK-64-NEXT: (field name=x offset=24
31+
// CHECK-64-NEXT: (field name=x offset=16
3232
// CHECK-64-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254
3333
// CHECK-64-NEXT: (field name=_value offset=0
3434
// CHECK-64-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254)))))
@@ -38,12 +38,12 @@ reflect(object: baseClass)
3838
// CHECK-32: (class inherits_NSObject.BaseNSClass)
3939

4040
// CHECK-32: Type info:
41-
// CHECK-32-NEXT: (class_instance size=17 alignment=4 stride=20 num_extra_inhabitants=0
42-
// CHECK-32-NEXT: (field name=w offset=12
41+
// CHECK-32-NEXT: (class_instance size=9 alignment=4 stride=12 num_extra_inhabitants=0
42+
// CHECK-32-NEXT: (field name=w offset=4
4343
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0
4444
// CHECK-32-NEXT: (field name=_value offset=0
4545
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0))))
46-
// CHECK-32-NEXT: (field name=x offset=16
46+
// CHECK-32-NEXT: (field name=x offset=8
4747
// CHECK-32-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254
4848
// CHECK-32-NEXT: (field name=_value offset=0
4949
// CHECK-32-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254)))))
@@ -61,12 +61,12 @@ reflect(object: derivedClass)
6161
// CHECK-64: (class inherits_NSObject.DerivedNSClass)
6262

6363
// CHECK-64: Type info:
64-
// CHECK-64-NEXT: (class_instance size=40 alignment=8 stride=40 num_extra_inhabitants=0
65-
// CHECK-64-NEXT: (field name=y offset=25
64+
// CHECK-64-NEXT: (class_instance size=32 alignment=8 stride=32 num_extra_inhabitants=0
65+
// CHECK-64-NEXT: (field name=y offset=17
6666
// CHECK-64-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254
6767
// CHECK-64-NEXT: (field name=_value offset=0
6868
// CHECK-64-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254))))
69-
// CHECK-64-NEXT: (field name=z offset=32
69+
// CHECK-64-NEXT: (field name=z offset=24
7070
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0
7171
// CHECK-64-NEXT: (field name=_value offset=0
7272
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))))
@@ -76,12 +76,12 @@ reflect(object: derivedClass)
7676
// CHECK-32: (class inherits_NSObject.DerivedNSClass)
7777

7878
// CHECK-32: Type info:
79-
// CHECK-32-NEXT: (class_instance size=24 alignment=4 stride=24 num_extra_inhabitants=0
80-
// CHECK-32-NEXT: (field name=y offset=17
79+
// CHECK-32-NEXT: (class_instance size=16 alignment=4 stride=16 num_extra_inhabitants=0
80+
// CHECK-32-NEXT: (field name=y offset=9
8181
// CHECK-32-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254
8282
// CHECK-32-NEXT: (field name=_value offset=0
8383
// CHECK-32-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254))))
84-
// CHECK-32-NEXT: (field name=z offset=20
84+
// CHECK-32-NEXT: (field name=z offset=12
8585
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0
8686
// CHECK-32-NEXT: (field name=_value offset=0
8787
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))))
@@ -131,12 +131,12 @@ reflect(object: alignedClass)
131131
// CHECK-64: (class inherits_NSObject.AlignedNSClass)
132132

133133
// CHECK-64: Type info:
134-
// CHECK-64-NEXT: (class_instance size=48 alignment=16 stride=48 num_extra_inhabitants=0
135-
// CHECK-64-NEXT: (field name=w offset=16
134+
// CHECK-64-NEXT: (class_instance size=32 alignment=16 stride=32 num_extra_inhabitants=0
135+
// CHECK-64-NEXT: (field name=w offset=8
136136
// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0
137137
// CHECK-64-NEXT: (field name=_value offset=0
138138
// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0))))
139-
// CHECK-64-NEXT: (field name=x offset=32
139+
// CHECK-64-NEXT: (field name=x offset=16
140140
// CHECK-64-NEXT: (builtin size=16 alignment=16 stride=16 num_extra_inhabitants=0)))
141141

142142
// CHECK-32: Reflecting an object.
@@ -145,7 +145,7 @@ reflect(object: alignedClass)
145145

146146
// CHECK-32: Type info:
147147
// CHECK-32-NEXT: (class_instance size=32 alignment=16 stride=32 num_extra_inhabitants=0
148-
// CHECK-32-NEXT: (field name=w offset=12
148+
// CHECK-32-NEXT: (field name=w offset=4
149149
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0
150150
// CHECK-32-NEXT: (field name=_value offset=0
151151
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0))))

validation-test/Reflection/inherits_ObjCClasses.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ reflect(object: firstClassB)
6161
// CHECK-32: (class inherits_ObjCClasses.FirstClassB)
6262

6363
// CHECK-32: Type info:
64-
// CHECK-32-NEXT: (class_instance size=16 alignment=4 stride=16 num_extra_inhabitants=0
65-
// CHECK-32-NEXT: (field name=zz offset=12
64+
// CHECK-32-NEXT: (class_instance size=12 alignment=4 stride=12 num_extra_inhabitants=0
65+
// CHECK-32-NEXT: (field name=zz offset=8
6666
// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0
6767
// CHECK-32-NEXT: (field name=_value offset=0
6868
// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))))

0 commit comments

Comments
 (0)