]> granicus.if.org Git - clang/commitdiff
[CodeGenObjC] Use a constant value for non-fragile ivar offsets when possible
authorErik Pilkington <erik.pilkington@gmail.com>
Thu, 17 Jan 2019 18:18:53 +0000 (18:18 +0000)
committerErik Pilkington <erik.pilkington@gmail.com>
Thu, 17 Jan 2019 18:18:53 +0000 (18:18 +0000)
If a class inherits from NSObject and has an implementation, then we
can assume that ivar offsets won't need to be updated by the runtime.
This allows us to index into the object using a constant value and
avoid loading from the ivar offset variable.

This patch was adapted from one written by Pete Cooper.

rdar://problem/10132568

Differential revision: https://reviews.llvm.org/D56802

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@351461 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGObjCMac.cpp
test/CodeGenObjC/constant-non-fragile-ivar-offset.m [new file with mode: 0644]
test/CodeGenObjC/optimize-ivar-offset-load.m
test/CodeGenObjC/reorder-synthesized-ivars.m

index d91eb43ca32227de4769ae7ba1e204d9216c7421..9b3522e8f81c9d0aa9650a24c0e46c5d936569fc 100644 (file)
@@ -1550,6 +1550,15 @@ private:
     return false;
   }
 
+  bool isClassLayoutKnownStatically(const ObjCInterfaceDecl *ID) {
+    // NSObject is a fixed size. If we can see the @implementation of a class
+    // which inherits from NSObject then we know that all it's offsets also must
+    // be fixed. FIXME: Can we do this if see a chain of super classes with
+    // implementations leading to NSObject?
+    return ID->getImplementation() && ID->getSuperClass() &&
+           ID->getSuperClass()->getName() == "NSObject";
+  }
+
 public:
   CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm);
 
@@ -6702,6 +6711,12 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
       IvarOffsetGV->setVisibility(llvm::GlobalValue::DefaultVisibility);
   }
 
+  // If ID's layout is known, then make the global constant. This serves as a
+  // useful assertion: we'll never use this variable to calculate ivar offsets,
+  // so if the runtime tries to patch it then we should crash.
+  if (isClassLayoutKnownStatically(ID))
+    IvarOffsetGV->setConstant(true);
+
   if (CGM.getTriple().isOSBinFormatMachO())
     IvarOffsetGV->setSection("__DATA, __objc_ivar");
   return IvarOffsetGV;
@@ -6990,17 +7005,24 @@ LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar(
                                   Offset);
 }
 
-llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset(
-  CodeGen::CodeGenFunction &CGF,
-  const ObjCInterfaceDecl *Interface,
-  const ObjCIvarDecl *Ivar) {
-  llvm::Value *IvarOffsetValue = ObjCIvarOffsetVariable(Interface, Ivar);
-  IvarOffsetValue = CGF.Builder.CreateAlignedLoad(IvarOffsetValue,
-                                                  CGF.getSizeAlign(), "ivar");
-  if (IsIvarOffsetKnownIdempotent(CGF, Ivar))
-    cast<llvm::LoadInst>(IvarOffsetValue)
-        ->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
-                      llvm::MDNode::get(VMContext, None));
+llvm::Value *
+CGObjCNonFragileABIMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
+                                       const ObjCInterfaceDecl *Interface,
+                                       const ObjCIvarDecl *Ivar) {
+  llvm::Value *IvarOffsetValue;
+  if (isClassLayoutKnownStatically(Interface)) {
+    IvarOffsetValue = llvm::ConstantInt::get(
+        ObjCTypes.IvarOffsetVarTy,
+        ComputeIvarBaseOffset(CGM, Interface->getImplementation(), Ivar));
+  } else {
+    llvm::GlobalVariable *GV = ObjCIvarOffsetVariable(Interface, Ivar);
+    IvarOffsetValue =
+        CGF.Builder.CreateAlignedLoad(GV, CGF.getSizeAlign(), "ivar");
+    if (IsIvarOffsetKnownIdempotent(CGF, Ivar))
+      cast<llvm::LoadInst>(IvarOffsetValue)
+          ->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
+                        llvm::MDNode::get(VMContext, None));
+  }
 
   // This could be 32bit int or 64bit integer depending on the architecture.
   // Cast it to 64bit integer value, if it is a 32bit integer ivar offset value
diff --git a/test/CodeGenObjC/constant-non-fragile-ivar-offset.m b/test/CodeGenObjC/constant-non-fragile-ivar-offset.m
new file mode 100644 (file)
index 0000000..34c393d
--- /dev/null
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: @"OBJC_IVAR_$_StaticLayout.static_layout_ivar" = hidden constant i64 20
+// CHECK: @"OBJC_IVAR_$_NotStaticLayout.not_static_layout_ivar" = hidden global i64 12
+
+@interface NSObject {
+  int these, will, never, change, ever;
+}
+@end
+
+@interface StaticLayout : NSObject
+@end
+
+@implementation StaticLayout {
+  int static_layout_ivar;
+}
+-(void)meth {
+  static_layout_ivar = 0;
+  // CHECK-NOT: load i64, i64* @"OBJC_IVAR_$_StaticLayout
+}
+@end
+
+@interface NotNSObject {
+  int these, might, change;
+}
+@end
+
+@interface NotStaticLayout : NotNSObject
+@end
+
+@implementation NotStaticLayout {
+  int not_static_layout_ivar;
+}
+-(void)meth {
+  not_static_layout_ivar = 0;
+  // CHECK: load i64, i64* @"OBJC_IVAR_$_NotStaticLayout.not_static_layout_ivar
+}
+@end
index 6a073dbd29c19c2ed92bfe1109c9c9a7bf77e335..6f902d79d369d528c578ea40df6e65b37e8d9024 100644 (file)
@@ -1,17 +1,17 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10  -O0 -emit-llvm %s -o -  | FileCheck %s
 // rdar://16095748
 
-@interface NSObject 
+@interface MyNSObject 
 @end
 
-@interface SampleClass : NSObject {
+@interface SampleClass : MyNSObject {
     @public
     int _value;
 }
 + (SampleClass*) new;
 @end
 
-@interface AppDelegate  : NSObject
+@interface AppDelegate  : MyNSObject
 @end
 
 extern void foo(int);
index ef1bb79bcccb57d80d3b8de922c55e1a6281b369..90f39f1a89ece05ca5513c9440ba1a8a1672e6f3 100644 (file)
@@ -39,20 +39,20 @@ typedef signed char BOOL;
 @end
 
 // CHECK: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean1
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean2
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean3
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean4
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean5
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean6
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean7
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean8
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean9
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object1
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object2
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object3
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object4
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object5
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object6
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object7
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object8
-// CHECK-NEXT: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object9
+// CHECK: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean2
+// CHECK: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean3
+// CHECK: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean4
+// CHECK: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean5
+// CHECK: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean6
+// CHECK: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean7
+// CHECK: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean8
+// CHECK: @{{.*}} = private unnamed_addr constant [10 x i8] c"_boolean9
+// CHECK: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object1
+// CHECK: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object2
+// CHECK: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object3
+// CHECK: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object4
+// CHECK: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object5
+// CHECK: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object6
+// CHECK: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object7
+// CHECK: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object8
+// CHECK: @{{.*}} = private unnamed_addr constant [9 x i8] c"_object9