From cdd207e43e364ced7eec68484ce467e2cf3c9869 Mon Sep 17 00:00:00 2001 From: David Chisnall Date: Tue, 4 Oct 2011 15:35:30 +0000 Subject: [PATCH] Add bitmaps for strong / weak ivar layout (GNUstep runtime). llvm-svn: 141085 --- clang/lib/CodeGen/CGObjCGNU.cpp | 120 +++++++++++++++++++++++++++----- 1 file changed, 102 insertions(+), 18 deletions(-) diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index 6bdc519a2606..a95e8e609708 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -160,6 +160,10 @@ protected: llvm::PointerType *PtrToIntTy; /// LLVM type for Objective-C BOOL type. llvm::Type *BoolTy; + /// 32-bit integer type, to save us needing to look it up every time it's used. + llvm::IntegerType *Int32Ty; + /// 64-bit integer type, to save us needing to look it up every time it's used. + llvm::IntegerType *Int64Ty; /// Metadata kind used to tie method lookups to message sends. The GNUstep /// runtime provides some LLVM passes that can use this to do things like /// automatic IMP caching and speculative inlining. @@ -191,7 +195,7 @@ protected: /// The element types must match the types of the structure elements in the /// first argument. llvm::GlobalVariable *MakeGlobal(llvm::StructType *Ty, - std::vector &V, + llvm::ArrayRef V, StringRef Name="", llvm::GlobalValue::LinkageTypes linkage =llvm::GlobalValue::InternalLinkage) { @@ -203,7 +207,7 @@ protected: /// elements that the array type declares, of the type specified as the array /// element type. llvm::GlobalVariable *MakeGlobal(llvm::ArrayType *Ty, - std::vector &V, + llvm::ArrayRef V, StringRef Name="", llvm::GlobalValue::LinkageTypes linkage =llvm::GlobalValue::InternalLinkage) { @@ -214,7 +218,7 @@ protected: /// Generates a global array, inferring the array type from the specified /// element type and the size of the initialiser. llvm::GlobalVariable *MakeGlobalArray(llvm::Type *Ty, - std::vector &V, + llvm::ArrayRef V, StringRef Name="", llvm::GlobalValue::LinkageTypes linkage =llvm::GlobalValue::InternalLinkage) { @@ -375,6 +379,8 @@ private: llvm::Constant *Protocols, llvm::Constant *IvarOffsets, llvm::Constant *Properties, + llvm::Constant *StrongIvarBitmap, + llvm::Constant *WeakIvarBitmap, bool isMeta=false); /// Generates a method list. This is used by protocols to define the required /// and optional methods. @@ -402,12 +408,24 @@ protected: llvm::Value *&Receiver, llvm::Value *cmd, llvm::MDNode *node) = 0; - /// Looks up the method for sending a message to a superclass. This mechanism - /// differs between the GCC and GNU runtimes, so this method must be - /// overridden in subclasses. + /// Looks up the method for sending a message to a superclass. This + /// mechanism differs between the GCC and GNU runtimes, so this method must + /// be overridden in subclasses. virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, llvm::Value *ObjCSuper, llvm::Value *cmd) = 0; + /// Libobjc2 uses a bitfield representation where small(ish) bitfields are + /// stored in a 64-bit value with the low bit set to 1 and the remaining 63 + /// bits set to their values, LSB first, while larger ones are stored in a + /// structure of this / form: + /// + /// struct { int32_t length; int32_t values[length]; }; + /// + /// The values in the array are stored in host-endian format, with the least + /// significant bit being assumed to come first in the bitfield. Therefore, + /// a bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] }, + /// while a bitfield / with the 63rd bit set will be 1<<64. + llvm::Constant *MakeBitField(llvm::SmallVectorImpl &bits); public: CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, unsigned protocolClassVersion); @@ -696,6 +714,9 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, PtrToIntTy = llvm::PointerType::getUnqual(IntTy); PtrTy = PtrToInt8Ty; + Int32Ty = llvm::Type::getInt32Ty(VMContext); + Int64Ty = llvm::Type::getInt64Ty(VMContext); + // Object type QualType UnqualIdTy = CGM.getContext().getObjCIdType(); ASTIdTy = CanQualType(); @@ -1246,8 +1267,7 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const StringRef &ClassName, Methods.clear(); Methods.push_back(llvm::ConstantPointerNull::get( llvm::PointerType::getUnqual(ObjCMethodListTy))); - Methods.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - MethodTypes.size())); + Methods.push_back(llvm::ConstantInt::get(Int32Ty, MethodTypes.size())); Methods.push_back(MethodArray); // Create an instance of the structure @@ -1307,6 +1327,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( llvm::Constant *Protocols, llvm::Constant *IvarOffsets, llvm::Constant *Properties, + llvm::Constant *StrongIvarBitmap, + llvm::Constant *WeakIvarBitmap, bool isMeta) { // Set up the class structure // Note: Several of these are char*s when they should be ids. This is @@ -1334,6 +1356,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( LongTy, // abi_version IvarOffsets->getType(), // ivar_offsets Properties->getType(), // properties + Int64Ty, // strong_pointers + Int64Ty, // weak_pointers NULL); llvm::Constant *Zero = llvm::ConstantInt::get(LongTy, 0); // Fill in the structure @@ -1358,9 +1382,11 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( Elements.push_back(NULLPtr); Elements.push_back(llvm::ConstantExpr::getBitCast(Protocols, PtrTy)); Elements.push_back(NULLPtr); - Elements.push_back(Zero); + Elements.push_back(llvm::ConstantInt::get(LongTy, 1)); Elements.push_back(IvarOffsets); Elements.push_back(Properties); + Elements.push_back(StrongIvarBitmap); + Elements.push_back(WeakIvarBitmap); // Create an instance of the structure // This is now an externally visible symbol, so that we can speed up class // messages in the next ABI. @@ -1460,8 +1486,7 @@ llvm::Constant *CGObjCGNU::GenerateEmptyProtocol( // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. Elements.push_back(llvm::ConstantExpr::getIntToPtr( - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - ProtocolVersion), IdTy)); + llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy)); Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name")); Elements.push_back(ProtocolList); Elements.push_back(MethodList); @@ -1621,8 +1646,7 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. Elements.push_back(llvm::ConstantExpr::getIntToPtr( - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - ProtocolVersion), IdTy)); + llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy)); Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name")); Elements.push_back(ProtocolList); Elements.push_back(InstanceMethodList); @@ -1681,6 +1705,46 @@ void CGObjCGNU::GenerateProtocolHolderCategory(void) { PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy)); } +/// Libobjc2 uses a bitfield representation where small(ish) bitfields are +/// stored in a 64-bit value with the low bit set to 1 and the remaining 63 +/// bits set to their values, LSB first, while larger ones are stored in a +/// structure of this / form: +/// +/// struct { int32_t length; int32_t values[length]; }; +/// +/// The values in the array are stored in host-endian format, with the least +/// significant bit being assumed to come first in the bitfield. Therefore, a +/// bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] }, while a +/// bitfield / with the 63rd bit set will be 1<<64. +llvm::Constant *CGObjCGNU::MakeBitField(llvm::SmallVectorImpl &bits) { + int bitCount = bits.size(); + if (bitCount < 64) { + uint64_t val = 1; + for (int i=0 ; i values; + int v=0; + while (v < bitCount) { + int32_t word = 0; + for (int i=0 ; (i<32) && (vgetClassInterface()->getNameAsString(); std::string CategoryName = OCD->getNameAsString(); @@ -1845,6 +1909,8 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { SmallVector IvarOffsets; std::vector IvarOffsetValues; + SmallVector WeakIvars; + SmallVector StrongIvars; int superInstanceSize = !SuperClassDecl ? 0 : Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity(); @@ -1887,7 +1953,23 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { IVD->getNameAsString()); IvarOffsets.push_back(OffsetValue); IvarOffsetValues.push_back(OffsetVar); + Qualifiers::ObjCLifetime lt = IVD->getType().getQualifiers().getObjCLifetime(); + switch (lt) { + case Qualifiers::OCL_Strong: + StrongIvars.push_back(true); + WeakIvars.push_back(false); + break; + case Qualifiers::OCL_Weak: + StrongIvars.push_back(false); + WeakIvars.push_back(true); + break; + default: + StrongIvars.push_back(false); + WeakIvars.push_back(false); + } } + llvm::Constant *StrongIvarBitmap = MakeBitField(StrongIvars); + llvm::Constant *WeakIvarBitmap = MakeBitField(WeakIvars); llvm::GlobalVariable *IvarOffsetArray = MakeGlobalArray(PtrToIntTy, IvarOffsetValues, ".ivar.offsets"); @@ -1954,7 +2036,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { // setting up the alias. These are: The base address for the global, the // ivar array (second field), the ivar in this list (set for each ivar), and // the offset (third field in ivar structure) - llvm::Type *IndexTy = llvm::Type::getInt32Ty(VMContext); + llvm::Type *IndexTy = Int32Ty; llvm::Constant *offsetPointerIndexes[] = {Zeros[0], llvm::ConstantInt::get(IndexTy, 1), 0, llvm::ConstantInt::get(IndexTy, 2) }; @@ -1983,10 +2065,12 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { } ++ivarIndex; } + llvm::Constant *Zero64 = llvm::ConstantInt::get(Int64Ty, 0); //Generate metaclass for class methods llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr, NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList( - empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr, true); + empty, empty, empty), ClassMethodList, NULLPtr, + NULLPtr, NULLPtr, Zero64, Zero64, true); // Generate the class structure llvm::Constant *ClassStruct = @@ -1994,7 +2078,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { ClassName.c_str(), 0, llvm::ConstantInt::get(LongTy, instanceSize), IvarList, MethodList, GenerateProtocolList(Protocols), IvarOffsetArray, - Properties); + Properties, StrongIvarBitmap, WeakIvarBitmap); // Resolve the class aliases, if they exist. if (ClassPtrAlias) { @@ -2118,7 +2202,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { for (unsigned int i=0 ; igetType(), false, llvm::GlobalValue::LinkOnceAnyLinkage,