More of objc2's ivar layout bitmap (Next: specific).

Work in progress.

llvm-svn: 66707
This commit is contained in:
Fariborz Jahanian 2009-03-11 20:59:05 +00:00
parent 4261e4c363
commit cbaf73cd26
1 changed files with 174 additions and 11 deletions

View File

@ -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<GC_IVAR, 8> SkipIvars;
llvm::SmallVector<GC_IVAR, 8> IvarsInfo;
// gc ivar layout bitmap calculation helper caches.
llvm::SmallVector<GC_IVAR, 16> SkipIvars;
llvm::SmallVector<GC_IVAR, 16> IvarsInfo;
llvm::SmallVector<SKIP_SCAN, 32> 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<FieldDecl*> 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) {