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;
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.

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

@ -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;

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

@ -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.

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

@ -855,6 +855,8 @@ void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(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);
}

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

@ -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;

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

@ -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