Bug 712865 - Avoid some padding nsCSSCompressedDataBlock by storing nsCSSValue and nsCSSProperty elements separately. r=dbaron.

--HG--
extra : rebase_source : 83dc6eff5e5500fa0dffc0e07d731941ee9e8122
This commit is contained in:
Nicholas Nethercote 2012-03-18 16:28:08 -07:00
Родитель a68813ed1b
Коммит dbc56b8bc5
2 изменённых файлов: 123 добавлений и 166 удалений

Просмотреть файл

@ -48,34 +48,6 @@
namespace css = mozilla::css;
enum {
CDBValueStorage_advance = sizeof(CDBValueStorage)
};
/*
* Define a bunch of utility functions for getting the property or any
* of the value types when the cursor is at the beginning of the storage
* for the property-value pair. The versions taking a non-const cursor
* argument return a reference so that the caller can assign into the
* result.
*/
inline nsCSSProperty& PropertyAtCursor(char *aCursor) {
return *reinterpret_cast<nsCSSProperty*>(aCursor);
}
inline nsCSSProperty PropertyAtCursor(const char *aCursor) {
return *reinterpret_cast<const nsCSSProperty*>(aCursor);
}
inline nsCSSValue* ValueAtCursor(char *aCursor) {
return & reinterpret_cast<CDBValueStorage*>(aCursor)->value;
}
inline const nsCSSValue* ValueAtCursor(const char *aCursor) {
return & reinterpret_cast<const CDBValueStorage*>(aCursor)->value;
}
/**
* Does a fast move of aSource to aDest. The previous value in
* aDest is cleanly destroyed, and aSource is cleared. Returns
@ -164,16 +136,13 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const
nsIDocument* doc = aRuleData->mPresContext->Document();
const char* cursor = Block();
const char* cursor_end = BlockEnd();
while (cursor < cursor_end) {
nsCSSProperty iProp = PropertyAtCursor(cursor);
NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range");
for (PRUint32 i = 0; i < mNumProps; i++) {
nsCSSProperty iProp = PropertyAtIndex(i);
if (nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]) &
aRuleData->mSIDs) {
nsCSSValue* target = aRuleData->ValueFor(iProp);
if (target->GetUnit() == eCSSUnit_Null) {
const nsCSSValue *val = ValueAtCursor(cursor);
const nsCSSValue *val = ValueAtIndex(i);
NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops");
if (ShouldStartImageLoads(aRuleData, iProp)) {
TryToStartImageLoad(*val, doc, iProp);
@ -197,9 +166,7 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const
}
}
}
cursor += CDBValueStorage_advance;
}
NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data");
}
const nsCSSValue*
@ -216,17 +183,11 @@ nsCSSCompressedDataBlock::ValueFor(nsCSSProperty aProperty) const
mStyleBits))
return nsnull;
const char* cursor = Block();
const char* cursor_end = BlockEnd();
while (cursor < cursor_end) {
nsCSSProperty iProp = PropertyAtCursor(cursor);
NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range");
if (iProp == aProperty) {
return ValueAtCursor(cursor);
for (PRUint32 i = 0; i < mNumProps; i++) {
if (PropertyAtIndex(i) == aProperty) {
return ValueAtIndex(i);
}
cursor += CDBValueStorage_advance;
}
NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data");
return nsnull;
}
@ -254,56 +215,35 @@ nsCSSCompressedDataBlock::TryReplaceValue(nsCSSProperty aProperty,
nsCSSCompressedDataBlock*
nsCSSCompressedDataBlock::Clone() const
{
const char *cursor = Block(), *cursor_end = BlockEnd();
char *result_cursor;
nsAutoPtr<nsCSSCompressedDataBlock>
result(new(mNumProps) nsCSSCompressedDataBlock(mNumProps));
nsAutoPtr<nsCSSCompressedDataBlock> result
(new(cursor_end - cursor) nsCSSCompressedDataBlock());
if (!result)
return nsnull;
result_cursor = result->Block();
while (cursor < cursor_end) {
nsCSSProperty iProp = PropertyAtCursor(cursor);
NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range");
PropertyAtCursor(result_cursor) = iProp;
const nsCSSValue* val = ValueAtCursor(cursor);
nsCSSValue *result_val = ValueAtCursor(result_cursor);
new (result_val) nsCSSValue(*val);
cursor += CDBValueStorage_advance;
result_cursor += CDBValueStorage_advance;
}
NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data");
result->SetBlockEnd(result_cursor);
result->mStyleBits = mStyleBits;
NS_ABORT_IF_FALSE(result->DataSize() == DataSize(), "wrong size");
for (PRUint32 i = 0; i < mNumProps; i++) {
result->SetPropertyAtIndex(i, PropertyAtIndex(i));
result->CopyValueToIndex(i, ValueAtIndex(i));
}
return result.forget();
}
nsCSSCompressedDataBlock::~nsCSSCompressedDataBlock()
{
const char* cursor = Block();
const char* cursor_end = BlockEnd();
while (cursor < cursor_end) {
NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(PropertyAtCursor(cursor)),
"out of range");
const nsCSSValue* val = ValueAtCursor(cursor);
for (PRUint32 i = 0; i < mNumProps; i++) {
#ifdef DEBUG
(void)PropertyAtIndex(i); // this checks the property is in range
#endif
const nsCSSValue* val = ValueAtIndex(i);
NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops");
val->~nsCSSValue();
cursor += CDBValueStorage_advance;
}
NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data");
}
/* static */ nsCSSCompressedDataBlock*
nsCSSCompressedDataBlock::CreateEmptyBlock()
{
nsCSSCompressedDataBlock *result = new(0) nsCSSCompressedDataBlock();
result->SetBlockEnd(result->Block());
nsCSSCompressedDataBlock *result = new(0) nsCSSCompressedDataBlock(0);
return result;
}
@ -311,12 +251,8 @@ size_t
nsCSSCompressedDataBlock::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
{
size_t n = aMallocSizeOf(this);
const char* cursor = Block();
const char* cursor_end = BlockEnd();
while (cursor < cursor_end) {
n += ValueAtCursor(cursor)->SizeOfExcludingThis(aMallocSizeOf);
cursor += CDBValueStorage_advance;
for (PRUint32 i = 0; i < mNumProps; i++) {
n += ValueAtIndex(i)->SizeOfExcludingThis(aMallocSizeOf);
}
return n;
}
@ -341,10 +277,8 @@ nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock,
* Save needless copying and allocation by copying the memory
* corresponding to the stored data in the compressed block.
*/
const char* cursor = aBlock->Block();
const char* cursor_end = aBlock->BlockEnd();
while (cursor < cursor_end) {
nsCSSProperty iProp = PropertyAtCursor(cursor);
for (PRUint32 i = 0; i < aBlock->mNumProps; i++) {
nsCSSProperty iProp = aBlock->PropertyAtIndex(i);
NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range");
NS_ABORT_IF_FALSE(!HasPropertyBit(iProp),
"compressed block has property multiple times");
@ -352,7 +286,7 @@ nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock,
if (aImportant)
SetImportantBit(iProp);
const nsCSSValue* val = ValueAtCursor(cursor);
const nsCSSValue* val = aBlock->ValueAtIndex(i);
nsCSSValue* dest = PropertyAt(iProp);
NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null, "oops");
NS_ABORT_IF_FALSE(dest->GetUnit() == eCSSUnit_Null,
@ -361,12 +295,11 @@ nsCSSExpandedDataBlock::DoExpand(nsCSSCompressedDataBlock *aBlock,
dest->~nsCSSValue();
#endif
memcpy(dest, val, sizeof(nsCSSValue));
cursor += CDBValueStorage_advance;
}
NS_ABORT_IF_FALSE(cursor == cursor_end, "inconsistent data");
// Don't destroy remnants of what we just copied
aBlock->SetBlockEnd(aBlock->Block());
// Set the number of properties to zero so that we don't destroy the
// remnants of what we just copied.
aBlock->SetNumPropsToZero();
delete aBlock;
}
@ -383,10 +316,11 @@ nsCSSExpandedDataBlock::Expand(nsCSSCompressedDataBlock *aNormalBlock,
}
}
nsCSSExpandedDataBlock::ComputeSizeResult
nsCSSExpandedDataBlock::ComputeSize()
void
nsCSSExpandedDataBlock::ComputeNumProps(PRUint32* aNumPropsNormal,
PRUint32* aNumPropsImportant)
{
ComputeSizeResult result = {0, 0};
*aNumPropsNormal = *aNumPropsImportant = 0;
for (size_t iHigh = 0; iHigh < nsCSSPropertySet::kChunkCount; ++iHigh) {
if (!mPropertiesSet.HasPropertyInChunk(iHigh))
continue;
@ -400,12 +334,11 @@ nsCSSExpandedDataBlock::ComputeSize()
NS_ABORT_IF_FALSE(PropertyAt(iProp)->GetUnit() != eCSSUnit_Null,
"null value while computing size");
if (mPropertiesImportant.HasPropertyAt(iHigh, iLow))
result.important += CDBValueStorage_advance;
(*aNumPropsImportant)++;
else
result.normal += CDBValueStorage_advance;
(*aNumPropsNormal)++;
}
}
return result;
}
void
@ -413,19 +346,19 @@ nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock,
nsCSSCompressedDataBlock **aImportantBlock)
{
nsAutoPtr<nsCSSCompressedDataBlock> result_normal, result_important;
char *cursor_normal, *cursor_important;
PRUint32 i_normal = 0, i_important = 0;
ComputeSizeResult size = ComputeSize();
PRUint32 numPropsNormal, numPropsImportant;
ComputeNumProps(&numPropsNormal, &numPropsImportant);
result_normal = new(size.normal) nsCSSCompressedDataBlock();
cursor_normal = result_normal->Block();
result_normal =
new(numPropsNormal) nsCSSCompressedDataBlock(numPropsNormal);
if (size.important != 0) {
result_important = new(size.important) nsCSSCompressedDataBlock();
cursor_important = result_important->Block();
if (numPropsImportant != 0) {
result_important =
new(numPropsImportant) nsCSSCompressedDataBlock(numPropsImportant);
} else {
result_important = nsnull;
cursor_important = nsnull;
}
/*
@ -443,32 +376,25 @@ nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock,
NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range");
bool important =
mPropertiesImportant.HasPropertyAt(iHigh, iLow);
char *&cursor = important ? cursor_important : cursor_normal;
nsCSSCompressedDataBlock *result =
important ? result_important : result_normal;
PRUint32* ip = important ? &i_important : &i_normal;
nsCSSValue* val = PropertyAt(iProp);
NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null,
"Null value while compressing");
CDBValueStorage *storage =
reinterpret_cast<CDBValueStorage*>(cursor);
storage->property = iProp;
memcpy(&storage->value, val, sizeof(nsCSSValue));
result->SetPropertyAtIndex(*ip, iProp);
result->RawCopyValueToIndex(*ip, val);
new (val) nsCSSValue();
cursor += CDBValueStorage_advance;
(*ip)++;
result->mStyleBits |=
nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]);
}
}
result_normal->SetBlockEnd(cursor_normal);
NS_ABORT_IF_FALSE(result_normal->DataSize() == ptrdiff_t(size.normal),
"size miscalculation");
NS_ABORT_IF_FALSE(numPropsNormal == i_normal, "bad numProps");
if (result_important) {
result_important->SetBlockEnd(cursor_important);
NS_ABORT_IF_FALSE(result_important->DataSize() ==
ptrdiff_t(size.important),
"size miscalculation");
NS_ABORT_IF_FALSE(numPropsImportant == i_important, "bad numProps");
}
ClearSets();

Просмотреть файл

@ -55,16 +55,6 @@ class Declaration;
}
}
/*
* nsCSSCompressedDataBlock holds property-value pairs corresponding
* to CSS declaration blocks. Each pair is stored in a CDBValueStorage
* object; these objects form an array at the end of the data block.
*/
struct CDBValueStorage {
nsCSSProperty property;
nsCSSValue value;
};
/**
* An |nsCSSCompressedDataBlock| holds a usually-immutable chunk of
* property-value data for a CSS declaration block (which we misname a
@ -77,7 +67,9 @@ private:
// Only this class (via |CreateEmptyBlock|) or nsCSSExpandedDataBlock
// (in |Compress|) can create compressed data blocks.
nsCSSCompressedDataBlock() : mStyleBits(0) {}
nsCSSCompressedDataBlock(PRUint32 aNumProps)
: mStyleBits(0), mNumProps(aNumProps)
{}
public:
~nsCSSCompressedDataBlock();
@ -124,47 +116,88 @@ public:
size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
private:
void* operator new(size_t aBaseSize, size_t aDataSize) {
void* operator new(size_t aBaseSize, PRUint32 aNumProps) {
NS_ABORT_IF_FALSE(aBaseSize == sizeof(nsCSSCompressedDataBlock),
"unexpected size for nsCSSCompressedDataBlock");
return ::operator new(aBaseSize + aDataSize);
return ::operator new(aBaseSize + DataSize(aNumProps));
}
/**
* Delete all the data stored in this block, and the block itself.
*/
void Destroy();
public:
// Ideally, |nsCSSProperty| would be |enum nsCSSProperty : PRInt16|. But
// not all of the compilers we use are modern enough to support small
// enums. So we manually squeeze nsCSSProperty into 16 bits ourselves.
// The static assertion below ensures it fits.
typedef PRInt16 CompressedCSSProperty;
static const size_t MaxCompressedCSSProperty = PR_INT16_MAX;
private:
static size_t DataSize(PRUint32 aNumProps) {
return size_t(aNumProps) *
(sizeof(nsCSSValue) + sizeof(CompressedCSSProperty));
}
PRInt32 mStyleBits; // the structs for which we have data, according to
// |nsCachedStyleData::GetBitForSID|.
PRUint32 mDataSize;
// CDBValueStorage elements are stored after these fields. Space for them
PRUint32 mNumProps;
// nsCSSValue elements are stored after these fields, and
// nsCSSProperty elements are stored -- each one compressed as a
// CompressedCSSProperty -- after the nsCSSValue elements. Space for them
// is allocated in |operator new| above. The static assertions following
// this class make sure that the CDBValueStorage elements are aligned
// this class make sure that the value and property elements are aligned
// appropriately.
char* Block() { return (char*)this + sizeof(*this); }
char* BlockEnd() { return Block() + mDataSize; }
const char* Block() const { return (char*)this + sizeof(*this); }
const char* BlockEnd() const { return Block() + mDataSize; }
void SetBlockEnd(char *blockEnd) {
/*
* Note: if we ever change nsCSSDeclaration to store the declarations
* in order and also store repeated declarations of the same property,
* then we need to worry about checking for integer overflow here.
*/
NS_ABORT_IF_FALSE(size_t(blockEnd - Block()) <= size_t(PR_UINT32_MAX),
"overflow of mDataSize");
mDataSize = PRUint32(blockEnd - Block());
nsCSSValue* Values() const {
return (nsCSSValue*)(this + 1);
}
CompressedCSSProperty* CompressedProperties() const {
return (CompressedCSSProperty*)(Values() + mNumProps);
}
nsCSSValue* ValueAtIndex(PRUint32 i) const {
NS_ABORT_IF_FALSE(i < mNumProps, "value index out of range");
return Values() + i;
}
nsCSSProperty PropertyAtIndex(PRUint32 i) const {
NS_ABORT_IF_FALSE(i < mNumProps, "property index out of range");
nsCSSProperty prop = (nsCSSProperty)CompressedProperties()[i];
NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(prop), "out of range");
return prop;
}
void CopyValueToIndex(PRUint32 i, nsCSSValue* aValue) {
new (ValueAtIndex(i)) nsCSSValue(*aValue);
}
void RawCopyValueToIndex(PRUint32 i, nsCSSValue* aValue) {
memcpy(ValueAtIndex(i), aValue, sizeof(nsCSSValue));
}
void SetPropertyAtIndex(PRUint32 i, nsCSSProperty aProperty) {
NS_ABORT_IF_FALSE(i < mNumProps, "set property index out of range");
CompressedProperties()[i] = (CompressedCSSProperty)aProperty;
}
void SetNumPropsToZero() {
mNumProps = 0;
}
ptrdiff_t DataSize() const { return mDataSize; }
};
/* Make sure the CDBValueStorage elements are aligned appropriately. */
// Make sure the values and properties are aligned appropriately. (These
// assertions are stronger than necessary to keep them simple.)
MOZ_STATIC_ASSERT(sizeof(nsCSSCompressedDataBlock) == 8,
"nsCSSCompressedDataBlock's size has changed");
MOZ_STATIC_ASSERT(NS_ALIGNMENT_OF(CDBValueStorage) <= 8,
"CDBValueStorage needs too much alignment");
MOZ_STATIC_ASSERT(NS_ALIGNMENT_OF(nsCSSValue) == 4 ||
NS_ALIGNMENT_OF(nsCSSValue) == 8,
"nsCSSValue doesn't align with nsCSSCompressedDataBlock");
MOZ_STATIC_ASSERT(NS_ALIGNMENT_OF(nsCSSCompressedDataBlock::CompressedCSSProperty) == 2,
"CompressedCSSProperty doesn't align with nsCSSValue");
// Make sure that sizeof(CompressedCSSProperty) is big enough.
MOZ_STATIC_ASSERT(eCSSProperty_COUNT_no_shorthands <=
nsCSSCompressedDataBlock::MaxCompressedCSSProperty,
"nsCSSProperty doesn't fit in StoredSizeOfCSSProperty");
class nsCSSExpandedDataBlock {
friend class nsCSSCompressedDataBlock;
@ -251,14 +284,12 @@ public:
private:
/**
* Compute the size that will be occupied by the result of
* |Compress|.
* Compute the number of properties that will be present in the
* result of |Compress|.
*/
struct ComputeSizeResult {
PRUint32 normal, important;
};
ComputeSizeResult ComputeSize();
void ComputeNumProps(PRUint32* aNumPropsNormal,
PRUint32* aNumPropsImportant);
void DoExpand(nsCSSCompressedDataBlock *aBlock, bool aImportant);
/**