From b03527a9a395168762ad8e25e59a7a272dd74561 Mon Sep 17 00:00:00 2001 From: John McCall Date: Wed, 17 Oct 2012 04:53:31 +0000 Subject: [PATCH] Set a special flag in class metadata when an Objective-C class has ivars that require destruction, but none that require anything except zero-initialization. This is common in ARC and (when true throughout a class hierarchy) permits the elimination of an unnecessary message-send during allocation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166088 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclObjC.h | 21 +++++++++++++++----- lib/CodeGen/CGObjCMac.cpp | 30 +++++++++++++++++++++++++---- lib/CodeGen/CodeGenModule.cpp | 4 ++-- lib/Serialization/ASTReaderDecl.cpp | 2 ++ lib/Serialization/ASTWriterDecl.cpp | 2 ++ test/CodeGenObjC/arc.m | 5 ++++- 6 files changed, 52 insertions(+), 12 deletions(-) diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 99dd293cf9..3372b8adbe 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -1581,8 +1581,12 @@ class ObjCImplementationDecl : public ObjCImplDecl { CXXCtorInitializer **IvarInitializers; unsigned NumIvarInitializers; - /// true if class has a .cxx_[construct,destruct] method. - bool HasCXXStructors : 1; + /// Do the ivars of this class require initialization other than + /// zero-initialization? + bool HasNonZeroConstructors : 1; + + /// Do the ivars of this class require non-trivial destruction? + bool HasDestructors : 1; ObjCImplementationDecl(DeclContext *DC, ObjCInterfaceDecl *classInterface, @@ -1594,7 +1598,7 @@ class ObjCImplementationDecl : public ObjCImplDecl { SuperClass(superDecl), IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc), IvarInitializers(0), NumIvarInitializers(0), - HasCXXStructors(false) {} + HasNonZeroConstructors(false), HasDestructors(false) {} public: static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC, ObjCInterfaceDecl *classInterface, @@ -1638,8 +1642,15 @@ public: CXXCtorInitializer ** initializers, unsigned numInitializers); - bool hasCXXStructors() const { return HasCXXStructors; } - void setHasCXXStructors(bool val) { HasCXXStructors = val; } + /// Do any of the ivars of this class (not counting its base classes) + /// require construction other than zero-initialization? + bool hasNonZeroConstructors() const { return HasNonZeroConstructors; } + void setHasNonZeroConstructors(bool val) { HasNonZeroConstructors = val; } + + /// Do any of the ivars of this class (not counting its base classes) + /// require non-trivial destruction? + bool hasDestructors() const { return HasDestructors; } + void setHasDestructors(bool val) { HasDestructors = val; } /// getIdentifier - Get the identifier that names the class /// interface associated with this implementation. diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 01179cca6b..9954851743 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -2367,7 +2367,10 @@ enum NonFragileClassFlags { NonFragileABI_Class_HasIvarReleaser = 0x00040, /// Class implementation was compiled under ARC. - NonFragileABI_Class_CompiledByARC = 0x00080 + NonFragileABI_Class_CompiledByARC = 0x00080, + + /// Class has non-trivial destructors, but zero-initialization is okay. + NonFragileABI_Class_HasCXXDestructorOnly = 0x00100 }; /* @@ -2401,7 +2404,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { Interface->all_referenced_protocol_begin(), Interface->all_referenced_protocol_end()); unsigned Flags = FragileABI_Class_Factory; - if (ID->hasCXXStructors()) + if (ID->hasNonZeroConstructors() || ID->hasDestructors()) Flags |= FragileABI_Class_HasCXXStructors; unsigned Size = CGM.getContext().getASTObjCImplementationLayout(ID).getSize().getQuantity(); @@ -5154,12 +5157,20 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { llvm::GlobalVariable *SuperClassGV, *IsAGV; + // Build the flags for the metaclass. bool classIsHidden = ID->getClassInterface()->getVisibility() == HiddenVisibility; if (classIsHidden) flags |= NonFragileABI_Class_Hidden; - if (ID->hasCXXStructors()) + + // FIXME: why is this flag set on the metaclass? + // ObjC metaclasses have no fields and don't really get constructed. + if (ID->hasNonZeroConstructors() || ID->hasDestructors()) { flags |= NonFragileABI_Class_HasCXXStructors; + if (!ID->hasNonZeroConstructors()) + flags |= NonFragileABI_Class_HasCXXDestructorOnly; + } + if (!ID->getClassInterface()->getSuperClass()) { // class is root flags |= NonFragileABI_Class_Root; @@ -5194,9 +5205,20 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { flags = 0; if (classIsHidden) flags |= NonFragileABI_Class_Hidden; - if (ID->hasCXXStructors()) + + if (ID->hasNonZeroConstructors() || ID->hasDestructors()) { flags |= NonFragileABI_Class_HasCXXStructors; + // Set a flag to enable a runtime optimization when a class has + // fields that require destruction but which don't require + // anything except zero-initialization during construction. This + // is most notably true of __strong and __weak types, but you can + // also imagine there being C++ types with non-trivial default + // constructors that merely set all fields to null. + if (!ID->hasNonZeroConstructors()) + flags |= NonFragileABI_Class_HasCXXDestructorOnly; + } + if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface())) flags |= NonFragileABI_Class_Exception; diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index e9344a1351..95753d540e 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -2541,7 +2541,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { /*isDefined=*/false, ObjCMethodDecl::Required); D->addInstanceMethod(DTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); - D->setHasCXXStructors(true); + D->setHasDestructors(true); } // If the implementation doesn't have any ivar initializers, we don't need @@ -2565,7 +2565,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { ObjCMethodDecl::Required); D->addInstanceMethod(CTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true); - D->setHasCXXStructors(true); + D->setHasNonZeroConstructors(true); } /// EmitNamespace - Emit all declarations in a namespace. diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index d85cb4eca9..17509c8527 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -855,6 +855,8 @@ void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { D->setSuperClass(ReadDeclAs(Record, Idx)); D->setIvarLBraceLoc(ReadSourceLocation(Record, Idx)); D->setIvarRBraceLoc(ReadSourceLocation(Record, Idx)); + D->setHasNonZeroConstructors(Record[Idx++]); + D->setHasDestructors(Record[Idx++]); llvm::tie(D->IvarInitializers, D->NumIvarInitializers) = Reader.ReadCXXCtorInitializers(F, Record, Idx); } diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 2270e8f621..e84afba549 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -606,6 +606,8 @@ void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { Writer.AddDeclRef(D->getSuperClass(), Record); Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record); Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record); + Record.push_back(D->hasNonZeroConstructors()); + Record.push_back(D->hasDestructors()); Writer.AddCXXCtorInitializers(D->IvarInitializers, D->NumIvarInitializers, Record); Code = serialization::DECL_OBJC_IMPLEMENTATION; diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m index d6bce5f87d..8e38019de5 100644 --- a/test/CodeGenObjC/arc.m +++ b/test/CodeGenObjC/arc.m @@ -602,7 +602,10 @@ void test22(_Bool cond) { // rdar://problem/8922540 // Note that we no longer emit .release_ivars flags. -// CHECK-GLOBALS: @"\01l_OBJC_CLASS_RO_$_Test23" = internal global [[RO_T:%.*]] { i32 134, +// rdar://problem/12492434 +// Note that we set the flag saying that we need destruction *and* +// the flag saying that we don't also need construction. +// CHECK-GLOBALS: @"\01l_OBJC_CLASS_RO_$_Test23" = internal global [[RO_T:%.*]] { i32 390, @interface Test23 { id x; } @end @implementation Test23 @end