Classes with "+load" methods need to go in the non-lazy class list (or

else the method will not be found by the runtime at class load time).

llvm-svn: 71904
This commit is contained in:
Daniel Dunbar 2009-05-15 22:33:15 +00:00
parent ca60224bbe
commit 9a017d7fcf
2 changed files with 70 additions and 10 deletions

View File

@ -810,10 +810,16 @@ protected:
/// DefinedClasses - List of defined classes.
std::vector<llvm::GlobalValue*> DefinedClasses;
/// DefinedNonLazyClasses - List of defined "non-lazy" classes.
std::vector<llvm::GlobalValue*> DefinedNonLazyClasses;
/// DefinedCategories - List of defined categories.
std::vector<llvm::GlobalValue*> DefinedCategories;
/// DefinedNonLazyCategories - List of defined "non-lazy" categories.
std::vector<llvm::GlobalValue*> DefinedNonLazyCategories;
/// UsedGlobals - List of globals to pack into the llvm.used metadata
/// to prevent them from being clobbered.
std::vector<llvm::GlobalVariable*> UsedGlobals;
@ -1259,16 +1265,20 @@ private:
uint32_t &InstanceSize);
// Shamelessly stolen from Analysis/CFRefCount.cpp
Selector GetNullarySelector(const char* name) {
Selector GetNullarySelector(const char* name) const {
IdentifierInfo* II = &CGM.getContext().Idents.get(name);
return CGM.getContext().Selectors.getSelector(0, &II);
}
Selector GetUnarySelector(const char* name) {
Selector GetUnarySelector(const char* name) const {
IdentifierInfo* II = &CGM.getContext().Idents.get(name);
return CGM.getContext().Selectors.getSelector(1, &II);
}
/// ImplementationIsNonLazy - Check whether the given category or
/// class implementation is "non-lazy".
bool ImplementationIsNonLazy(const DeclContext *DC) const;
public:
CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm);
// FIXME. All stubs for now!
@ -4075,21 +4085,21 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
// Build list of all implemented class addresses in array
// L_OBJC_LABEL_CLASS_$.
// FIXME. Also generate in L_OBJC_LABEL_NONLAZY_CLASS_$
// list of 'nonlazy' implementations (defined as those with a +load{}
// method!!).
AddModuleClassList(DefinedClasses,
"\01L_OBJC_LABEL_CLASS_$",
"__DATA, __objc_classlist, regular, no_dead_strip");
AddModuleClassList(DefinedNonLazyClasses,
"\01L_OBJC_LABEL_NONLAZY_CLASS_$",
"__DATA, __objc_nlclslist, regular, no_dead_strip");
// Build list of all implemented category addresses in array
// L_OBJC_LABEL_CATEGORY_$.
// FIXME. Also generate in L_OBJC_LABEL_NONLAZY_CATEGORY_$
// list of 'nonlazy' category implementations (defined as those with a +load{}
// method!!).
AddModuleClassList(DefinedCategories,
"\01L_OBJC_LABEL_CATEGORY_$",
"__DATA, __objc_catlist, regular, no_dead_strip");
AddModuleClassList(DefinedNonLazyCategories,
"\01L_OBJC_LABEL_NONLAZY_CATEGORY_$",
"__DATA, __objc_nlcatlist, regular, no_dead_strip");
// static int L_OBJC_IMAGE_INFO[2] = { 0, flags };
// FIXME. flags can be 0 | 1 | 2 | 6. For now just use 0
@ -4321,6 +4331,19 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
return GV;
}
bool
CGObjCNonFragileABIMac::ImplementationIsNonLazy(const DeclContext *DC) const {
DeclContext::lookup_const_result res =
DC->lookup(CGM.getContext(), GetNullarySelector("load"));
for (; res.first != res.second; ++res.first)
if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(*res.first))
if (OMD->isClassMethod())
return true;
return false;
}
void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID,
uint32_t &InstanceStart,
uint32_t &InstanceSize) {
@ -4425,6 +4448,10 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
classIsHidden);
DefinedClasses.push_back(ClassMD);
// Determine if this class is also "non-lazy".
if (ImplementationIsNonLazy(ID))
DefinedNonLazyClasses.push_back(ClassMD);
// Force the definition of the EHType if necessary.
if (flags & CLS_EXCEPTION)
GetInterfaceEHType(ID->getClassInterface(), true);
@ -4475,8 +4502,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
/// const struct _prop_list_t * const properties;
/// }
///
void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD)
{
void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
const ObjCInterfaceDecl *Interface = OCD->getClassInterface();
const char *Prefix = "\01l_OBJC_$_CATEGORY_";
std::string ExtCatName(Prefix + Interface->getNameAsString()+
@ -4553,6 +4579,10 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD)
GCATV->setSection("__DATA, __objc_const");
UsedGlobals.push_back(GCATV);
DefinedCategories.push_back(GCATV);
// Determine if this category is also "non-lazy".
if (ImplementationIsNonLazy(OCD))
DefinedNonLazyCategories.push_back(GCATV);
}
/// GetMethodConstant - Return a struct objc_method constant for the

View File

@ -0,0 +1,30 @@
// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
// RUN: clang-cc -triple x86_64-apple-darwin10 -emit-llvm -o %t %s &&
// RUN: grep '@".01L_OBJC_LABEL_NONLAZY_CLASS_$" = internal global \[1 x .*\] .*@"OBJC_CLASS_$_A".*, section "__DATA, __objc_nlclslist, regular, no_dead_strip", align 8' %t &&
// RUN: grep '@".01L_OBJC_LABEL_NONLAZY_CATEGORY_$" = internal global \[1 x .*\] .*@".01l_OBJC_$_CATEGORY_A_$_Cat".*, section "__DATA, __objc_nlcatlist, regular, no_dead_strip", align 8' %t &&
// RUN: true
@interface A @end
@implementation A
+(void) load {
}
@end
@interface A (Cat) @end
@implementation A (Cat)
+(void) load {
}
@end
@interface B @end
@implementation B
-(void) load {
}
@end
@interface B (Cat) @end
@implementation B (Cat)
-(void) load {
}
@end