From: Daniel Dunbar Date: Fri, 22 Aug 2008 20:34:54 +0000 (+0000) Subject: NeXT: Emit category metadata. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=86e253a0cb438b118eb598abb0225d431c8798d2;p=clang NeXT: Emit category metadata. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55197 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 51558f86fa..14d9bc42b0 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -88,6 +88,8 @@ public: const llvm::Type *ProtocolListTy; /// ProtocolListPtrTy - LLVM type for struct objc_property_list*. const llvm::Type *ProtocolListPtrTy; + /// CategoryTy - LLVM type for struct objc_category. + const llvm::StructType *CategoryTy; /// ClassTy - LLVM type for struct objc_class. const llvm::StructType *ClassTy; /// ClassPtrTy - LLVM type for struct objc_class *. @@ -205,8 +207,10 @@ private: /// implementation. If ForClass is true the list of class methods /// will be emitted, otherwise the list of instance methods will be /// generated.The return value has type MethodListPtrTy. - llvm::Constant *EmitMethodList(const ObjCImplementationDecl *ID, - bool ForClass); + llvm::Constant *EmitMethodList(const std::string &Name, + const char *Section, + llvm::SmallVector::const_iterator begin, + llvm::SmallVector::const_iterator end); /// EmitMethodDescList - Emit a method description list for a list of /// method declarations. @@ -679,8 +683,54 @@ llvm::Constant *CGObjCMac::EmitMethodDescList(const std::string &TypeName, ObjCTypes.MethodDescriptionListPtrTy); } +/* + struct _objc_category { + char *category_name; + char *class_name; + struct _objc_method_list *instance_methods; + struct _objc_method_list *class_methods; + struct _objc_protocol_list *protocols; + uint32_t size; // + struct _objc_property_list *instance_properties; + }; + */ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { - assert(0 && "Cannot generate category for Mac runtime."); + unsigned Size = CGM.getTargetData().getABITypeSize(ObjCTypes.CategoryTy); + + const ObjCInterfaceDecl *Interface = OCD->getClassInterface(); + std::string ExtName(std::string(Interface->getName()) + + "_" + + OCD->getName()); + + std::vector Values(7); + Values[0] = GetClassName(OCD->getIdentifier()); + Values[1] = GetClassName(Interface->getIdentifier()); + Values[2] = EmitMethodList(std::string("\01L_OBJC_CATEGORY_INSTANCE_METHODS_") + ExtName, + "__OBJC,__cat_inst_meth,regular,no_dead_strip", + OCD->instmeth_begin(), + OCD->instmeth_end()); + Values[3] = EmitMethodList(std::string("\01L_OBJC_CATEGORY_CLASS_METHODS_") + ExtName, + "__OBJC,__cat_class_meth,regular,no_dead_strip", + OCD->classmeth_begin(), + OCD->classmeth_end()); + Values[4] = EmitProtocolList(std::string("\01L_OBJC_CATEGORY_PROTOCOLS_") + ExtName, + Interface->protocol_begin(), + Interface->protocol_end()); + Values[5] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); + Values[6] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); + + llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.CategoryTy, + Values); + + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(ObjCTypes.CategoryTy, false, + llvm::GlobalValue::InternalLinkage, + Init, + std::string("\01L_OBJC_CATEGORY_")+ExtName, + &CGM.getModule()); + GV->setSection("__OBJC,__category,regular,no_dead_strip"); + UsedGlobals.push_back(GV); + DefinedCategories.push_back(GV); } // FIXME: Get from somewhere? @@ -765,11 +815,15 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags); Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size); Values[ 6] = EmitIvarList(ID, false, InterfaceTy); - Values[ 7] = EmitMethodList(ID, false); + Values[ 7] = EmitMethodList(std::string("\01L_OBJC_INSTANCE_METHODS_") + ID->getName(), + "__OBJC,__inst_meth,regular,no_dead_strip", + ID->instmeth_begin(), + ID->instmeth_end()); // cache is always NULL. Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy); Values[ 9] = Protocols; - Values[10] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); // XXX + // FIXME: Set ivar_layout + Values[10] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); Values[11] = EmitClassExtension(ID); llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy, Values); @@ -805,7 +859,9 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID, Values[ 0] = llvm::ConstantExpr::getBitCast(GetClassName(Root->getIdentifier()), ObjCTypes.ClassPtrTy); - // FIXME: Document fix-up here. + // The super class for the metaclass is emitted as the name of the + // super class. The runtime fixes this up to point to the + // *metaclass* for the super class. if (ObjCInterfaceDecl *Super = ID->getClassInterface()->getSuperClass()) { Values[ 1] = llvm::ConstantExpr::getBitCast(GetClassName(Super->getIdentifier()), @@ -819,7 +875,10 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID, Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags); Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size); Values[ 6] = EmitIvarList(ID, true, InterfaceTy); - Values[ 7] = EmitMethodList(ID, true); + Values[ 7] = EmitMethodList(std::string("\01L_OBJC_CLASS_METHODS_") + ID->getName(), + "__OBJC,__inst_meth,regular,no_dead_strip", + ID->classmeth_begin(), + ID->classmeth_end()); // cache is always NULL. Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy); Values[ 9] = Protocols; @@ -858,7 +917,7 @@ CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) { std::vector Values(3); Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); - // FIXME: Output weak_ivar string. + // FIXME: Output weak_ivar_layout string. Values[1] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); // FIXME: Output properties. Values[2] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); @@ -972,15 +1031,14 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, struct objc_method methods_list[count]; }; */ -llvm::Constant *CGObjCMac::EmitMethodList(const ObjCImplementationDecl *ID, - bool ForClass) { +llvm::Constant *CGObjCMac::EmitMethodList(const std::string &Name, + const char *Section, + llvm::SmallVector::const_iterator begin, + llvm::SmallVector::const_iterator end) { std::vector Methods, Method(3); - llvm::SmallVector::const_iterator - i = ForClass ? ID->classmeth_begin() : ID->instmeth_begin(), - e = ForClass ? ID->classmeth_end() : ID->instmeth_end(); - for (; i != e; ++i) { - ObjCMethodDecl *MD = *i; + for (; begin != end; ++begin) { + ObjCMethodDecl *MD = *begin; Method[0] = llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()), @@ -1009,19 +1067,13 @@ llvm::Constant *CGObjCMac::EmitMethodList(const ObjCImplementationDecl *ID, Values[2] = llvm::ConstantArray::get(AT, Methods); llvm::Constant *Init = llvm::ConstantStruct::get(Values); - const char *Prefix = (ForClass ? "\01L_OBJC_CLASS_METHODS_" : - "\01L_OBJC_INSTANCE_METHODS_"); llvm::GlobalVariable *GV = new llvm::GlobalVariable(Init->getType(), false, llvm::GlobalValue::InternalLinkage, Init, - std::string(Prefix) + ID->getName(), + Name, &CGM.getModule()); - if (ForClass) { - GV->setSection("__OBJC,__cls_meth,regular,no_dead_strip"); - } else { - GV->setSection("__OBJC,__inst_meth,regular,no_dead_strip"); - } + GV->setSection(Section); UsedGlobals.push_back(GV); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListPtrTy); @@ -1174,14 +1226,19 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() { Values[2] = llvm::ConstantInt::get(ObjCTypes.ShortTy, NumClasses); Values[3] = llvm::ConstantInt::get(ObjCTypes.ShortTy, NumCategories); - // FIXME: Is this correct? Document. + // The runtime expects exactly the list of defined classes followed + // by the list of defined categories, in a single array. std::vector Symbols(NumClasses + NumCategories); - std::copy(DefinedClasses.begin(), DefinedClasses.end(), - Symbols.begin()); - std::copy(DefinedCategories.begin(), DefinedCategories.end(), - Symbols.begin() + NumClasses); + for (unsigned i=0; i