diff options
author | David Chisnall <csdavec@swan.ac.uk> | 2011-10-04 15:35:30 +0000 |
---|---|---|
committer | David Chisnall <csdavec@swan.ac.uk> | 2011-10-04 15:35:30 +0000 |
commit | 917b28b980a8300ce9c7c8d71b2a77bb93b7cdd2 (patch) | |
tree | 61ded58b81316c173d2a51e82352c70bbf76884c /lib/CodeGen/CGObjCGNU.cpp | |
parent | f347667044100b8a91076480a8e73a2abb418b05 (diff) |
Add bitmaps for strong / weak ivar layout (GNUstep runtime).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141085 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGObjCGNU.cpp')
-rw-r--r-- | lib/CodeGen/CGObjCGNU.cpp | 120 |
1 files changed, 102 insertions, 18 deletions
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 6bdc519a26..a95e8e6097 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/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<llvm::Constant*> &V, + llvm::ArrayRef<llvm::Constant*> 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<llvm::Constant*> &V, + llvm::ArrayRef<llvm::Constant*> 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<llvm::Constant*> &V, + llvm::ArrayRef<llvm::Constant*> 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<bool> &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<bool> &bits) { + int bitCount = bits.size(); + if (bitCount < 64) { + uint64_t val = 1; + for (int i=0 ; i<bitCount ; ++i) { + if (bits[i]) val |= 1<<(i+1); + } + return llvm::ConstantInt::get(Int64Ty, val); + } + llvm::SmallVector<llvm::Constant*, 8> values; + int v=0; + while (v < bitCount) { + int32_t word = 0; + for (int i=0 ; (i<32) && (v<bitCount) ; ++i) { + if (bits[v]) word |= 1<<i; + v++; + } + values.push_back(llvm::ConstantInt::get(Int32Ty, word)); + } + llvm::ArrayType *arrayTy = llvm::ArrayType::get(Int32Ty, values.size()); + llvm::Constant *array = llvm::ConstantArray::get(arrayTy, values); + llvm::Constant *fields[2] = { + llvm::ConstantInt::get(Int32Ty, values.size()), + array }; + llvm::Constant *GS = MakeGlobal(llvm::StructType::get(Int32Ty, arrayTy, + NULL), fields); + return llvm::ConstantExpr::getPtrToInt(GS, Int64Ty); +} + void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) { std::string ClassName = OCD->getClassInterface()->getNameAsString(); std::string CategoryName = OCD->getNameAsString(); @@ -1845,6 +1909,8 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { SmallVector<llvm::Constant*, 16> IvarOffsets; std::vector<llvm::Constant*> IvarOffsetValues; + SmallVector<bool, 16> WeakIvars; + SmallVector<bool, 16> 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 ; i<SelectorCount ; i++) { llvm::Constant *Idxs[] = {Zeros[0], - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), i), Zeros[0]}; + llvm::ConstantInt::get(Int32Ty, i), Zeros[0]}; // FIXME: We're generating redundant loads and stores here! llvm::Constant *SelPtr = llvm::ConstantExpr::getGetElementPtr(SelectorList, makeArrayRef(Idxs, 2)); @@ -2396,7 +2480,7 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable( // GCC-compiled class. if (CGM.getLangOptions().PICLevel) { llvm::GlobalVariable *IvarOffsetGV = new llvm::GlobalVariable(TheModule, - llvm::Type::getInt32Ty(VMContext), false, + Int32Ty, false, llvm::GlobalValue::PrivateLinkage, OffsetGuess, Name+".guess"); IvarOffsetPointer = new llvm::GlobalVariable(TheModule, IvarOffsetGV->getType(), false, llvm::GlobalValue::LinkOnceAnyLinkage, |