Skip to content

Commit c606c0e

Browse files
committed
[ObjC] Check entire chain of superclasses to see if class layout is statically known
As of now, we only check if a class directly inherits from NSObject to determine if said class has fixed offsets and can therefore have its memory layout statically known. However, if an NSObject subclass has fixed offsets, then so must the subclasses of that subclass, so this allows us to optimize instances of subclasses of subclasses that inherit from NSObject and so on. To determine this, we need to find that the compiler can see the implementation of each intermediate class, as that means it is statically linked.
1 parent b25d3b4 commit c606c0e

File tree

2 files changed

+44
-30
lines changed

2 files changed

+44
-30
lines changed

clang/lib/CodeGen/CGObjCMac.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,12 +1593,20 @@ class CGObjCNonFragileABIMac : public CGObjCCommonMac {
15931593
}
15941594

15951595
bool isClassLayoutKnownStatically(const ObjCInterfaceDecl *ID) {
1596-
// NSObject is a fixed size. If we can see the @implementation of a class
1597-
// which inherits from NSObject then we know that all it's offsets also must
1598-
// be fixed. FIXME: Can we do this if see a chain of super classes with
1599-
// implementations leading to NSObject?
1600-
return ID->getImplementation() && ID->getSuperClass() &&
1601-
ID->getSuperClass()->getName() == "NSObject";
1596+
// Test a class by checking its superclasses up to
1597+
// its base class if it has one.
1598+
for (; ID; ID = ID->getSuperClass()) {
1599+
// The layout of base class NSObject
1600+
// is guaranteed to be statically known
1601+
if (ID->getIdentifier()->getName() == "NSObject")
1602+
return true;
1603+
1604+
// If we cannot see the @implementation of a class,
1605+
// we cannot statically know the class layout.
1606+
if (!ID->getImplementation())
1607+
return false;
1608+
}
1609+
return false;
16021610
}
16031611

16041612
public:

clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
// CHECK: @"OBJC_IVAR_$_StaticLayout.static_layout_ivar" = hidden constant i64 20
44
// CHECK: @"OBJC_IVAR_$_SuperClass.superClassIvar" = hidden constant i64 20
55
// CHECK: @"OBJC_IVAR_$_SuperClass._superClassProperty" = hidden constant i64 24
6-
// CHECK: @"OBJC_IVAR_$_IntermediateClass.intermediateClassIvar" = global i64 32
7-
// CHECK: @"OBJC_IVAR_$_IntermediateClass.intermediateClassIvar2" = global i64 40
8-
// CHECK: @"OBJC_IVAR_$_IntermediateClass._intermediateProperty" = hidden global i64 48
9-
// CHECK: @"OBJC_IVAR_$_SubClass.subClassIvar" = global i64 56
10-
// CHECK: @"OBJC_IVAR_$_SubClass._subClassProperty" = hidden global i64 64
6+
// CHECK: @"OBJC_IVAR_$_IntermediateClass.intermediateClassIvar" = constant i64 32
7+
// CHECK: @"OBJC_IVAR_$_IntermediateClass.intermediateClassIvar2" = constant i64 40
8+
// CHECK: @"OBJC_IVAR_$_IntermediateClass._intermediateProperty" = hidden constant i64 48
9+
// CHECK: @"OBJC_IVAR_$_SubClass.subClassIvar" = constant i64 56
10+
// CHECK: @"OBJC_IVAR_$_SubClass._subClassProperty" = hidden constant i64 64
1111
// CHECK: @"OBJC_IVAR_$_NotStaticLayout.not_static_layout_ivar" = hidden global i64 12
1212

