objective-C: Make order of ivars which are synthesized
authorFariborz Jahanian <fjahanian@apple.com>
Wed, 13 Feb 2013 22:50:36 +0000 (22:50 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Wed, 13 Feb 2013 22:50:36 +0000 (22:50 +0000)
in the course of property synthesis deterministic (ordered
by their type size), instead of having hashtable order
(as it is currently). // rdar://13192366

llvm-svn: 175100

clang/lib/AST/DeclObjC.cpp
clang/test/CodeGenObjC/reorder-synthesized-ivars.m [new file with mode: 0644]

index ce765a7..6e740bf 100644 (file)
@@ -1074,6 +1074,20 @@ void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) {
   getASTContext().setObjCImplementation(getDefinition(), ImplD);
 }
 
+namespace {
+  struct SynthesizeIvarChunk {
+    uint64_t Size;
+    ObjCIvarDecl *Ivar;
+    SynthesizeIvarChunk(uint64_t size, ObjCIvarDecl *ivar)
+      : Size(size), Ivar(ivar) {}
+  };
+
+  bool operator<(const SynthesizeIvarChunk & LHS,
+                 const SynthesizeIvarChunk &RHS) {
+      return LHS.Size < RHS.Size;
+  }
+}
+
 /// all_declared_ivar_begin - return first ivar declared in this class,
 /// its extensions and its implementation. Lazily build the list on first
 /// access.
@@ -1110,14 +1124,33 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
   
   if (ObjCImplementationDecl *ImplDecl = getImplementation()) {
     if (!ImplDecl->ivar_empty()) {
-      ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
-                                            E = ImplDecl->ivar_end();
-      if (!data().IvarList) {
-        data().IvarList = *I; ++I;
-        curIvar = data().IvarList;
+      SmallVector<SynthesizeIvarChunk, 16> layout;
+      for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
+           E = ImplDecl->ivar_end(); I != E; ++I) {
+        ObjCIvarDecl *IV = *I;
+        if (IV->getSynthesize() && !IV->isInvalidDecl()) {
+          layout.push_back(SynthesizeIvarChunk(
+                             IV->getASTContext().getTypeSize(IV->getType()), IV));
+          continue;
+        }
+        if (!data().IvarList)
+          data().IvarList = *I;
+        else
+          curIvar->setNextIvar(*I);
+        curIvar = *I;
+      }
+      
+      if (!layout.empty()) {
+        // Order synthesized ivars by their size.
+        std::stable_sort(layout.begin(), layout.end());
+        unsigned Ix = 0, EIx = layout.size();
+        if (!data().IvarList) {
+          data().IvarList = layout[0].Ivar; Ix++;
+          curIvar = data().IvarList;
+        }
+        for ( ; Ix != EIx; curIvar = layout[Ix].Ivar, Ix++)
+          curIvar->setNextIvar(layout[Ix].Ivar);
       }
-      for ( ;I != E; curIvar = *I, ++I)
-        curIvar->setNextIvar(*I);
     }
   }
   return data().IvarList;
diff --git a/clang/test/CodeGenObjC/reorder-synthesized-ivars.m b/clang/test/CodeGenObjC/reorder-synthesized-ivars.m
new file mode 100644 (file)
index 0000000..3045b49
--- /dev/null
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-default-synthesize-properties -emit-llvm -x objective-c %s -o - | FileCheck %s
+// rdar://13192366
+typedef signed char BOOL;
+@interface NSObject 
+{
+  id isa;
+}
+@end
+
+@interface MyClass : NSObject
+
+@property (readwrite) BOOL boolean1;
+@property (readwrite, copy) id object1;
+@property (readwrite) BOOL boolean2;
+@property (readwrite, copy) id object2;
+@property (readwrite) BOOL boolean3;
+@property (readwrite, copy) id object3;
+@property (readwrite) BOOL boolean4;
+@property (readwrite, copy) id object4;
+@property (readwrite) BOOL boolean5;
+@property (readwrite, copy) id object5;
+@property (readwrite) BOOL boolean6;
+@property (readwrite, copy) id object6;
+@property (readwrite) BOOL boolean7;
+@property (readwrite) BOOL MyBool;
+@property (readwrite, copy) id object7;
+@property (readwrite) BOOL boolean8;
+@property (readwrite, copy) id object8;
+@property (readwrite) BOOL boolean9;
+@property (readwrite, copy) id object9;
+@end
+
+@implementation MyClass
+{
+  id MyIvar;
+  BOOL _MyBool;
+  char * pc;
+}
+@end
+
+// CHECK: @"{{.*}}" = internal global [10 x i8] c"_boolean
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object