HphpArray compact layout

ArrayData gets on a diet, down to 32 bytes
devirtualized destructor call in HphpArray::release()
aggressively inlined constructors for ArrayData (do away with defaulted arguments)
eliminate a dead memset() for the hashtable in HphpArray(uint size, const TypedValue* values)
Esse commit está contido em:
Andrei Alexandrescu
2013-05-23 16:05:41 -07:00
commit de Sara Golemon
commit 6d365df98f
8 arquivos alterados com 106 adições e 60 exclusões
+52 -35
Ver Arquivo
@@ -66,7 +66,13 @@ static const Trace::Module TRACEMOD = Trace::runtime;
* separately. Even larger tables allocate the hashtable and slots
* contiguously.
*/
IMPLEMENT_SMART_ALLOCATION(HphpArray);
void *HphpArray::SmaAllocatorInitSetup = SmartAllocatorInitSetup<HphpArray>();
void HphpArray::release() {
assert(typeid(*this) == typeid(HphpArray));
this->HphpArray::~HphpArray();
HphpArray::AllocatorType::getNoCheck()->dealloc(this);
}
//=============================================================================
// Static members.
@@ -76,12 +82,12 @@ HphpArray HphpArray::s_theEmptyArray(StaticEmptyArray);
//=============================================================================
// Helpers.
static inline size_t computeMaskFromNumElms(uint32_t numElms) {
assert(numElms <= 0x7fffffffU);
static inline size_t computeMaskFromNumElms(const uint32_t n) {
assert(n <= 0x7fffffffU);
size_t lgSize = HphpArray::MinLgTableSize;
size_t maxElms = (size_t(3U)) << (lgSize-2);
size_t maxElms = (size_t(3U)) << (HphpArray::MinLgTableSize - 2);
assert(lgSize >= 2);
while (maxElms < numElms) {
while (maxElms < n) {
++lgSize;
maxElms <<= 1;
}
@@ -95,60 +101,72 @@ static inline size_t computeMaskFromNumElms(uint32_t numElms) {
//=============================================================================
// Construction/destruction.
inline void HphpArray::init(uint size) {
m_size = 0;
m_tableMask = computeMaskFromNumElms(size);
size_t tableSize = computeTableSize(m_tableMask);
size_t maxElms = computeMaxElms(m_tableMask);
allocData(maxElms, tableSize);
inline uint32_t HphpArray::initWithoutHash(uint capacity) {
m_tableMask = computeMaskFromNumElms(capacity);
auto const tableSize = computeTableSize(m_tableMask);
allocData(computeMaxElms(m_tableMask), tableSize);
return tableSize;
}
inline void HphpArray::init(uint capacity) {
assert(m_size == 0);
const auto tableSize = initWithoutHash(capacity);
initHash(m_hash, tableSize);
m_pos = ArrayData::invalid_index;
}
HphpArray::HphpArray(uint size) : ArrayData(kHphpArray),
m_lastE(ElmIndEmpty), m_data(nullptr), m_nextKI(0), m_hLoad(0) {
HphpArray::HphpArray(uint size) : ArrayData(kHphpArray, false, 0),
m_lastE(ElmIndEmpty), m_hLoad(0), m_nextKI(0) {
#ifdef PEDANTIC
if (size > 0x7fffffffU) {
raise_error("Cannot create an array with more than 2^31 - 1 elements");
}
#endif
assert(m_size == 0);
init(size);
}
HphpArray::HphpArray(uint size, const TypedValue* values) :
ArrayData(kHphpArray), m_lastE(ElmIndEmpty), m_data(nullptr),
m_nextKI(0), m_hLoad(0)
{
HphpArray::HphpArray(uint size, const TypedValue* values)
: ArrayData(kHphpArray, false, size)
, m_lastE(size - 1)
, m_hLoad(size)
, m_nextKI(size) {
#ifdef PEDANTIC
if (size > 0x7fffffffU) {
raise_error("Cannot create an array with more than 2^31 - 1 elements");
}
#endif
init(size);
initWithoutHash(size);
assert(size <= m_tableMask + 1);
// append values by moving -- Caller assumes we update refcount. Values
// are in reverse order since they come from the stack, which grows down.
// This code is hand-specialized from nextInsert().
assert(m_size == 0 && m_hLoad == 0 && m_nextKI == 0);
assert(m_size == size && m_hLoad == size && m_nextKI == size);
ElmInd* hash = m_hash;
Elm* data = m_data;
for (uint i = 0; i < size; i++) {
assert(hash[i] == HphpArray::ElmIndEmpty);
uint i = 0;
for (; i < size; i++) {
const TypedValue& tv = values[size - i - 1];
data[i].data.m_data = tv.m_data;
data[i].data.m_type = tv.m_type;
data[i].setIntKey(i);
hash[i] = i;
}
m_size = size;
m_hLoad = size;
m_lastE = size - 1;
m_nextKI = size;
if (size > 0) m_pos = 0;
// Initialize the leftover hash
for (; i <= m_tableMask; i++) {
hash[i] = ElmIndEmpty;
}
assert(m_size == size);
assert(m_hLoad == size);
assert(m_lastE == size - 1);
assert(m_nextKI == size);
assert(size == 0 || m_pos == 0);
}
HphpArray::HphpArray(EmptyMode) : ArrayData(kHphpArray),
m_lastE(ElmIndEmpty), m_data(nullptr), m_nextKI(0), m_hLoad(0) {
HphpArray::HphpArray(EmptyMode)
: ArrayData(kHphpArray, false, 0)
, m_lastE(ElmIndEmpty)
, m_hLoad(0)
, m_nextKI(0) {
init(0);
setStatic();
}
@@ -189,10 +207,10 @@ void HphpArray::dumpDebugInfo() const {
"--- dumpDebugInfo(this=0x%08zx) ----------------------------\n",
uintptr_t(this));
fprintf(stderr, "m_data = %p\tm_hash = %p\n"
"m_tableMask = %u\tm_size = %d\tm_hLoad = %d\n"
"m_nextKI = %" PRId64 "\t\tm_lastE = %d\tm_pos = %zd\n",
m_data, m_hash, m_tableMask, m_size, m_hLoad,
m_nextKI, m_lastE, m_pos);
"m_tableMask = %u\tm_size = %d\tm_hLoad = %d\n"
"m_nextKI = %" PRId64 "\t\tm_lastE = %d\tm_pos = %zd\n",
m_data, m_hash, m_tableMask, m_size, m_hLoad,
m_nextKI, m_lastE, size_t(m_pos));
fprintf(stderr, "Elements:\n");
ssize_t lastE = m_lastE;
Elm* elms = m_data;
@@ -394,7 +412,7 @@ Variant HphpArray::key() const {
return uninit_null();
}
Variant HphpArray::value(ssize_t& pos) const {
Variant HphpArray::value(int32_t& pos) const {
if (pos != ArrayData::invalid_index) {
Elm* e = &m_data[pos];
assert(e->data.m_type != KindOfTombstone);
@@ -703,7 +721,6 @@ void HphpArray::newElmStr(ElmInd* ei, strhash_t h, StringData* key,
}
void HphpArray::allocData(size_t maxElms, size_t tableSize) {
assert(!m_data);
if (maxElms <= SmallSize) {
m_data = m_inline_data.slots;
m_hash = m_inline_data.hash;