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
This commit is contained in:
John McCall 2012-10-17 04:53:31 +00:00
Родитель 621915c7a4
Коммит b03527a9a3
6 изменённых файлов: 52 добавлений и 12 удалений

Просмотреть файл

@ -1581,8 +1581,12 @@ class ObjCImplementationDecl : public ObjCImplDecl {
CXXCtorInitializer **IvarInitializers; CXXCtorInitializer **IvarInitializers;
unsigned NumIvarInitializers; unsigned NumIvarInitializers;
/// true if class has a .cxx_[construct,destruct] method. /// Do the ivars of this class require initialization other than
bool HasCXXStructors : 1; /// zero-initialization?
bool HasNonZeroConstructors : 1;
/// Do the ivars of this class require non-trivial destruction?
bool HasDestructors : 1;
ObjCImplementationDecl(DeclContext *DC, ObjCImplementationDecl(DeclContext *DC,
ObjCInterfaceDecl *classInterface, ObjCInterfaceDecl *classInterface,
@ -1594,7 +1598,7 @@ class ObjCImplementationDecl : public ObjCImplDecl {
SuperClass(superDecl), IvarLBraceLoc(IvarLBraceLoc), SuperClass(superDecl), IvarLBraceLoc(IvarLBraceLoc),
IvarRBraceLoc(IvarRBraceLoc), IvarRBraceLoc(IvarRBraceLoc),
IvarInitializers(0), NumIvarInitializers(0), IvarInitializers(0), NumIvarInitializers(0),
HasCXXStructors(false) {} HasNonZeroConstructors(false), HasDestructors(false) {}
public: public:
static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC, static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC,
ObjCInterfaceDecl *classInterface, ObjCInterfaceDecl *classInterface,
@ -1638,8 +1642,15 @@ public:
CXXCtorInitializer ** initializers, CXXCtorInitializer ** initializers,
unsigned numInitializers); unsigned numInitializers);
bool hasCXXStructors() const { return HasCXXStructors; } /// Do any of the ivars of this class (not counting its base classes)
void setHasCXXStructors(bool val) { HasCXXStructors = val; } /// 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 /// getIdentifier - Get the identifier that names the class
/// interface associated with this implementation. /// interface associated with this implementation.

Просмотреть файл

@ -2367,7 +2367,10 @@ enum NonFragileClassFlags {
NonFragileABI_Class_HasIvarReleaser = 0x00040, NonFragileABI_Class_HasIvarReleaser = 0x00040,
/// Class implementation was compiled under ARC. /// 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_begin(),
Interface->all_referenced_protocol_end()); Interface->all_referenced_protocol_end());
unsigned Flags = FragileABI_Class_Factory; unsigned Flags = FragileABI_Class_Factory;
if (ID->hasCXXStructors()) if (ID->hasNonZeroConstructors() || ID->hasDestructors())
Flags |= FragileABI_Class_HasCXXStructors; Flags |= FragileABI_Class_HasCXXStructors;
unsigned Size = unsigned Size =
CGM.getContext().getASTObjCImplementationLayout(ID).getSize().getQuantity(); CGM.getContext().getASTObjCImplementationLayout(ID).getSize().getQuantity();
@ -5154,12 +5157,20 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
llvm::GlobalVariable *SuperClassGV, *IsAGV; llvm::GlobalVariable *SuperClassGV, *IsAGV;
// Build the flags for the metaclass.
bool classIsHidden = bool classIsHidden =
ID->getClassInterface()->getVisibility() == HiddenVisibility; ID->getClassInterface()->getVisibility() == HiddenVisibility;
if (classIsHidden) if (classIsHidden)
flags |= NonFragileABI_Class_Hidden; 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; flags |= NonFragileABI_Class_HasCXXStructors;
if (!ID->hasNonZeroConstructors())
flags |= NonFragileABI_Class_HasCXXDestructorOnly;
}
if (!ID->getClassInterface()->getSuperClass()) { if (!ID->getClassInterface()->getSuperClass()) {
// class is root // class is root
flags |= NonFragileABI_Class_Root; flags |= NonFragileABI_Class_Root;
@ -5194,9 +5205,20 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
flags = 0; flags = 0;
if (classIsHidden) if (classIsHidden)
flags |= NonFragileABI_Class_Hidden; flags |= NonFragileABI_Class_Hidden;
if (ID->hasCXXStructors())
if (ID->hasNonZeroConstructors() || ID->hasDestructors()) {
flags |= NonFragileABI_Class_HasCXXStructors; 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())) if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface()))
flags |= NonFragileABI_Class_Exception; flags |= NonFragileABI_Class_Exception;

Просмотреть файл

@ -2541,7 +2541,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
/*isDefined=*/false, ObjCMethodDecl::Required); /*isDefined=*/false, ObjCMethodDecl::Required);
D->addInstanceMethod(DTORMethod); D->addInstanceMethod(DTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); 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 // If the implementation doesn't have any ivar initializers, we don't need
@ -2565,7 +2565,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
ObjCMethodDecl::Required); ObjCMethodDecl::Required);
D->addInstanceMethod(CTORMethod); D->addInstanceMethod(CTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
D->setHasCXXStructors(true); D->setHasNonZeroConstructors(true);
} }
/// EmitNamespace - Emit all declarations in a namespace. /// EmitNamespace - Emit all declarations in a namespace.

Просмотреть файл

@ -855,6 +855,8 @@ void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx)); D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
D->setIvarLBraceLoc(ReadSourceLocation(Record, Idx)); D->setIvarLBraceLoc(ReadSourceLocation(Record, Idx));
D->setIvarRBraceLoc(ReadSourceLocation(Record, Idx)); D->setIvarRBraceLoc(ReadSourceLocation(Record, Idx));
D->setHasNonZeroConstructors(Record[Idx++]);
D->setHasDestructors(Record[Idx++]);
llvm::tie(D->IvarInitializers, D->NumIvarInitializers) llvm::tie(D->IvarInitializers, D->NumIvarInitializers)
= Reader.ReadCXXCtorInitializers(F, Record, Idx); = Reader.ReadCXXCtorInitializers(F, Record, Idx);
} }

Просмотреть файл

@ -606,6 +606,8 @@ void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
Writer.AddDeclRef(D->getSuperClass(), Record); Writer.AddDeclRef(D->getSuperClass(), Record);
Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record); Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record);
Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record); Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
Record.push_back(D->hasNonZeroConstructors());
Record.push_back(D->hasDestructors());
Writer.AddCXXCtorInitializers(D->IvarInitializers, D->NumIvarInitializers, Writer.AddCXXCtorInitializers(D->IvarInitializers, D->NumIvarInitializers,
Record); Record);
Code = serialization::DECL_OBJC_IMPLEMENTATION; Code = serialization::DECL_OBJC_IMPLEMENTATION;

Просмотреть файл

@ -602,7 +602,10 @@ void test22(_Bool cond) {
// rdar://problem/8922540 // rdar://problem/8922540
// Note that we no longer emit .release_ivars flags. // 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 @interface Test23 { id x; } @end
@implementation Test23 @end @implementation Test23 @end