From 3c8220405d2dfc93da1c0c69942d07b0bd12927a Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Wed, 13 Feb 2013 22:50:36 +0000 Subject: [PATCH] objective-C: Make order of ivars which are synthesized 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 | 47 +++++++++++++++--- clang/test/CodeGenObjC/reorder-synthesized-ivars.m | 58 ++++++++++++++++++++++ 2 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 clang/test/CodeGenObjC/reorder-synthesized-ivars.m diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index ce765a7..6e740bf 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -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 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 index 0000000..3045b49 --- /dev/null +++ b/clang/test/CodeGenObjC/reorder-synthesized-ivars.m @@ -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 -- 2.7.4