From 4debf268f7757519988097525a08363f7872ba33 Mon Sep 17 00:00:00 2001 From: Andrei Alexandrescu Date: Wed, 5 Jun 2013 20:33:08 -0700 Subject: [PATCH] ArrayData: consolidate m_nonsmart and m_allocMode into one field The in-situ allocation case can be easily detected by checking m_data == m_inline_data.slots. Therefore there's no need for two distinct flags to track current and future allocation strategy. --- hphp/runtime/base/array/array_data.cpp | 7 +- hphp/runtime/base/array/array_data.h | 71 +++++++++--------- hphp/runtime/base/array/hphp_array.cpp | 83 ++++++++++++---------- hphp/runtime/base/array/hphp_array.h | 4 +- hphp/runtime/base/array/policy_array.cpp | 68 +++++++++--------- hphp/runtime/base/array/policy_array.h | 27 +++---- hphp/runtime/base/shared/shared_map.h | 4 +- hphp/runtime/vm/name_value_table_wrapper.h | 2 +- 8 files changed, 139 insertions(+), 127 deletions(-) diff --git a/hphp/runtime/base/array/array_data.cpp b/hphp/runtime/base/array/array_data.cpp index 304a4de32..26a1cc7a3 100644 --- a/hphp/runtime/base/array/array_data.cpp +++ b/hphp/runtime/base/array/array_data.cpp @@ -31,6 +31,11 @@ namespace HPHP { /////////////////////////////////////////////////////////////////////////////// +static_assert( + sizeof(ArrayData) == 32, + "Performance is sensitive to sizeof(ArrayData)." + " Make sure you changed it with good reason and then update this assert."); + typedef tbb::concurrent_hash_map ArrayDataMap; static ArrayDataMap s_arrayDataMap; @@ -121,7 +126,7 @@ void ArrayData::release() { that->release(); return; } - assert(m_kind == kNameValueTableWrapper); + assert(m_kind == ArrayKind::kNameValueTableWrapper); // NameValueTableWrapper: nop. } diff --git a/hphp/runtime/base/array/array_data.h b/hphp/runtime/base/array/array_data.h index 895c43ba0..d1e31e559 100644 --- a/hphp/runtime/base/array/array_data.h +++ b/hphp/runtime/base/array/array_data.h @@ -34,6 +34,8 @@ class HphpArray; */ class ArrayData : public Countable { public: + enum class AllocationMode : bool { smart, nonSmart }; + enum ArrayOp { Plus, Merge, @@ -41,50 +43,47 @@ class ArrayData : public Countable { // enum of possible array types, so we can guard nonvirtual // fast paths in runtime code. - enum ArrayKind : uint8_t { + enum class ArrayKind : uint8_t { kHphpArray, kSharedMap, kNameValueTableWrapper, kArrayShell, }; - protected: - // used in subclasses but declared here. - enum AllocMode : uint8_t { kInline, kSmart, kMalloc }; - - public: +public: static const ssize_t invalid_index = -1; explicit ArrayData(ArrayKind kind) : m_size(-1) + , m_strongIterators(nullptr) , m_pos(0) , m_kind(kind) - , m_nonsmart(false) - , m_strongIterators(nullptr) { - } + , m_allocMode(AllocationMode::smart) + {} - ArrayData(ArrayKind kind, bool nonsmart) - : m_size(-1) - , m_pos(0) - , m_kind(kind) - , m_nonsmart(nonsmart) - , m_strongIterators(nullptr) { - } + explicit ArrayData(ArrayKind kind, AllocationMode m) + : m_size(-1) + , m_strongIterators(nullptr) + , m_pos(0) + , m_kind(kind) + , m_allocMode(m) + {} - ArrayData(ArrayKind kind, bool nonsmart, uint size) + ArrayData(ArrayKind kind, AllocationMode m, uint size) : m_size(size) + , m_strongIterators(nullptr) , m_pos(size ? 0 : ArrayData::invalid_index) , m_kind(kind) - , m_nonsmart(nonsmart) - , m_strongIterators(nullptr) { - } + , m_allocMode(m) + {} - ArrayData(const ArrayData *src, ArrayKind kind, bool nonsmart = false) - : m_pos(src->m_pos) - , m_kind(src->m_kind) - , m_nonsmart(nonsmart) - , m_strongIterators(nullptr) { - } + ArrayData(const ArrayData *src, ArrayKind kind, + AllocationMode m = AllocationMode::smart) + : m_strongIterators(nullptr) + , m_pos(src->m_pos) + , m_kind(src->m_kind) + , m_allocMode(m) + {} static HphpArray* Make(uint capacity); static HphpArray* Make(uint size, const TypedValue*); @@ -172,11 +171,11 @@ class ArrayData : public Countable { /* * Specific derived class type querying operators. */ - bool isArrayShell() const { return m_kind == kArrayShell; } - bool isHphpArray() const { return m_kind == kHphpArray; } - bool isSharedMap() const { return m_kind == kSharedMap; } + bool isArrayShell() const { return m_kind == ArrayKind::kArrayShell; } + bool isHphpArray() const { return m_kind == ArrayKind::kHphpArray; } + bool isSharedMap() const { return m_kind == ArrayKind::kSharedMap; } bool isNameValueTableWrapper() const { - return m_kind == kNameValueTableWrapper; + return m_kind == ArrayKind::kNameValueTableWrapper; } @@ -503,14 +502,12 @@ class ArrayData : public Countable { // Layout starts with 64 bits for vtable, then 32 bits for m_count // from Countable base, then... uint m_size; - int32_t m_pos; - protected: - const ArrayKind m_kind; - AllocMode m_allocMode; - const bool m_nonsmart; // never use smartalloc to allocate Elms - uint8_t m_slack8; // use this for whatever you wanna - private: +private: FullPos* m_strongIterators; // head of linked list +protected: + int32_t m_pos; + const ArrayKind m_kind; + const AllocationMode m_allocMode; public: // for the JIT static uint32_t getKindOff() { diff --git a/hphp/runtime/base/array/hphp_array.cpp b/hphp/runtime/base/array/hphp_array.cpp index 7e5898324..e98279ac3 100644 --- a/hphp/runtime/base/array/hphp_array.cpp +++ b/hphp/runtime/base/array/hphp_array.cpp @@ -41,6 +41,11 @@ namespace HPHP { +static_assert( + sizeof(HphpArray) == 160, + "Performance is sensitive to sizeof(HphpArray)." + " Make sure you changed it with good reason and then update this assert."); + static const Trace::Module TRACEMOD = Trace::runtime; /////////////////////////////////////////////////////////////////////////////// @@ -114,19 +119,22 @@ inline void HphpArray::init(uint capacity) { initHash(m_hash, tableSize); } -HphpArray::HphpArray(uint size) : ArrayData(kHphpArray, false, 0), - m_lastE(ElmIndEmpty), m_hLoad(0), m_nextKI(0) { +HphpArray::HphpArray(uint capacity) + : ArrayData(ArrayKind::kHphpArray, AllocationMode::smart, 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); + init(capacity); } HphpArray::HphpArray(uint size, const TypedValue* values) - : ArrayData(kHphpArray, false, size) + : ArrayData(ArrayKind::kHphpArray, AllocationMode::smart, size) , m_lastE(size - 1) , m_hLoad(size) , m_nextKI(size) { @@ -163,33 +171,36 @@ HphpArray::HphpArray(uint size, const TypedValue* values) } HphpArray::HphpArray(EmptyMode) - : ArrayData(kHphpArray, false, 0) - , m_lastE(ElmIndEmpty) - , m_hLoad(0) - , m_nextKI(0) { + : ArrayData(ArrayKind::kHphpArray, AllocationMode::smart, 0) + , m_lastE(ElmIndEmpty) + , m_hLoad(0) + , m_nextKI(0) { init(0); setStatic(); } // Empty constructor for internal use by nonSmartCopy() and copyImpl() -HphpArray::HphpArray(AllocMode mode) : - ArrayData(kHphpArray, /*nonsmart*/ mode == kMalloc) { +HphpArray::HphpArray(AllocationMode mode) : + ArrayData(ArrayKind::kHphpArray, mode) { } HOT_FUNC_VM HphpArray::~HphpArray() { - Elm* elms = m_data; - ssize_t lastE = (ssize_t)m_lastE; + auto const elms = m_data; + auto const lastE = (ssize_t)m_lastE; for (ssize_t /*ElmInd*/ pos = 0; pos <= lastE; ++pos) { - Elm* e = &elms[pos]; - if (e->data.m_type == KindOfTombstone) continue; - if (e->hasStrKey()) decRefStr(e->key); - tvRefcountedDecRef(&e->data); + auto& e = elms[pos]; + if (e.data.m_type == KindOfTombstone) continue; + if (e.hasStrKey()) decRefStr(e.key); + tvRefcountedDecRef(&e.data); } - if (m_allocMode == kSmart) { - smart_free(m_data); - } else if (m_allocMode == kMalloc) { - free(m_data); + if (m_data == m_inline_data.slots) { + return; + } + if (m_allocMode == AllocationMode::smart) { + smart_free(elms); + } else { + free(elms); } } @@ -724,19 +735,16 @@ void HphpArray::allocData(size_t maxElms, size_t tableSize) { if (maxElms <= SmallSize) { m_data = m_inline_data.slots; m_hash = m_inline_data.hash; - m_allocMode = kInline; return; } size_t hashSize = tableSize * sizeof(ElmInd); size_t dataSize = maxElms * sizeof(Elm); size_t allocSize = hashSize <= sizeof(m_inline_hash) ? dataSize : dataSize + hashSize; - if (!m_nonsmart) { + if (m_allocMode == AllocationMode::smart) { m_data = (Elm*) smart_malloc(allocSize); - m_allocMode = kSmart; } else { m_data = (Elm*) Util::safe_malloc(allocSize); - m_allocMode = kMalloc; } m_hash = hashSize <= sizeof(m_inline_hash) ? m_inline_hash : (ElmInd*)(uintptr_t(m_data) + dataSize); @@ -749,24 +757,21 @@ void HphpArray::reallocData(size_t maxElms, size_t tableSize, uint oldMask) { size_t allocSize = hashSize <= sizeof(m_inline_hash) ? dataSize : dataSize + hashSize; size_t oldDataSize = computeMaxElms(oldMask) * sizeof(Elm); // slots only. - if (!m_nonsmart) { - assert(m_allocMode == kInline || m_allocMode == kSmart); - if (m_allocMode == kInline) { + if (m_allocMode == AllocationMode::smart) { + if (m_data == m_inline_data.slots) { m_data = (Elm*) smart_malloc(allocSize); + copyData: memcpy(m_data, m_inline_data.slots, oldDataSize); - m_allocMode = kSmart; } else { m_data = (Elm*) smart_realloc(m_data, allocSize); } } else { - assert(m_allocMode == kInline || m_allocMode == kMalloc); - if (m_allocMode == kInline) { + if (m_data == m_inline_data.slots) { m_data = (Elm*) Util::safe_malloc(allocSize); - memcpy(m_data, m_inline_data.slots, oldDataSize); - m_allocMode = kMalloc; - } else { - m_data = (Elm*) Util::safe_realloc(m_data, allocSize); + // This goto doesn't loop, just saves the memcpy call code. + goto copyData; } + m_data = (Elm*) Util::safe_realloc(m_data, allocSize); } m_hash = hashSize <= sizeof(m_inline_hash) ? m_inline_hash : (ElmInd*)(uintptr_t(m_data) + dataSize); @@ -1855,8 +1860,8 @@ ArrayData* array_add(ArrayData* a1, ArrayData* a2) { //============================================================================= -ALWAYS_INLINE HphpArray* HphpArray::clone(AllocMode am) const { - const auto p = am == kSmart +ALWAYS_INLINE HphpArray* HphpArray::clone(AllocationMode am) const { + const auto p = am == AllocationMode::smart ? HphpArray::AllocatorType::getNoCheck()->alloc(sizeof(HphpArray)) : operator new(sizeof(HphpArray)); auto target = new(p) HphpArray(am); @@ -1870,7 +1875,7 @@ ALWAYS_INLINE HphpArray* HphpArray::clone(AllocMode am) const { // frequent. Do this only for arrays that actually don't allocate // data so the copied array doesn't lose capacity. target->ArrayData::m_pos = invalid_index; - target->ArrayData::m_allocMode = kInline; + assert(target->ArrayData::m_allocMode == am); // Conservatively copy m_nextKI target->m_nextKI = m_nextKI; target->m_tableMask = SmallHashSize - 1; @@ -1889,11 +1894,11 @@ ALWAYS_INLINE HphpArray* HphpArray::clone(AllocMode am) const { } NEVER_INLINE ArrayData* HphpArray::nonSmartCopy() const { - return clone(kMalloc); + return clone(AllocationMode::nonSmart); } NEVER_INLINE HphpArray* HphpArray::copyImpl() const { - return clone(kSmart); + return clone(AllocationMode::smart); } NEVER_INLINE void HphpArray::cloneNonEmpty(HphpArray* target) const { diff --git a/hphp/runtime/base/array/hphp_array.h b/hphp/runtime/base/array/hphp_array.h index 40b26273f..fe1653e2f 100644 --- a/hphp/runtime/base/array/hphp_array.h +++ b/hphp/runtime/base/array/hphp_array.h @@ -45,7 +45,7 @@ public: private: // for copy-on-write escalation - explicit HphpArray(AllocMode); + explicit HphpArray(AllocationMode); public: // Create an empty array with enough capacity for nSize elements. @@ -507,7 +507,7 @@ public: } private: - HphpArray* clone(AllocMode am) const; + HphpArray* clone(AllocationMode am) const; void cloneNonEmpty(HphpArray* target) const; }; diff --git a/hphp/runtime/base/array/policy_array.cpp b/hphp/runtime/base/array/policy_array.cpp index 98f0fc31a..a6894735c 100644 --- a/hphp/runtime/base/array/policy_array.cpp +++ b/hphp/runtime/base/array/policy_array.cpp @@ -46,11 +46,12 @@ static string valstr(const Variant& v) { SimpleArrayStore::SimpleArrayStore(const SimpleArrayStore& rhs, uint length, uint capacity, - bool nonSmart, const ArrayData* owner) + ArrayData::AllocationMode am, + const ArrayData* owner) : m_capacity(std::max(startingCapacity, capacity)) , m_nextKey(rhs.m_nextKey) { assert(length <= capacity && this != &rhs); - allocate(m_keys, m_vals, m_capacity, nonSmart); + allocate(m_keys, m_vals, m_capacity, am); // Copy data with flattening FOR_EACH_RANGE (i, 0, length) { tvDupFlattenVars(rhs.m_vals + i, m_vals + i, owner); @@ -63,26 +64,26 @@ SimpleArrayStore::SimpleArrayStore(const SimpleArrayStore& rhs, } void SimpleArrayStore::grow(uint length, uint minCap, uint idealCap, - bool nonSmart) { + ArrayData::AllocationMode am) { assert(idealCap >= minCap); if (m_capacity >= minCap) return; MYLOG << (void*)this << "->grow(" << length << ", " << minCap << ", " - << idealCap << ", " << nonSmart << "); m_capacity=" << m_capacity; + << idealCap << ", " << uint(am) << "); m_capacity=" << m_capacity; idealCap = std::max(startingCapacity, idealCap); Key* newKeys; TypedValueAux* newVals; - allocate(newKeys, newVals, idealCap, nonSmart); + allocate(newKeys, newVals, idealCap, am); // Move data memcpy(newKeys, m_keys, length * sizeof(*m_keys)); memcpy(newVals, m_vals, length * sizeof(*m_vals)); - deallocate(m_keys, m_vals, nonSmart); + deallocate(m_keys, m_vals, am); // Change state m_capacity = idealCap; m_keys = newKeys; m_vals = newVals; } -void SimpleArrayStore::destroy(uint length, bool nonSmart) { +void SimpleArrayStore::destroy(uint length, ArrayData::AllocationMode am) { FOR_EACH_RANGE (i, 0, length) { if (hasStrKey(toPos(i))) { auto k = m_keys[i].s; @@ -91,7 +92,7 @@ void SimpleArrayStore::destroy(uint length, bool nonSmart) { } lval(toPos(i)).~Variant(); } - deallocate(m_keys, m_vals, nonSmart); + deallocate(m_keys, m_vals, am); #ifndef NDEBUG m_keys = nullptr; m_vals = nullptr; @@ -130,7 +131,7 @@ PosType SimpleArrayStore::find(const StringData* key, uint length) const { template bool SimpleArrayStore::update(K key, const Variant& val, uint length, - bool nonSmart) { + ArrayData::AllocationMode am) { assert(length <= m_capacity && m_vals); auto const pos = find(key, length); if (pos != PosType::invalid) { @@ -142,7 +143,7 @@ bool SimpleArrayStore::update(K key, const Variant& val, uint length, // not found, insert assert(length <= m_capacity); if (length == m_capacity) { - grow(length, length + 1, length * 2 + 1, nonSmart); + grow(length, length + 1, length * 2 + 1, am); } assert(m_keys && m_vals && length < m_capacity); new(&lval(toPos(length))) Variant(val); @@ -166,9 +167,10 @@ void SimpleArrayStore::erase(PosType pos, uint length) { memmove(m_vals + ipos, m_vals + ipos + 1, itemsToMove * sizeof(*m_vals)); } -void SimpleArrayStore::prepend(const Variant& v, uint length, bool nonSmart) { +void SimpleArrayStore::prepend(const Variant& v, uint length, + ArrayData::AllocationMode am) { if (length == capacity()) { - grow(length, length + 1, length * 2 + 1, nonSmart); + grow(length, length + 1, length * 2 + 1, am); } assert(length < capacity()); // Shift stuff over @@ -183,8 +185,8 @@ void SimpleArrayStore::prepend(const Variant& v, uint length, bool nonSmart) { IMPLEMENT_SMART_ALLOCATION(ArrayShell) ArrayShell::ArrayShell(uint capacity) - : ArrayData(kArrayShell) - , Store(m_nonsmart, capacity) { + : ArrayData(ArrayKind::kArrayShell) + , Store(m_allocMode, capacity) { m_size = 0; m_pos = invalid_index; // Log at the end of the ctor so as to show the properly initialized @@ -193,19 +195,19 @@ ArrayShell::ArrayShell(uint capacity) } ArrayShell::ArrayShell(const ArrayShell& rhs, uint capacity, - bool nonSmart) - : ArrayData(kArrayShell, nonSmart) - , Store(rhs, rhs.m_size, capacity, nonSmart, &rhs) { + AllocationMode am) + : ArrayData(ArrayKind::kArrayShell, am) + , Store(rhs, rhs.m_size, capacity, am, &rhs) { m_size = rhs.m_size; m_pos = rhs.m_pos; // Log at the end of the ctor so as to show the properly initialized // members. - APILOG << "(" << &rhs << ", " << capacity << ", " << nonSmart << ");"; + APILOG << "(" << &rhs << ", " << capacity << ", " << uint(am) << ");"; } ArrayShell::~ArrayShell() { APILOG << "()"; - destroy(m_size, m_nonsmart); + destroy(m_size, m_allocMode); } Variant ArrayShell::getKey(ssize_t pos) const { @@ -391,7 +393,7 @@ ArrayData *ArrayShell::lvalImpl(K k, Variant*& ret, } else { // not found, initialize if (m_size == capacity()) { - grow(m_size, m_size + 1, m_size * 2 + 1, m_nonsmart); + grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode); } assert(m_size < capacity()); ret = appendNoGrow(k, Variant::NullInit()); @@ -431,7 +433,7 @@ ArrayShell* ArrayShell::setImpl(K k, const Variant& v, bool copy) { << ")"; ArrayShell* result = this; if (copy) result = ArrayShell::copy(); - if (result->update(k, v, result->m_size, result->m_nonsmart)) { + if (result->update(k, v, result->m_size, result->m_allocMode)) { // Added a new element, must update size and possibly m_pos if (m_pos == invalid_index) m_pos = result->m_size; result->m_size++; @@ -457,7 +459,7 @@ ArrayData *ArrayShell::setRefImpl(K k, CVarRef v, bool copy) { MYLOG << "setRef: not found, appending at " << m_size; if (m_size == capacity()) { MYLOG << "grow"; - grow(m_size, m_size + 1, m_size * 2 + 1, m_nonsmart); + grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode); } appendNoGrow(k, Variant::NoInit())->constructRefHelper(v); } @@ -475,7 +477,7 @@ ArrayData *ArrayShell::addImpl(K k, const Variant& v, bool copy) { assert(!exists(k)); // Make sure there's enough capacity if (m_size == capacity()) { - grow(m_size, m_size + 1, m_size * 2 + 1, m_nonsmart); + grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode); } appendNoGrow(k, v); return this; @@ -489,7 +491,7 @@ ArrayShell *ArrayShell::addLvalImpl(K k, Variant*& ret, bool copy) { } assert(!exists(k) && m_size <= capacity()); if (m_size == capacity()) { - grow(m_size, m_size + 1, m_size * 2 + 1, m_nonsmart); + grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode); } ret = appendNoGrow(k, Variant::NullInit()); MYLOG << (void*)this << "->lval:" << "added"; @@ -635,14 +637,14 @@ ArrayShell *ArrayShell::copy() const { auto result = NEW(ArrayShell)( *this, capacity() + (m_size == capacity()), - m_nonsmart); + m_allocMode); assert(result->getCount() == 0); return result; } ArrayShell* ArrayShell::copy(uint capacity) { APILOG << "(" << capacity << ")"; - return NEW(ArrayShell)(*this, capacity, m_nonsmart); + return NEW(ArrayShell)(*this, capacity, m_allocMode); } ArrayShell *ArrayShell::copyWithStrongIterators() const { @@ -664,7 +666,7 @@ ArrayShell *ArrayShell::append(const Variant& v, bool copy) { if (copy) { return ArrayShell::copy()->append(v, false); } - grow(m_size, m_size + 1, m_size * 2 + 1, m_nonsmart); + grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode); appendNoGrow(nextKeyBump(), v); return this; } @@ -677,7 +679,7 @@ ArrayShell *ArrayShell::appendRef(const Variant& v, bool copy) { //addValWithRef(nextKeyBump(), v); auto const k = nextKeyBump(); if (m_size == capacity()) { - grow(m_size, m_size + 1, m_size * 2 + 1, m_nonsmart); + grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode); } assert(m_size < capacity()); appendNoGrow(k, Variant::NoInit())->constructRefHelper(v); @@ -693,7 +695,7 @@ ArrayData *ArrayShell::appendWithRef(CVarRef v, bool copy) { return ArrayShell::copy()->appendWithRef(v, false); } if (m_size == capacity()) { - grow(m_size, m_size + 1, m_size * 2 + 1, m_nonsmart); + grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode); } assert(m_size < capacity()); appendNoGrow(nextKeyBump(), Variant::NullInit())->setWithRef(v); @@ -710,7 +712,7 @@ void ArrayShell::addValWithRef(K k, const Variant& v) { return; } if (m_size == capacity()) { - grow(m_size, m_size + 1, m_size * 2 + 1, m_nonsmart); + grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode); } assert(m_size < capacity()); appendNoGrow(k, Variant::NullInit())->setWithRef(v); @@ -730,7 +732,7 @@ void ArrayShell::nextInsertWithRef(const Variant& v) { // always false [-Werror=strict-overflow] auto const k = nextKeyBump(); if (m_size == capacity()) { - grow(m_size, m_size + 1, m_size * 2 + 1, m_nonsmart); + grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode); } assert(m_size < capacity()); appendNoGrow(k, Variant::NullInit())->setWithRef(v); @@ -744,7 +746,7 @@ ArrayData *ArrayShell::append(const ArrayData *elems, ArrayOp op, bool copy) { assert(elems); assert(op == Plus || op == Merge); - grow(m_size, m_size + 1, m_size * 2 + 1, m_nonsmart); + grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode); for (ArrayIter it(elems); !it.end(); it.next()) { Variant key = it.first(); @@ -827,7 +829,7 @@ ArrayData* ArrayShell::prepend(CVarRef v, bool copy) { // To match PHP-like semantics, we invalidate all strong iterators when an // element is added to the beginning of the array. freeStrongIterators(); - Store::prepend(v, m_size, m_nonsmart); + Store::prepend(v, m_size, m_allocMode); ++m_size; auto first = firstIndex(m_size); setKey(first, int64_t(0)); diff --git a/hphp/runtime/base/array/policy_array.h b/hphp/runtime/base/array/policy_array.h index 18a52b8cc..939484a41 100644 --- a/hphp/runtime/base/array/policy_array.h +++ b/hphp/runtime/base/array/policy_array.h @@ -99,11 +99,12 @@ class SimpleArrayStore { Allocate keys and values at a given capacity and with a given allocation strategy. */ - static void allocate(Key*& ks, TypedValueAux*& vs, uint cap, bool nonSmart) { + static void allocate(Key*& ks, TypedValueAux*& vs, uint cap, + ArrayData::AllocationMode am) { /* To save time, only one allocation is done and keys are stored right next to the values. */ auto const totSize = (sizeof(*ks) + sizeof(*vs)) * cap; - auto const raw = nonSmart + auto const raw = am == ArrayData::AllocationMode::nonSmart ? Util::safe_malloc(totSize) : smart_malloc(totSize); vs = static_cast(raw); @@ -111,9 +112,10 @@ class SimpleArrayStore { } /** Inverse of allocate */ - static void deallocate(Key* ks, TypedValueAux* vs, bool nonSmart) { + static void deallocate(Key* ks, TypedValueAux* vs, + ArrayData::AllocationMode am) { assert(ks && vs); - if (nonSmart) { + if (am == ArrayData::AllocationMode::nonSmart) { Util::safe_free(vs); } else { smart_free(vs); @@ -139,7 +141,7 @@ protected: required by tvDupFlattenVars). */ SimpleArrayStore(const SimpleArrayStore& rhs, uint length, uint capacity, - bool nonSmart, const ArrayData* owner); + ArrayData::AllocationMode am, const ArrayData* owner); ~SimpleArrayStore() { /* If this fails, it means someone didn't call destroy. */ assert(!m_keys && !m_vals); @@ -151,7 +153,7 @@ protected: separate function in order to obtain length and nonSmart information. */ - void destroy(uint length, bool nonSmart); + void destroy(uint length, ArrayData::AllocationMode); /** The following four methods implement bidirectional iteration for @@ -188,7 +190,7 @@ protected: Prepend v to the array. An uninitialized hole is left in the first key slot; you MUST use setKey subsequently to initialize it. */ - void prepend(const Variant& v, uint length, bool nonSmart); + void prepend(const Variant& v, uint length, ArrayData::AllocationMode); /** Erase at position pos from the array. Cleans up data and @@ -200,10 +202,10 @@ protected: Construct an array store with the given allocation strategy and capacity. */ - SimpleArrayStore(bool nonSmart, uint capacity) + SimpleArrayStore(ArrayData::AllocationMode am, uint capacity) : m_capacity(std::max(startingCapacity, capacity)) , m_nextKey(0) { - allocate(m_keys, m_vals, m_capacity, nonSmart); + allocate(m_keys, m_vals, m_capacity, am); } /** @@ -218,7 +220,7 @@ protected: <= minSize && minSize = idealSize. No actual objects are allocated in the grown store. */ - void grow(uint size, uint minSize, uint idealSize, bool nonSmart); + void grow(uint size, uint minSize, uint idealSize, ArrayData::AllocationMode); /** Returns true iff the key at pos is a string. @@ -277,7 +279,8 @@ protected: its refcount. */ template - bool update(K key, const Variant& val, uint length, bool nonSmart); + bool update(K key, const Variant& val, uint length, + ArrayData::AllocationMode); /** Returns a const reference to the Variant held at position @@ -326,7 +329,7 @@ class ArrayShell : public ArrayData, private SimpleArrayStore { ArrayShell(const ArrayShell& rhs) = delete; ArrayShell& operator=(const ArrayShell& rhs) = delete; - ArrayShell(const ArrayShell& rhs, uint capacity, bool nonSmart); + ArrayShell(const ArrayShell& rhs, uint capacity, ArrayData::AllocationMode); template void addValWithRef(K k, const Variant& value); diff --git a/hphp/runtime/base/shared/shared_map.h b/hphp/runtime/base/shared/shared_map.h index 34f762343..025ff8f83 100644 --- a/hphp/runtime/base/shared/shared_map.h +++ b/hphp/runtime/base/shared/shared_map.h @@ -32,8 +32,8 @@ namespace HPHP { class SharedMap : public ArrayData { public: explicit SharedMap(SharedVariant* source) - : ArrayData(kSharedMap) - , m_localCache(nullptr) { + : ArrayData(ArrayKind::kSharedMap) + , m_localCache(nullptr) { m_map = source->getMap(); m_isVector = source->getIsVector(); } diff --git a/hphp/runtime/vm/name_value_table_wrapper.h b/hphp/runtime/vm/name_value_table_wrapper.h index 51eca1719..24705fafd 100644 --- a/hphp/runtime/vm/name_value_table_wrapper.h +++ b/hphp/runtime/vm/name_value_table_wrapper.h @@ -54,7 +54,7 @@ namespace HPHP { */ struct NameValueTableWrapper : public ArrayData { explicit NameValueTableWrapper(NameValueTable* tab) - : ArrayData(kNameValueTableWrapper) + : ArrayData(ArrayKind::kNameValueTableWrapper) , m_tab(tab) { }