From: Fariborz Jahanian Date: Wed, 11 Mar 2009 20:59:05 +0000 (+0000) Subject: More of objc2's ivar layout bitmap (Next: specific). X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9397e1dd41cb52fb3f49e1872d48897dcfb14859;p=clang More of objc2's ivar layout bitmap (Next: specific). Work in progress. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66707 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 45e4b1286c..48ea99ef7d 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -307,6 +307,8 @@ public: }; class CGObjCCommonMac : public CodeGen::CGObjCRuntime { +public: + // FIXME - accessibility class GC_IVAR { public: unsigned int ivar_bytepos; @@ -314,13 +316,22 @@ class CGObjCCommonMac : public CodeGen::CGObjCRuntime { GC_IVAR() : ivar_bytepos(0), ivar_size(0) {} }; + class SKIP_SCAN { + public: + unsigned int skip; + unsigned int scan; + SKIP_SCAN() : skip(0), scan(0) {} + }; + protected: CodeGen::CodeGenModule &CGM; // FIXME! May not be needing this after all. unsigned ObjCABI; - llvm::SmallVector SkipIvars; - llvm::SmallVector IvarsInfo; + // gc ivar layout bitmap calculation helper caches. + llvm::SmallVector SkipIvars; + llvm::SmallVector IvarsInfo; + llvm::SmallVector SkipScanIvars; /// LazySymbols - Symbols to generate a lazy reference for. See /// DefinedSymbols and FinishModule(). @@ -410,7 +421,8 @@ protected: /// llvm::Constant *BuildIvarLayout(const llvm::StructLayout *Layout, ObjCImplementationDecl *OI, - bool ForStrongLayout); + bool ForStrongLayout, + const ObjCCommonTypesHelper &ObjCTypes); void BuildAggrIvarLayout(const llvm::StructLayout *Layout, const RecordDecl *RD, @@ -2624,6 +2636,19 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const llvm::StructLayout *Layout, return; } +static int +IvarBytePosCompare (const void *a, const void *b) +{ + unsigned int sa = ((CGObjCCommonMac::GC_IVAR *)a)->ivar_bytepos; + unsigned int sb = ((CGObjCCommonMac::GC_IVAR *)b)->ivar_bytepos; + + if (sa < sb) + return -1; + if (sa > sb) + return 1; + return 0; +} + /// BuildIvarLayout - Builds ivar layout bitmap for the class /// implementation for the __strong or __weak case. /// The layout map displays which words in ivar list must be skipped @@ -2641,21 +2666,159 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const llvm::StructLayout *Layout, /// - __weak anything /// llvm::Constant *CGObjCCommonMac::BuildIvarLayout( - const llvm::StructLayout *Layout, - ObjCImplementationDecl *OMD, - bool ForStrongLayout) { - int iIndex = -1; - int iSkIndex = -1; + const llvm::StructLayout *Layout, + ObjCImplementationDecl *OMD, + bool ForStrongLayout, + const ObjCCommonTypesHelper &ObjCTypes) { + int Index = -1; + int SkIndex = -1; bool hasUnion = false; + int SkipScan; + unsigned int WordsToScan, WordsToSkip; std::vector RecFields; ObjCInterfaceDecl *OI = OMD->getClassInterface(); CGM.getContext().CollectObjCIvars(OI, RecFields); if (RecFields.empty()) - return 0; + return llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); + BuildAggrIvarLayout (Layout, 0, RecFields, 0, ForStrongLayout, - iIndex, iSkIndex, hasUnion); - return 0; + Index, SkIndex, hasUnion); + if (Index == -1) + return llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); + + // Sort on byte position in case we encounterred a union nested in + // the ivar list. + if (hasUnion && Index > 0) + // FIXME - Is this correct? + qsort(&IvarsInfo[0], Index+1, sizeof(GC_IVAR), IvarBytePosCompare); + if (hasUnion && SkIndex > 0) + qsort(&SkipIvars[0], Index+1, sizeof(GC_IVAR), IvarBytePosCompare); + + // Build the string of skip/scan nibbles + SkipScan = -1; + unsigned int WordSize = + CGM.getTypes().getTargetData().getTypePaddedSize(ObjCTypes.Int8PtrTy); + if (IvarsInfo[0].ivar_bytepos == 0) { + WordsToSkip = 0; + WordsToScan = IvarsInfo[0].ivar_size; + } + else { + WordsToSkip = IvarsInfo[0].ivar_bytepos/WordSize; + WordsToScan = IvarsInfo[0].ivar_size; + } + for (int i=1; i <= Index; i++) + { + unsigned int TailPrevGCObjC = + IvarsInfo[i-1].ivar_bytepos + IvarsInfo[i-1].ivar_size * WordSize; + if (IvarsInfo[i].ivar_bytepos == TailPrevGCObjC) + { + // consecutive 'scanned' object pointers. + WordsToScan += IvarsInfo[i].ivar_size; + } + else + { + // Skip over 'gc'able object pointer which lay over each other. + if (TailPrevGCObjC > IvarsInfo[i].ivar_bytepos) + continue; + // Must skip over 1 or more words. We save current skip/scan values + // and start a new pair. + SkipScanIvars[++SkipScan].skip = WordsToSkip; + SkipScanIvars[SkipScan].scan = WordsToScan; + // Skip the hole. + SkipScanIvars[++SkipScan].skip = + (IvarsInfo[i].ivar_bytepos - TailPrevGCObjC) / WordSize; + SkipScanIvars[SkipScan].scan = 0; + WordsToSkip = 0; + WordsToScan = IvarsInfo[i].ivar_size; + } + } + if (WordsToScan > 0) + { + SkipScanIvars[++SkipScan].skip = WordsToSkip; + SkipScanIvars[SkipScan].scan = WordsToScan; + } + + bool BytesSkipped = false; + if (SkIndex >= 0) + { + int LastByteSkipped = + SkipIvars[SkIndex].ivar_bytepos + SkipIvars[SkIndex].ivar_size; + int LastByteScanned = + IvarsInfo[Index].ivar_bytepos + IvarsInfo[Index].ivar_size * WordSize; + BytesSkipped = (LastByteSkipped > LastByteScanned); + // Compute number of bytes to skip at the tail end of the last ivar scanned. + if (BytesSkipped) + { + unsigned int TotalWords = (LastByteSkipped + (WordSize -1)) / WordSize; + SkipScanIvars[++SkipScan].skip = TotalWords - (LastByteScanned/WordSize); + SkipScanIvars[SkipScan].scan = 0; + } + } + // Mini optimization of nibbles such that an 0xM0 followed by 0x0N is produced + // as 0xMN. + for (int i = 0; i <= SkipScan; i++) + { + if ((i < SkipScan) && SkipScanIvars[i].skip && SkipScanIvars[i].scan == 0 + && SkipScanIvars[i+1].skip == 0 && SkipScanIvars[i+1].scan) { + // 0xM0 followed by 0x0N detected. + SkipScanIvars[i].scan = SkipScanIvars[i+1].scan; + for (int j = i+1; j < SkipScan; j++) + SkipScanIvars[j] = SkipScanIvars[j+1]; + --SkipScan; + } + } + + // Generate the string. + std::string BitMap; + for (int i = 0; i <= SkipScan; i++) + { + unsigned char byte; + unsigned int skip_small = SkipScanIvars[i].skip % 0xf; + unsigned int scan_small = SkipScanIvars[i].scan % 0xf; + unsigned int skip_big = SkipScanIvars[i].skip / 0xf; + unsigned int scan_big = SkipScanIvars[i].scan / 0xf; + + if (skip_small > 0 || skip_big > 0) + BytesSkipped = true; + // first skip big. + for (unsigned int ix = 0; ix < skip_big; ix++) + BitMap += (unsigned char)(0xf0); + + // next (skip small, scan) + if (skip_small) + { + byte = skip_small << 4; + if (scan_big > 0) + { + byte |= 0xf; + --scan_big; + } + else if (scan_small) + { + byte |= scan_small; + scan_small = 0; + } + BitMap += byte; + } + // next scan big + for (unsigned int ix = 0; ix < scan_big; ix++) + BitMap += (unsigned char)(0x0f); + // last scan small + if (scan_small) + { + byte = scan_small; + BitMap += byte; + } + } + // null terminate string. + // BitMap += (unsigned char)0; + // if ivar_layout bitmap is all 1 bits (nothing skipped) then use NULL as + // final layout. + if (ForStrongLayout && !BytesSkipped) + return llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); + + return llvm::ConstantArray::get(BitMap); } llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) {