1313
@interface NSObject {
@@ -21,13 +21,15 @@ @interface StaticLayout : NSObject
2121
@implementation StaticLayout {
2222
int static_layout_ivar;
2323
}
24+
25+
// CHECK-LABEL: define internal void @"\01-[StaticLayout meth]"
2426
-(void)meth {
2527
static_layout_ivar = 0;
2628
// CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_StaticLayout
29+
// CHECK: getelementptr inbounds i8, ptr %0, i64 20
2730
}
2831
@end
2932

30-
// Ivars declared in the @interface
3133
@interface SuperClass : NSObject
3234
@property (nonatomic, assign) int superClassProperty;
3335
@end
@@ -40,21 +42,19 @@ @implementation SuperClass {
4042
- (void)superClassMethod {
4143
_superClassProperty = 42;
4244
superClassIvar = 10;
43-
// CHECK: load i64, ptr @"OBJC_IVAR_$_SuperClass
45+
// CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_SuperClass
4446
// CHECK: getelementptr inbounds i8, ptr %1, i64 20
4547
}
4648

47-
// implicitly synthesized method here
49+
// Implicitly synthesized method here
4850
// CHECK-LABEL: define internal i32 @"\01-[SuperClass superClassProperty]"
4951
// CHECK: getelementptr inbounds i8, ptr %0, i64 24
5052

5153
// CHECK-LABEL: define internal void @"\01-[SuperClass setSuperClassProperty:]"
5254
// CHECK: getelementptr inbounds i8, ptr %1, i64 24
5355
@end
5456

55-
// Inheritance and Ivars
56-
@interface IntermediateClass : SuperClass
57-
{
57+
@interface IntermediateClass : SuperClass {
5858
double intermediateClassIvar;
5959

6060
@protected
@@ -65,10 +65,12 @@ @interface IntermediateClass : SuperClass
6565

6666
@implementation IntermediateClass
6767
@synthesize intermediateProperty = _intermediateProperty;
68+
69+
// CHECK-LABEL: define internal void @"\01-[IntermediateClass intermediateClassMethod]"
6870
- (void)intermediateClassMethod {
6971
intermediateClassIvar = 3.14;
70-
// CHECK: load i64, ptr @"OBJC_IVAR_$_IntermediateClass
71-
// CHECK: getelementptr inbounds i8, ptr %0, i64 %ivar
72+
// CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_IntermediateClass
73+
// CHECK: getelementptr inbounds i8, ptr %0, i64 32
7274
}
7375

7476
// CHECK-LABEL: define internal void @"\01-[IntermediateClass intermediateClassPropertyMethod]"
@@ -81,39 +83,41 @@ - (void)intermediateClassPropertyMethod {
8183
// CHECK-LABEL: define internal void @"\01-[IntermediateClass intermediateClassPropertyMethodDirect]"
8284
- (void)intermediateClassPropertyMethodDirect {
8385
_intermediateProperty = 0;
84-
// CHECK: load i64, ptr @"OBJC_IVAR_$_IntermediateClass._intermediateProperty"
86+
// CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_IntermediateClass._intermediateProperty"
87+
// CHECK: getelementptr inbounds i8, ptr %0, i64 48
8588
}
8689
@end
8790

88-
@interface SubClass : IntermediateClass
89-
{
91+
@interface SubClass : IntermediateClass {
9092
double subClassIvar;
9193
}
9294
@property (nonatomic, assign) SubClass *subClassProperty;
9395
@end
9496

9597
@implementation SubClass
98+
9699
// CHECK-LABEL: define internal void @"\01-[SubClass subclassVar]"
97100
- (void)subclassVar {
98-
99101
subClassIvar = 6.28;
100-
// CHECK: load i64, ptr @"OBJC_IVAR_$_SubClass
101-
// CHECK: getelementptr inbounds i8, ptr %0, i64 %ivar
102+
// CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_SubClass
103+
// CHECK: getelementptr inbounds i8, ptr %0, i64 56
102104
}
103105

104106
// CHECK-LABEL: define internal void @"\01-[SubClass intermediateSubclassVar]"
105107
-(void)intermediateSubclassVar {
106108
intermediateClassIvar = 3.14;
107-
// CHECK: load i64, ptr @"OBJC_IVAR_$_IntermediateClass
108-
// CHECK: getelementptr inbounds i8, ptr %0, i64 %ivar
109+
// CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_IntermediateClass
110+
// CHECK: getelementptr inbounds i8, ptr %0, i64 32
109111
}
110112

111-
// implicit synthesized method here:
113+
// Implicit synthesized method here:
112114
// CHECK-LABEL: define internal ptr @"\01-[SubClass subClassProperty]"
113-
// CHECK: load i64, ptr @"OBJC_IVAR_$_SubClass._subClassProperty"
115+
// CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_SubClass._subClassProperty"
116+
// CHECK: getelementptr inbounds i8, ptr %0, i64 64
114117

115118
// CHECK-LABEL: define internal void @"\01-[SubClass setSubClassProperty:]"
116-
// CHECK: load i64, ptr @"OBJC_IVAR_$_SubClass._subClassProperty"
119+
// CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_SubClass._subClassProperty"
120+
// CHECK: getelementptr inbounds i8, ptr %1, i64 64
117121
@end
118122

119123
@interface NotNSObject {
@@ -127,6 +131,8 @@ @interface NotStaticLayout : NotNSObject
127131
@implementation NotStaticLayout {
128132
int not_static_layout_ivar;
129133
}
134+
135+
// CHECK-LABEL: define internal void @"\01-[NotStaticLayout meth]"
130136
-(void)meth {
131137
not_static_layout_ivar = 0;
132138
// CHECK: load i64, ptr @"OBJC_IVAR_$_NotStaticLayout.not_static_layout_ivar

0 commit comments

Comments
 (0)