diff --git a/hphp/runtime/base/array_data-defs.h b/hphp/runtime/base/array_data-defs.h index 3faa29045..b99e46a60 100644 --- a/hphp/runtime/base/array_data-defs.h +++ b/hphp/runtime/base/array_data-defs.h @@ -193,6 +193,100 @@ inline ArrayData* ArrayData::set(StringData* k, CVarRef v, bool copy) { return g_array_funcs.setStr[m_kind](this, k, v, copy); } +inline size_t ArrayData::vsize() const { + return g_array_funcs.vsize[m_kind](this); +} + +inline CVarRef ArrayData::getValueRef(ssize_t pos) const { + return g_array_funcs.getValueRef[m_kind](this, pos); +} + +inline bool ArrayData::noCopyOnWrite() const { + return g_array_funcs.noCopyOnWrite[m_kind]; +} + +inline bool ArrayData::isVectorData() const { + return g_array_funcs.isVectorData[m_kind](this); +} + +inline bool ArrayData::exists(int64_t k) const { + return g_array_funcs.existsInt[m_kind](this, k); +} + +inline bool ArrayData::exists(const StringData* k) const { + return g_array_funcs.existsStr[m_kind](this, k); +} + +inline ArrayData* ArrayData::lval(int64_t k, Variant*& ret, bool copy) { + return g_array_funcs.lvalInt[m_kind](this, k, ret, copy); +} + +inline ArrayData* ArrayData::lval(StringData* k, Variant*& ret, bool copy) { + return g_array_funcs.lvalStr[m_kind](this, k, ret, copy); +} + +inline ArrayData* ArrayData::lvalNew(Variant*& ret, bool copy) { + return g_array_funcs.lvalNew[m_kind](this, ret, copy); +} + +inline ArrayData* ArrayData::createLvalPtr(StringData* k, Variant*& ret, + bool copy) { + return g_array_funcs.createLvalPtr[m_kind](this, k, ret, copy); +} + +inline ArrayData* ArrayData::getLvalPtr(StringData* k, Variant*& ret, + bool copy) { + return g_array_funcs.getLvalPtr[m_kind](this, k, ret, copy); +} + +inline ArrayData* ArrayData::setRef(int64_t k, CVarRef v, bool copy) { + return g_array_funcs.setRefInt[m_kind](this, k, v, copy); +} + +inline ArrayData* ArrayData::setRef(StringData* k, CVarRef v, bool copy) { + return g_array_funcs.setRefStr[m_kind](this, k, v, copy); +} + +inline ArrayData* ArrayData::add(int64_t k, CVarRef v, bool copy) { + return g_array_funcs.addInt[m_kind](this, k, v, copy); +} + +inline ArrayData* ArrayData::add(StringData* k, CVarRef v, bool copy) { + return g_array_funcs.addStr[m_kind](this, k, v, copy); +} + +inline ArrayData* ArrayData::addLval(int64_t k, Variant *&ret, bool copy) { + return g_array_funcs.addLvalInt[m_kind](this, k, ret, copy); +} + +inline ArrayData* ArrayData::addLval(StringData* k, Variant *&ret, bool copy) { + return g_array_funcs.addLvalStr[m_kind](this, k, ret, copy); +} + +inline ArrayData* ArrayData::remove(int64_t k, bool copy) { + return g_array_funcs.removeInt[m_kind](this, k, copy); +} + +inline ArrayData* ArrayData::remove(const StringData* k, bool copy) { + return g_array_funcs.removeStr[m_kind](this, k, copy); +} + +inline ssize_t ArrayData::iter_begin() const { + return g_array_funcs.iterBegin[m_kind](this); +} + +inline ssize_t ArrayData::iter_end() const { + return g_array_funcs.iterEnd[m_kind](this); +} + +inline ssize_t ArrayData::iter_advance(ssize_t pos) const { + return g_array_funcs.iterAdvance[m_kind](this, pos); +} + +inline ssize_t ArrayData::iter_rewind(ssize_t pos) const { + return g_array_funcs.iterRewind[m_kind](this, pos); +} + /////////////////////////////////////////////////////////////////////////////// } diff --git a/hphp/runtime/base/array_data.cpp b/hphp/runtime/base/array_data.cpp index 7fd25f07b..451492c67 100644 --- a/hphp/runtime/base/array_data.cpp +++ b/hphp/runtime/base/array_data.cpp @@ -64,6 +64,11 @@ ArrayData *ArrayData::GetScalarArray(ArrayData *arr, /////////////////////////////////////////////////////////////////////////////// +static size_t VsizeNop(const ArrayData* ad) { + assert(false); + return ad->getSize(); +} + // order: kVectorKind, kMixedKind, kSharedKind, kNvtwKind, kPolicyKind extern const ArrayFunctions g_array_funcs = { // release @@ -101,6 +106,121 @@ extern const ArrayFunctions g_array_funcs = { &SharedMap::SetStr, &NameValueTableWrapper::SetStr, &PolicyArray::SetStr }, + // vsize + { &VsizeNop, &VsizeNop, + &VsizeNop, + &NameValueTableWrapper::Vsize, + &VsizeNop }, + // getValueRef + { &HphpArray::GetValueRef, &HphpArray::GetValueRef, + &SharedMap::GetValueRef, + &NameValueTableWrapper::GetValueRef, + &PolicyArray::GetValueRef }, + // noCopyOnWrite + { false, false, + false, + true, // NameValueTableWrapper doesn't support COW. + false }, + // isVectorData + { &HphpArray::IsVectorDataVec, &HphpArray::IsVectorData, + &SharedMap::IsVectorData, + &NameValueTableWrapper::IsVectorData, + &PolicyArray::IsVectorData }, + // existsInt + { &HphpArray::ExistsIntVec, &HphpArray::ExistsInt, + &SharedMap::ExistsInt, + &NameValueTableWrapper::ExistsInt, + &PolicyArray::ExistsInt }, + // existsStr + { &HphpArray::ExistsStrVec, &HphpArray::ExistsStr, + &SharedMap::ExistsStr, + &NameValueTableWrapper::ExistsStr, + &PolicyArray::ExistsStr }, + // lvalInt + { &HphpArray::LvalIntVec, &HphpArray::LvalInt, + &SharedMap::LvalInt, + &NameValueTableWrapper::LvalInt, + &PolicyArray::LvalInt }, + // lvalStr + { &HphpArray::LvalStrVec, &HphpArray::LvalStr, + &SharedMap::LvalStr, + &NameValueTableWrapper::LvalStr, + &PolicyArray::LvalStr }, + // lvalNew + { &HphpArray::LvalNewVec, &HphpArray::LvalNew, + &SharedMap::LvalNew, + &NameValueTableWrapper::LvalNew, + &PolicyArray::LvalNew }, + // createLvalPtr + { &HphpArray::CreateLvalPtrVec, &HphpArray::CreateLvalPtr, + &ArrayData::CreateLvalPtr, // fatal + &ArrayData::CreateLvalPtr, // fatal + &PolicyArray::CreateLvalPtr }, + // getLvalPtr + { &HphpArray::GetLvalPtrVec, &HphpArray::GetLvalPtr, + &ArrayData::GetLvalPtr, // fatal + &ArrayData::GetLvalPtr, // fatal + &PolicyArray::GetLvalPtr }, + // setRefInt + { &HphpArray::SetRefIntVec, &HphpArray::SetRefInt, + &SharedMap::SetRefInt, + &NameValueTableWrapper::SetRefInt, + &PolicyArray::SetRefInt }, + // setRefStr + { &HphpArray::SetRefStrVec, &HphpArray::SetRefStr, + &SharedMap::SetRefStr, + &NameValueTableWrapper::SetRefStr, + &PolicyArray::SetRefStr }, + // addInt + { &HphpArray::AddIntVec, &HphpArray::AddInt, + &SharedMap::SetInt, // reuse set + &NameValueTableWrapper::SetInt, // reuse set + &PolicyArray::AddInt }, + // addStr + { &HphpArray::AddStrVec, &HphpArray::AddStr, + &SharedMap::SetStr, // reuse set + &NameValueTableWrapper::SetStr, // reuse set + &PolicyArray::AddStr }, + // addLvalInt + { &HphpArray::AddLvalIntVec, &HphpArray::AddLvalInt, + &SharedMap::AddLvalInt, + &NameValueTableWrapper::AddLvalInt, + &PolicyArray::AddLvalInt }, + // addLvalStr + { &HphpArray::AddLvalStrVec, &HphpArray::AddLvalStr, + &SharedMap::AddLvalStr, + &NameValueTableWrapper::AddLvalStr, + &PolicyArray::AddLvalStr }, + // removeInt + { &HphpArray::RemoveIntVec, &HphpArray::RemoveInt, + &SharedMap::RemoveInt, + &NameValueTableWrapper::RemoveInt, + &PolicyArray::RemoveInt }, + // removeStr + { &HphpArray::RemoveStrVec, &HphpArray::RemoveStr, + &SharedMap::RemoveStr, + &NameValueTableWrapper::RemoveStr, + &PolicyArray::RemoveStr }, + // iterBegin + { &HphpArray::IterBegin, &HphpArray::IterBegin, + &SharedMap::IterBegin, + &NameValueTableWrapper::IterBegin, + &PolicyArray::IterBegin }, + // iterEnd + { &HphpArray::IterEnd, &HphpArray::IterEnd, + &SharedMap::IterEnd, + &NameValueTableWrapper::IterEnd, + &PolicyArray::IterEnd }, + // iterAdvance + { &HphpArray::IterAdvance, &HphpArray::IterAdvance, + &SharedMap::IterAdvance, + &NameValueTableWrapper::IterAdvance, + &PolicyArray::IterAdvance }, + // iterRewind + { &HphpArray::IterRewind, &HphpArray::IterRewind, + &SharedMap::IterRewind, + &NameValueTableWrapper::IterRewind, + &PolicyArray::IterRewind }, }; /////////////////////////////////////////////////////////////////////////////// @@ -218,34 +338,16 @@ bool ArrayData::equal(const ArrayData *v2, bool strict) const { return true; } -ArrayData *ArrayData::createLvalPtr(StringData* k, Variant *&ret, bool copy) { +ArrayData *ArrayData::CreateLvalPtr(ArrayData* ad, StringData* k, + Variant *&ret, bool copy) { throw FatalErrorException("Unimplemented ArrayData::createLvalPtr"); } -ArrayData *ArrayData::getLvalPtr(StringData* k, Variant *&ret, bool copy) { +ArrayData *ArrayData::GetLvalPtr(ArrayData* ad, StringData* k, + Variant *&ret, bool copy) { throw FatalErrorException("Unimplemented ArrayData::getLvalPtr"); } -ArrayData *ArrayData::add(int64_t k, CVarRef v, bool copy) { - assert(!exists(k)); - return set(k, v, copy); -} - -ArrayData *ArrayData::add(StringData* k, CVarRef v, bool copy) { - assert(!exists(k)); - return set(k, v, copy); -} - -ArrayData *ArrayData::addLval(int64_t k, Variant *&ret, bool copy) { - assert(!exists(k)); - return lval(k, ret, copy); -} - -ArrayData *ArrayData::addLval(StringData* k, Variant *&ret, bool copy) { - assert(!exists(k)); - return lval(k, ret, copy); -} - /////////////////////////////////////////////////////////////////////////////// // stack and queue operations diff --git a/hphp/runtime/base/array_data.h b/hphp/runtime/base/array_data.h index bccd64981..d38f68d1b 100644 --- a/hphp/runtime/base/array_data.h +++ b/hphp/runtime/base/array_data.h @@ -144,25 +144,32 @@ public: /** * Number of elements this array has. */ - ssize_t size() const { + size_t size() const { if (UNLIKELY((int)m_size) < 0) return vsize(); return m_size; } + // unlike ArrayData::size(), this functions doesn't delegate + // to the virtual Vsize() function, so its more efficient to + // use this when you know you don't have a NameValueTableWrapper. + size_t getSize() const { + return m_size; + } + /** * Number of elements this array has. */ - virtual ssize_t vsize() const = 0; + size_t vsize() const; /** * getValueRef() gets a reference to value at position "pos". */ - virtual CVarRef getValueRef(ssize_t pos) const = 0; + CVarRef getValueRef(ssize_t pos) const; /* * Return true for array types that don't have COW semantics. */ - virtual bool noCopyOnWrite() const { return false; } + bool noCopyOnWrite() const; /* * Specific derived class type querying operators. @@ -183,7 +190,7 @@ public: * Returns whether or not this array contains "vector-like" data. * I.e. all the keys are contiguous increasing integers. */ - virtual bool isVectorData() const = 0; + bool isVectorData() const; /** * Whether or not this array has a referenced Variant or Object appearing @@ -213,8 +220,8 @@ public: /** * Testing whether a key exists. */ - virtual bool exists(int64_t k) const = 0; - virtual bool exists(const StringData* k) const = 0; + bool exists(int64_t k) const; + bool exists(const StringData* k) const; /** * Interface for VM helpers. ArrayData implements generic versions @@ -236,8 +243,8 @@ public: * Getting l-value (that Variant pointer) at specified key. Return this if * escalation is not needed, or an escalated array data. */ - virtual ArrayData *lval(int64_t k, Variant *&ret, bool copy) = 0; - virtual ArrayData *lval(StringData* k, Variant *&ret, bool copy) = 0; + ArrayData *lval(int64_t k, Variant *&ret, bool copy); + ArrayData *lval(StringData* k, Variant *&ret, bool copy); /** * Getting l-value (that Variant pointer) of a new element with the next @@ -246,15 +253,19 @@ public: * available integer key may fail, in which case ret is set to point to * the lval blackhole (see Variant::lvalBlackHole() for details). */ - virtual ArrayData *lvalNew(Variant *&ret, bool copy) = 0; + ArrayData *lvalNew(Variant *&ret, bool copy); /** * Helper functions used for getting a reference to elements of * the dynamic property array in ObjectData or the local cache array * in ShardMap. */ - virtual ArrayData *createLvalPtr(StringData* k, Variant *&ret, bool copy); - virtual ArrayData *getLvalPtr(StringData* k, Variant *&ret, bool copy); + ArrayData *createLvalPtr(StringData* k, Variant *&ret, bool copy); + ArrayData *getLvalPtr(StringData* k, Variant *&ret, bool copy); + static ArrayData *CreateLvalPtr(ArrayData* ad, StringData* k, + Variant *&ret, bool copy); + static ArrayData *GetLvalPtr(ArrayData* ad, StringData* k, + Variant *&ret, bool copy); /** * Setting a value at specified key. If "copy" is true, make a copy first @@ -264,31 +275,31 @@ public: ArrayData *set(int64_t k, CVarRef v, bool copy); ArrayData *set(StringData* k, CVarRef v, bool copy); - virtual ArrayData *setRef(int64_t k, CVarRef v, bool copy) = 0; - virtual ArrayData *setRef(StringData* k, CVarRef v, bool copy) = 0; + ArrayData *setRef(int64_t k, CVarRef v, bool copy); + ArrayData *setRef(StringData* k, CVarRef v, bool copy); /** * The same as set(), but with the precondition that the key does * not already exist in this array. (This is to allow more * efficient implementation of this case in some derived classes.) */ - virtual ArrayData *add(int64_t k, CVarRef v, bool copy); - virtual ArrayData *add(StringData* k, CVarRef v, bool copy); + ArrayData *add(int64_t k, CVarRef v, bool copy); + ArrayData *add(StringData* k, CVarRef v, bool copy); /* * Same semantics as lval(), except with the precondition that the * key doesn't already exist in the array. */ - virtual ArrayData *addLval(int64_t k, Variant *&ret, bool copy); - virtual ArrayData *addLval(StringData* k, Variant *&ret, bool copy); + ArrayData *addLval(int64_t k, Variant *&ret, bool copy); + ArrayData *addLval(StringData* k, Variant *&ret, bool copy); /** * Remove a value at specified key. If "copy" is true, make a copy first * then remove the value. Return this if escalation is not needed, or an * escalated array data. */ - virtual ArrayData *remove(int64_t k, bool copy) = 0; - virtual ArrayData *remove(const StringData* k, bool copy) = 0; + ArrayData *remove(int64_t k, bool copy); + ArrayData *remove(const StringData* k, bool copy); /** * Inline accessors that convert keys to StringData* before delegating to @@ -317,10 +328,10 @@ public: ArrayData *remove(CStrRef k, bool copy); ArrayData *remove(CVarRef k, bool copy); - virtual ssize_t iter_begin() const = 0; - virtual ssize_t iter_end() const = 0; - virtual ssize_t iter_advance(ssize_t prev) const = 0; - virtual ssize_t iter_rewind(ssize_t prev) const = 0; + ssize_t iter_begin() const; + ssize_t iter_end() const; + ssize_t iter_advance(ssize_t prev) const; + ssize_t iter_rewind(ssize_t prev) const; /** * Mutable iteration APIs @@ -529,6 +540,35 @@ struct ArrayFunctions { void (*nvGetKey[NK])(const ArrayData*, TypedValue* out, ssize_t pos); ArrayData* (*setInt[NK])(ArrayData*, int64_t k, CVarRef v, bool copy); ArrayData* (*setStr[NK])(ArrayData*, StringData* k, CVarRef v, bool copy); + size_t (*vsize[NK])(const ArrayData*); + CVarRef (*getValueRef[NK])(const ArrayData*, ssize_t pos); + bool noCopyOnWrite[NK]; + bool (*isVectorData[NK])(const ArrayData*); + bool (*existsInt[NK])(const ArrayData*, int64_t k); + bool (*existsStr[NK])(const ArrayData*, const StringData* k); + ArrayData* (*lvalInt[NK])(ArrayData*, int64_t k, Variant*& ret, + bool copy); + ArrayData* (*lvalStr[NK])(ArrayData*, StringData* k, Variant*& ret, + bool copy); + ArrayData* (*lvalNew[NK])(ArrayData*, Variant *&ret, bool copy); + ArrayData* (*createLvalPtr[NK])(ArrayData*, StringData* k, Variant *&ret, + bool copy); + ArrayData* (*getLvalPtr[NK])(ArrayData*, StringData* k, Variant *&ret, + bool copy); + ArrayData* (*setRefInt[NK])(ArrayData*, int64_t k, CVarRef v, bool copy); + ArrayData* (*setRefStr[NK])(ArrayData*, StringData* k, CVarRef v, bool copy); + ArrayData* (*addInt[NK])(ArrayData*, int64_t k, CVarRef v, bool copy); + ArrayData* (*addStr[NK])(ArrayData*, StringData* k, CVarRef v, bool copy); + ArrayData* (*addLvalInt[NK])(ArrayData*, int64_t k, Variant *&ret, + bool copy); + ArrayData* (*addLvalStr[NK])(ArrayData*, StringData* k, Variant *&ret, + bool copy); + ArrayData* (*removeInt[NK])(ArrayData*, int64_t k, bool copy); + ArrayData* (*removeStr[NK])(ArrayData*, const StringData* k, bool copy); + ssize_t (*iterBegin[NK])(const ArrayData*); + ssize_t (*iterEnd[NK])(const ArrayData*); + ssize_t (*iterAdvance[NK])(const ArrayData*, ssize_t pos); + ssize_t (*iterRewind[NK])(const ArrayData*, ssize_t pos); }; extern const ArrayFunctions g_array_funcs; diff --git a/hphp/runtime/base/hphp_array-defs.h b/hphp/runtime/base/hphp_array-defs.h index 594e80321..fbecb3989 100644 --- a/hphp/runtime/base/hphp_array-defs.h +++ b/hphp/runtime/base/hphp_array-defs.h @@ -103,6 +103,20 @@ void HphpArray::getArrayElm(ssize_t pos, TypedValue* valOut, } } +inline HphpArray* HphpArray::asHphpArray(ArrayData* ad) { + assert(ad->isHphpArray()); + auto a = static_cast(ad); + assert(a->checkInvariants()); + return a; +} + +inline const HphpArray* HphpArray::asHphpArray(const ArrayData* ad) { + assert(ad->isHphpArray()); + auto a = static_cast(ad); + assert(a->checkInvariants()); + return a; +} + inline HphpArray* HphpArray::asVector(ArrayData* ad) { assert(ad->kind() == kVectorKind); assert(dynamic_cast(ad)); @@ -119,17 +133,15 @@ inline const HphpArray* HphpArray::asVector(const ArrayData* ad) { return a; } -inline HphpArray* HphpArray::asHphpArray(ArrayData* ad) { +inline HphpArray* HphpArray::asGeneric(ArrayData* ad) { assert(ad->kind() == kMixedKind); - assert(dynamic_cast(ad)); auto a = static_cast(ad); assert(a->checkInvariants()); return a; } -inline const HphpArray* HphpArray::asHphpArray(const ArrayData* ad) { +inline const HphpArray* HphpArray::asGeneric(const ArrayData* ad) { assert(ad->kind() == kMixedKind); - assert(dynamic_cast(ad)); auto a = static_cast(ad); assert(a->checkInvariants()); return a; diff --git a/hphp/runtime/base/hphp_array.cpp b/hphp/runtime/base/hphp_array.cpp index 6538fc39f..c3c0d1d8d 100644 --- a/hphp/runtime/base/hphp_array.cpp +++ b/hphp/runtime/base/hphp_array.cpp @@ -244,7 +244,7 @@ void HphpArray::ReleaseVec(ArrayData* ad) { HOT_FUNC_VM void HphpArray::Release(ArrayData* ad) { - auto a = asHphpArray(ad); + auto a = asGeneric(ad); a->destroy(); if (UNLIKELY(a->strongIterators() != nullptr)) a->freeStrongIterators(); HphpArray::AllocatorType::getNoCheck()->dealloc(a); @@ -345,12 +345,6 @@ bool HphpArray::checkInvariants() const { return true; } -ssize_t HphpArray::vsize() const { - assert(false && "vsize() called, but m_size should " - "never be -1 in HphpArray"); - return m_size; -} - //============================================================================= // Iteration. @@ -365,26 +359,26 @@ inline ssize_t HphpArray::prevElm(Elm* elms, ssize_t ei) const { return (ssize_t)ElmIndEmpty; } -ssize_t HphpArray::iter_begin() const { - assert(checkInvariants()); - return nextElm(m_data, ElmIndEmpty); +ssize_t HphpArray::IterBegin(const ArrayData* ad) { + auto a = asHphpArray(ad); + return a->nextElm(a->m_data, ElmIndEmpty); } -ssize_t HphpArray::iter_end() const { - assert(checkInvariants()); - return prevElm(m_data, m_used); +ssize_t HphpArray::IterEnd(const ArrayData* ad) { + auto a = asHphpArray(ad); + return a->prevElm(a->m_data, a->m_used); } -ssize_t HphpArray::iter_advance(ssize_t pos) const { - assert(checkInvariants()); - assert(ArrayData::invalid_index == -1); +ssize_t HphpArray::IterAdvance(const ArrayData* ad, ssize_t pos) { + auto a = asHphpArray(ad); // Since m_used is always less than 2^32 and invalid_index == -1, // we can save a check by doing an unsigned comparison instead // of a signed comparison. - if (size_t(++pos) < m_used && !isTombstone(m_data[pos].data.m_type)) { + if (size_t(++pos) < a->m_used && !isTombstone(a->m_data[pos].data.m_type)) { return pos; } - return iter_advance_helper(pos); + return a->iter_advance_helper(pos); + static_assert(invalid_index == -1, ""); } // caller has already incremented pos but encountered a tombstone @@ -398,40 +392,43 @@ ssize_t HphpArray::iter_advance_helper(ssize_t next_pos) const { return next_pos; } } - return ArrayData::invalid_index; + return invalid_index; } -ssize_t HphpArray::iter_rewind(ssize_t pos) const { - assert(checkInvariants()); - if (pos == ArrayData::invalid_index) { - return ArrayData::invalid_index; - } - return prevElm(m_data, pos); +ssize_t HphpArray::IterRewind(const ArrayData* ad, ssize_t pos) { + if (pos == invalid_index) return invalid_index; + auto a = asHphpArray(ad); + return a->prevElm(a->m_data, pos); } -CVarRef HphpArray::getValueRef(ssize_t pos) const { - assert(checkInvariants()); +CVarRef HphpArray::GetValueRef(const ArrayData* ad, ssize_t pos) { + auto a = asHphpArray(ad); + assert(a->checkInvariants()); assert(pos != ArrayData::invalid_index); - Elm* e = &m_data[pos]; + Elm* e = &a->m_data[pos]; assert(!isTombstone(e->data.m_type)); return tvAsCVarRef(&e->data); } -bool HphpArray::isVectorData() const { - assert(checkInvariants()); - if (m_size == 0 || isVector()) { +bool HphpArray::IsVectorDataVec(const ArrayData*) { + return true; +} + +bool HphpArray::IsVectorData(const ArrayData* ad) { + auto a = asGeneric(ad); + if (a->m_size == 0) { // any 0-length array is "vector-like" for the sake of this // function, even if m_kind != kVector. return true; } - Elm* elms = m_data; + auto const elms = a->m_data; int64_t i = 0; - for (uint32_t pos = 0, limit = m_used; pos < limit; ++pos) { - Elm* e = &elms[pos]; - if (isTombstone(e->data.m_type)) { + for (uint32_t pos = 0, limit = a->m_used; pos < limit; ++pos) { + auto const& e = elms[pos]; + if (isTombstone(e.data.m_type)) { continue; } - if (e->hasStrKey() || e->ikey != i) { + if (e.hasStrKey() || e.ikey != i) { return false; } ++i; @@ -606,16 +603,24 @@ HphpArray::findForNewInsertLoop(size_t tableMask, size_t h0) const { } } -bool HphpArray::exists(int64_t k) const { - assert(checkInvariants()); - if (isVector()) return size_t(k) < m_size; - return find(k) != ElmIndEmpty; +bool HphpArray::ExistsIntVec(const ArrayData* ad, int64_t k) { + auto a = asVector(ad); + return size_t(k) < a->m_size; } -bool HphpArray::exists(const StringData* k) const { - assert(checkInvariants()); - if (isVector()) return false; - return find(k, k->hash()) != ElmIndEmpty; +bool HphpArray::ExistsInt(const ArrayData* ad, int64_t k) { + auto a = asGeneric(ad); + return a->find(k) != ElmIndEmpty; +} + +bool HphpArray::ExistsStrVec(const ArrayData* ad, const StringData* k) { + assert(asVector(ad)); + return false; +} + +bool HphpArray::ExistsStr(const ArrayData* ad, const StringData* k) { + auto a = asGeneric(ad); + return a->find(k, k->hash()) != ElmIndEmpty; } //============================================================================= @@ -1069,19 +1074,7 @@ ArrayData* HphpArray::update(StringData* key, CVarRef data) { } ArrayData* HphpArray::updateRef(int64_t ki, CVarRef data) { - if (isVector()) { - if (size_t(ki) < m_size) { - tvAsVariant(&m_data[ki].data).assignRefHelper(data); - return this; - } - if (size_t(ki) == m_size) { - auto& tv = allocNextElm(ki); - tvAsUninitializedVariant(&tv).constructRefHelper(data); - return this; - } - vectorToGeneric(); - // todo t2606310: key can't exist. use add/findForNewInsert - } + assert(!isVector()); ElmInd* ei = findForInsert(ki); if (validElmInd(*ei)) { Elm* e = &m_data[*ei]; @@ -1096,10 +1089,7 @@ ArrayData* HphpArray::updateRef(int64_t ki, CVarRef data) { } ArrayData* HphpArray::updateRef(StringData* key, CVarRef data) { - if (isVector()) { - vectorToGeneric(); - // todo t2606310: key can't exist. use add/findForNewInsert - } + assert(!isVector()); strhash_t h = key->hash(); ElmInd* ei = findForInsert(key, h); if (validElmInd(*ei)) { @@ -1111,44 +1101,90 @@ ArrayData* HphpArray::updateRef(StringData* key, CVarRef data) { return this; } -ArrayData* HphpArray::lval(int64_t k, Variant*& ret, bool copy) { - assert(checkInvariants()); - return (!copy ? this : copyImpl())->addLvalImpl(k, &ret); +// return true if Elm contains a Reference that won't be flattened +// by a copy, or an object. +static inline bool isContainer(const TypedValue& tv) { + auto& v = tvAsCVarRef(&tv); + return v.isReferenced() || v.isObject(); } -ArrayData* HphpArray::lval(StringData* key, Variant*& ret, bool copy) { - assert(checkInvariants()); - return (!copy ? this : copyImpl())->addLvalImpl(key, key->hash(), &ret); +ArrayData* HphpArray::LvalIntVec(ArrayData* ad, int64_t k, Variant*& ret, + bool copy) { + auto a = asVector(ad); + return (!copy ? a : a->copyImpl())->addLvalImpl(k, &ret); } -ArrayData *HphpArray::createLvalPtr(StringData* key, Variant*& ret, bool copy) { - assert(checkInvariants()); - HphpArray* a = !copy ? this : copyImpl(); +ArrayData* HphpArray::LvalInt(ArrayData* ad, int64_t k, Variant*& ret, + bool copy) { + auto a = asGeneric(ad); + return (!copy ? a : a->copyImpl())->addLvalImpl(k, &ret); +} + +ArrayData* HphpArray::LvalStrVec(ArrayData* ad, StringData* key, Variant*& ret, + bool copy) { + auto a = asVector(ad); + return (!copy ? a : a->copyImpl())->addLvalImpl(key, key->hash(), &ret); +} + +ArrayData* HphpArray::LvalStr(ArrayData* ad, StringData* key, Variant*& ret, + bool copy) { + auto a = asGeneric(ad); + return (!copy ? a : a->copyImpl())->addLvalImpl(key, key->hash(), &ret); +} + +ArrayData *HphpArray::CreateLvalPtrVec(ArrayData* ad, StringData* key, + Variant*& ret, bool copy) { + auto a = asVector(ad); + if (copy) a = a->copyVec(); + return a->vectorToGeneric()->addLvalImpl(key, key->hash(), &ret); + // todo: we know the key can't exist; use specialized addLvalImpl +} + +ArrayData *HphpArray::CreateLvalPtr(ArrayData* ad, StringData* key, + Variant*& ret, bool copy) { + auto a = asGeneric(ad); + if (copy) a = a->copyGeneric(); return a->addLvalImpl(key, key->hash(), &ret); } -ArrayData *HphpArray::getLvalPtr(StringData* key, Variant*& ret, bool copy) { - assert(checkInvariants()); - HphpArray* a = !copy ? this : copyImpl(); - auto pos = a->find(key, key->hash()); - if (pos != ElmIndEmpty) { - Elm* e = &a->m_data[pos]; - ret = &tvAsVariant(&e->data); - } else { - ret = nullptr; - } +ArrayData *HphpArray::GetLvalPtrVec(ArrayData* ad, StringData* key, + Variant*& ret, bool copy) { + auto a = asVector(ad); + if (copy) a = a->copyVec(); + // todo: we didn't have to copy since we didn't mutate. Or, should + // we have just escalate to generic anyway? and, why isn't this + // method const? + ret = nullptr; return a; } -ArrayData* HphpArray::lvalNew(Variant*& ret, bool copy) { - assert(checkInvariants()); - TypedValue* tv; - ArrayData* a = nvNew(tv, copy); - if (tv == nullptr) { - ret = &(Variant::lvalBlackHole()); - } else { - ret = &tvAsVariant(tv); +ArrayData *HphpArray::GetLvalPtr(ArrayData* ad, StringData* key, + Variant*& ret, bool copy) { + auto a = asGeneric(ad); + if (copy) a = a->copyGeneric(); + auto pos = a->find(key, key->hash()); + ret = pos != ElmIndEmpty ? &tvAsVariant(&a->m_data[pos].data) : + nullptr; + return a; +} + +ArrayData* HphpArray::LvalNewVec(ArrayData* ad, Variant*& ret, bool copy) { + auto a = asVector(ad); + if (copy) a = a->copyVec(); + auto& tv = a->allocNextElm(a->m_size); + tvWriteUninit(&tv); + ret = &tvAsVariant(&tv); + return a; +} + +ArrayData* HphpArray::LvalNew(ArrayData* ad, Variant*& ret, bool copy) { + auto a = asGeneric(ad); + if (copy) a = a->copyGeneric(); + if (UNLIKELY(!a->nextInsert(uninit_null()))) { + ret = &Variant::lvalBlackHole(); + return a; } + ret = &tvAsVariant(&a->m_data[a->m_used - 1].data); return a; } @@ -1170,7 +1206,7 @@ HphpArray::SetIntVec(ArrayData* ad, int64_t k, CVarRef v, bool copy) { } ArrayData* HphpArray::SetInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) { - auto a = asHphpArray(ad); + auto a = asGeneric(ad); if (copy) a = a->copyGeneric(); return a->update(k, v); } @@ -1185,58 +1221,127 @@ HphpArray::SetStrVec(ArrayData* ad, StringData* k, CVarRef v, bool copy) { ArrayData* HphpArray::SetStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) { - auto a = asHphpArray(ad); + auto a = asGeneric(ad); if (copy) a = a->copyGeneric(); return a->update(k, v); } -ArrayData* HphpArray::setRef(int64_t k, CVarRef v, bool copy) { - assert(checkInvariants()); - HphpArray* a = !copy ? this : copyImpl(); - return a->updateRef(k, v); -} - -ArrayData* HphpArray::setRef(StringData* k, CVarRef v, bool copy) { - assert(checkInvariants()); - HphpArray* a = !copy ? this : copyImpl(); - return a->updateRef(k, v); -} - -ArrayData* HphpArray::add(int64_t k, CVarRef v, bool copy) { - assert(checkInvariants()); - assert(!exists(k)); - HphpArray* a = !copy ? this : copyImpl(); - if (a->isVector()) { - if (size_t(k) == a->m_size) { - auto& tv = a->allocNextElm(k); - elemConstruct((TypedValue*)&v, &tv); - return a; - } - a->vectorToGeneric(); +ArrayData* +HphpArray::SetRefIntVec(ArrayData* ad, int64_t k, CVarRef v, bool copy) { + auto a = asVector(ad); + if (copy) a = a->copyVec(); + if (size_t(k) < a->m_size) { + tvAsVariant(&a->m_data[k].data).assignRefHelper(v); + return a; } + if (size_t(k) == a->m_size) { + auto& tv = a->allocNextElm(k); + tvAsUninitializedVariant(&tv).constructRefHelper(v); + return a; + } + // todo t2606310: key can't exist. use add/findForNewInsert + return a->vectorToGeneric()->updateRef(k, v); +} + +ArrayData* +HphpArray::SetRefInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) { + auto a = asGeneric(ad); + if (copy) a = a->copyGeneric(); + return a->updateRef(k, v); +} + +ArrayData* +HphpArray::SetRefStrVec(ArrayData* ad, StringData* k, CVarRef v, bool copy) { + auto a = asVector(ad); + if (copy) a = a->copyVec(); + return a->vectorToGeneric()->updateRef(k, v); +} + +ArrayData* +HphpArray::SetRefStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) { + auto a = asGeneric(ad); + if (copy) a = a->copyVec(); + // todo t2606310: key can't exist. use add/findForNewInsert + return a->updateRef(k, v); +} + +ArrayData* +HphpArray::AddIntVec(ArrayData* ad, int64_t k, CVarRef v, bool copy) { + assert(!ad->exists(k)); + auto a = asVector(ad); + if (copy) a = a->copyVec(); + if (size_t(k) == a->m_size) { + auto& tv = a->allocNextElm(k); + elemConstruct((TypedValue*)&v, &tv); + return a; + } + return a->vectorToGeneric()->addVal(k, v); +} + +ArrayData* +HphpArray::AddInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) { + assert(!ad->exists(k)); + auto a = asGeneric(ad); + if (copy) a = a->copyGeneric(); return a->addVal(k, v); } -ArrayData* HphpArray::add(StringData* k, CVarRef v, bool copy) { - assert(checkInvariants()); - assert(!exists(k)); - HphpArray* a = !copy ? this : copyImpl(); - if (a->isVector()) a->vectorToGeneric(); +ArrayData* +HphpArray::AddStrVec(ArrayData* ad, StringData* k, CVarRef v, bool copy) { + assert(!ad->exists(k)); + auto a = asVector(ad); + if (copy) a = a->copyVec(); + return a->vectorToGeneric()->addVal(k, v); +} + +ArrayData* +HphpArray::AddStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) { + assert(!ad->exists(k)); + auto a = asGeneric(ad); + if (copy) a = a->copyGeneric(); return a->addVal(k, v); } -ArrayData* HphpArray::addLval(int64_t k, Variant*& ret, bool copy) { - assert(checkInvariants()); - assert(!exists(k)); - HphpArray* a = !copy ? this : copyImpl(); +ArrayData* +HphpArray::AddLvalIntVec(ArrayData* ad, int64_t k, Variant*& ret, bool copy) { + assert(!ad->exists(k)); + auto a = asVector(ad); + if (copy) a = a->copyVec(); + if (size_t(k) < a->m_size) { + ret = &tvAsVariant(&a->m_data[k].data); + return a; + } + if (size_t(k) == a->m_size) { + auto& tv = a->allocNextElm(k); + tvWriteNull(&tv); + ret = &(tvAsVariant(&tv)); + return a; + } + return a->vectorToGeneric()->addLvalImpl(k, &ret); +} + +ArrayData* +HphpArray::AddLvalInt(ArrayData* ad, int64_t k, Variant*& ret, bool copy) { + assert(!ad->exists(k)); + auto a = asGeneric(ad); + if (copy) a = a->copyGeneric(); return a->addLvalImpl(k, &ret); } -ArrayData* HphpArray::addLval(StringData* k, Variant*& ret, bool copy) { - assert(checkInvariants()); - assert(!exists(k)); - HphpArray* a = !copy ? this : copyImpl(); - if (a->isVector()) a->vectorToGeneric(); +ArrayData* +HphpArray::AddLvalStrVec(ArrayData* ad, StringData* k, Variant*& ret, + bool copy) { + assert(!ad->exists(k)); + auto a = asVector(ad); + if (copy) a = a->copyVec(); + return a->vectorToGeneric()->addLvalImpl(k, k->hash(), &ret); +} + +ArrayData* +HphpArray::AddLvalStr(ArrayData* ad, StringData* k, Variant*& ret, bool copy) { + assert(!ad->exists(k)); + auto a = asGeneric(ad); + if (copy) a = a->copyVec(); return a->addLvalImpl(k, k->hash(), &ret); } @@ -1319,20 +1424,34 @@ ArrayData* HphpArray::erase(ElmInd* ei, bool updateNext /* = false */) { return this; } -ArrayData* HphpArray::remove(int64_t k, bool copy) { - assert(checkInvariants()); - HphpArray* a = !copy ? this : copyImpl(); - if (a->isVector()) { - // todo t2606310: what is probability of (k == size-1) +ArrayData* HphpArray::RemoveIntVec(ArrayData* ad, int64_t k, bool copy) { + auto a = asVector(ad); + if (copy) a = a->copyImpl(); + // todo t2606310: what is probability of (k == size-1) + if (size_t(k) < a->m_size) { a->vectorToGeneric(); + return a->erase(a->findForInsert(k)); } + return a; // key didn't exist, so we're still vector +} + +ArrayData* HphpArray::RemoveInt(ArrayData* ad, int64_t k, bool copy) { + auto a = asGeneric(ad); + if (copy) a = a->copyImpl(); return a->erase(a->findForInsert(k)); } -ArrayData* HphpArray::remove(const StringData* key, bool copy) { - assert(checkInvariants()); - HphpArray* a = !copy ? this : copyImpl(); - if (a->isVector()) return a; // since key cannot exist +ArrayData* +HphpArray::RemoveStrVec(ArrayData* ad, const StringData* key, bool copy) { + auto a = asVector(ad); + if (copy) a = a->copyImpl(); + return a; +} + +ArrayData* +HphpArray::RemoveStr(ArrayData* ad, const StringData* key, bool copy) { + auto a = asGeneric(ad); + if (copy) a = a->copyImpl(); return a->erase(a->findForInsert(key, key->hash())); } @@ -1357,7 +1476,7 @@ TypedValue* HphpArray::NvGetIntVec(const ArrayData* ad, int64_t ki) { } TypedValue* HphpArray::NvGetInt(const ArrayData* ad, int64_t ki) { - auto a = asHphpArray(ad); + auto a = asGeneric(ad); auto i = a->find(ki); return LIKELY(i != ElmIndEmpty) ? &a->m_data[i].data : nullptr; } @@ -1368,7 +1487,7 @@ TypedValue* HphpArray::NvGetStrVec(const ArrayData* ad, const StringData* k) { } TypedValue* HphpArray::NvGetStr(const ArrayData* ad, const StringData* k) { - auto a = asHphpArray(ad); + auto a = asGeneric(ad); auto i = a->find(k, k->hash()); if (LIKELY(i != ElmIndEmpty)) { return &a->m_data[i].data; @@ -1376,24 +1495,6 @@ TypedValue* HphpArray::NvGetStr(const ArrayData* ad, const StringData* k) { return nullptr; } -ArrayData* HphpArray::nvNew(TypedValue*& ret, bool copy) { - assert(checkInvariants()); - HphpArray* a = !copy ? this : copyImpl(); - if (a->isVector()) { - auto& tv = a->allocNextElm(a->m_size); - tv.m_type = KindOfUninit; - ret = &tv; - return a; - } - if (UNLIKELY(!a->nextInsert(uninit_null()))) { - ret = nullptr; - return a; - } - assert(a->m_used > 0); - ret = &a->m_data[a->m_used - 1].data; - return a; -} - // nvGetKey does not touch out->_count, so can be used // for inner or outer cells. void HphpArray::NvGetKeyVec(const ArrayData* ad, TypedValue* out, ssize_t pos) { @@ -1405,7 +1506,7 @@ void HphpArray::NvGetKeyVec(const ArrayData* ad, TypedValue* out, ssize_t pos) { } void HphpArray::NvGetKey(const ArrayData* ad, TypedValue* out, ssize_t pos) { - auto a = asHphpArray(ad); + auto a = asGeneric(ad); assert(pos != ArrayData::invalid_index); assert(!isTombstone(a->m_data[pos].data.m_type)); getElmKey(a->m_data[pos], out); @@ -1444,7 +1545,7 @@ ArrayData* HphpArray::AppendVec(ArrayData* ad, CVarRef v, bool copy) { } ArrayData* HphpArray::Append(ArrayData* ad, CVarRef v, bool copy) { - auto a = asHphpArray(ad); + auto a = asGeneric(ad); if (copy) a = a->copyGeneric(); a->nextInsert(v); return a; @@ -1557,7 +1658,7 @@ ArrayData* HphpArray::pop(Variant& value) { assert(checkInvariants()); HphpArray* a = getCount() <= 1 ? this : copyImpl(); Elm* elms = a->m_data; - ElmInd pos = a->HphpArray::iter_end(); + ElmInd pos = IterEnd(a); if (validElmInd(pos)) { Elm* e = &elms[pos]; assert(!isTombstone(e->data.m_type)); diff --git a/hphp/runtime/base/hphp_array.h b/hphp/runtime/base/hphp_array.h index 852d3589b..08ec88a5b 100644 --- a/hphp/runtime/base/hphp_array.h +++ b/hphp/runtime/base/hphp_array.h @@ -57,6 +57,8 @@ private: // Safe downcast helpers static HphpArray* asVector(ArrayData* ad); static const HphpArray* asVector(const ArrayData* ad); + static HphpArray* asGeneric(ArrayData* ad); + static const HphpArray* asGeneric(const ArrayData* ad); static HphpArray* asHphpArray(ArrayData* ad); static const HphpArray* asHphpArray(const ArrayData* ad); @@ -72,13 +74,6 @@ public: void destroyVec(); void destroy(); - // unlike ArrayData::size(), this functions doesn't delegate - // to the virtual vsize() functions, so its more efficient to - // use this when you know you have an HphpArray. - ssize_t getSize() const { - return m_size; - } - // This behaves the same as iter_begin except that it assumes // this array is not empty and its not virtual. ssize_t getIterBegin() const { @@ -107,28 +102,43 @@ public: using ArrayData::nvGet; // implements ArrayData - ssize_t vsize() const; - CVarRef getValueRef(ssize_t pos) const; + static CVarRef GetValueRef(const ArrayData*, ssize_t pos); // overrides ArrayData - bool isVectorData() const; - ssize_t iter_begin() const; - ssize_t iter_end() const; - ssize_t iter_advance(ssize_t prev) const; - ssize_t iter_rewind(ssize_t prev) const; + static bool IsVectorData(const ArrayData*); + static bool IsVectorDataVec(const ArrayData*); + static ssize_t IterBegin(const ArrayData*); + static ssize_t IterEnd(const ArrayData*); + static ssize_t IterAdvance(const ArrayData*, ssize_t pos); + static ssize_t IterRewind(const ArrayData*, ssize_t pos); // implements ArrayData - bool exists(int64_t k) const; - bool exists(const StringData* k) const; + static bool ExistsInt(const ArrayData*, int64_t k); + static bool ExistsStr(const ArrayData*, const StringData* k); + static bool ExistsIntVec(const ArrayData*, int64_t k); + static bool ExistsStrVec(const ArrayData*, const StringData* k); // implements ArrayData - ArrayData* lval(int64_t k, Variant*& ret, bool copy); - ArrayData* lval(StringData* k, Variant*& ret, bool copy); - ArrayData* lvalNew(Variant*& ret, bool copy); + static ArrayData* LvalInt(ArrayData* ad, int64_t k, Variant*& ret, + bool copy); + static ArrayData* LvalStr(ArrayData* ad, StringData* k, Variant*& ret, + bool copy); + static ArrayData* LvalIntVec(ArrayData* ad, int64_t k, Variant*& ret, + bool copy); + static ArrayData* LvalStrVec(ArrayData* ad, StringData* k, Variant*& ret, + bool copy); + static ArrayData* LvalNew(ArrayData*, Variant*& ret, bool copy); + static ArrayData* LvalNewVec(ArrayData*, Variant*& ret, bool copy); // overrides ArrayData - ArrayData* createLvalPtr(StringData* k, Variant*& ret, bool copy); - ArrayData* getLvalPtr(StringData* k, Variant*& ret, bool copy); + static ArrayData* CreateLvalPtr(ArrayData*, StringData* k, Variant*& ret, + bool copy); + static ArrayData* GetLvalPtr(ArrayData*, StringData* k, Variant*& ret, + bool copy); + static ArrayData* CreateLvalPtrVec(ArrayData*, StringData* k, Variant*& ret, + bool copy); + static ArrayData* GetLvalPtrVec(ArrayData*, StringData* k, Variant*& ret, + bool copy); // implements ArrayData static ArrayData* SetIntVec(ArrayData*, int64_t k, CVarRef v, bool copy); @@ -137,18 +147,35 @@ public: static ArrayData* SetStr(ArrayData*, StringData* k, CVarRef v, bool copy); // implements ArrayData - ArrayData* setRef(int64_t k, CVarRef v, bool copy); - ArrayData* setRef(StringData* k, CVarRef v, bool copy); + static ArrayData* SetRefInt(ArrayData* ad, int64_t k, CVarRef v, + bool copy); + static ArrayData* SetRefStr(ArrayData* ad, StringData* k, CVarRef v, + bool copy); + static ArrayData* SetRefIntVec(ArrayData* ad, int64_t k, CVarRef v, + bool copy); + static ArrayData* SetRefStrVec(ArrayData* ad, StringData* k, CVarRef v, + bool copy); // overrides ArrayData - ArrayData *add(int64_t k, CVarRef v, bool copy); - ArrayData *add(StringData* k, CVarRef v, bool copy); - ArrayData *addLval(int64_t k, Variant*& ret, bool copy); - ArrayData *addLval(StringData* k, Variant*& ret, bool copy); + static ArrayData* AddInt(ArrayData*, int64_t k, CVarRef v, bool copy); + static ArrayData* AddStr(ArrayData*, StringData* k, CVarRef v, bool copy); + static ArrayData* AddIntVec(ArrayData*, int64_t k, CVarRef v, bool copy); + static ArrayData* AddStrVec(ArrayData*, StringData* k, CVarRef v, bool copy); + + static ArrayData* AddLvalInt(ArrayData*, int64_t k, Variant*& ret, + bool copy); + static ArrayData* AddLvalStr(ArrayData*, StringData* k, Variant*& ret, + bool copy); + static ArrayData* AddLvalIntVec(ArrayData*, int64_t k, Variant*& ret, + bool copy); + static ArrayData* AddLvalStrVec(ArrayData*, StringData* k, Variant*& ret, + bool copy); // implements ArrayData - ArrayData* remove(int64_t k, bool copy); - ArrayData* remove(const StringData* k, bool copy); + static ArrayData* RemoveInt(ArrayData*, int64_t k, bool copy); + static ArrayData* RemoveStr(ArrayData*, const StringData* k, bool copy); + static ArrayData* RemoveIntVec(ArrayData*, int64_t k, bool copy); + static ArrayData* RemoveStrVec(ArrayData*, const StringData* k, bool copy); // overrides/implements ArrayData ArrayData* copy() const; @@ -189,16 +216,15 @@ public: static TypedValue* NvGetStrVec(const ArrayData*, const StringData* k); static TypedValue* NvGetStr(const ArrayData*, const StringData* k); - void nvBind(int64_t ki, const TypedValue* v) { - updateRef(ki, tvAsCVarRef(v)); + void nvBind(int64_t k, const TypedValue* v) { + ArrayData::setRef(k, tvAsCVarRef(v), false); } void nvBind(StringData* k, const TypedValue* v) { - updateRef(k, tvAsCVarRef(v)); + ArrayData::setRef(k, tvAsCVarRef(v), false); } void nvAppend(const TypedValue* v) { nextInsertVec(tvAsCVarRef(v)); } - ArrayData* nvNew(TypedValue*& v, bool copy); static void NvGetKeyVec(const ArrayData*, TypedValue* out, ssize_t pos); static void NvGetKey(const ArrayData*, TypedValue* out, ssize_t pos); bool nvInsert(StringData* k, TypedValue *v); diff --git a/hphp/runtime/base/policy_array.cpp b/hphp/runtime/base/policy_array.cpp index 14c5add9b..d1c27892a 100644 --- a/hphp/runtime/base/policy_array.cpp +++ b/hphp/runtime/base/policy_array.cpp @@ -227,20 +227,32 @@ inline const PolicyArray* PolicyArray::asPolicyArray(const ArrayData* ad) { return static_cast(ad); } -const Variant& PolicyArray::getValueRef(ssize_t pos) const { - APILOG(this) << "(" << pos << ")"; - assert(size_t(pos) < m_size); - return val(toPos(pos)); +const Variant& PolicyArray::GetValueRef(const ArrayData* ad, ssize_t pos) { + auto a = asPolicyArray(ad); + APILOG(a) << "(" << pos << ")"; + assert(size_t(pos) < a->m_size); + return a->val(toPos(pos)); } -bool PolicyArray::isVectorData() const { - APILOG(this) << "()"; - for (ssize_t i = 0; i < m_size; ++i) { - if (Store::find(i, m_size) != toPos(i)) return false; +bool PolicyArray::IsVectorData(const ArrayData* ad) { + auto a = asPolicyArray(ad); + APILOG(a) << "()"; + for (ssize_t i = 0; i < a->m_size; ++i) { + if (a->Store::find(i, a->m_size) != toPos(i)) return false; } return true; } +bool PolicyArray::ExistsInt(const ArrayData* ad, int64_t k) { + auto a = asPolicyArray(ad); + return a->Store::find(k, a->m_size) < toPos(a->m_size); +} + +bool PolicyArray::ExistsStr(const ArrayData* ad, const StringData* k) { + auto a = asPolicyArray(ad); + return a->Store::find(k, a->m_size) < toPos(a->m_size); +} + static_assert(ArrayData::invalid_index == size_t(-1), "ehm"); template @@ -295,41 +307,53 @@ ArrayData *PolicyArray::lvalImpl(K k, Variant*& ret, bool copy) { return this; } -ArrayData *PolicyArray::lvalNew(Variant *&ret, bool copy) { - if (copy) { - return PolicyArray::copy()->lvalNew(ret, false); - } +ArrayData* PolicyArray::LvalInt(ArrayData* ad, int64_t k, Variant *&ret, + bool copy) { + return asPolicyArray(ad)->lvalImpl(k, ret, copy); +} + +ArrayData* PolicyArray::LvalStr(ArrayData* ad, StringData* k, Variant*& ret, + bool copy) { + return asPolicyArray(ad)->lvalImpl(k, ret, copy); +} + +ArrayData *PolicyArray::LvalNew(ArrayData* ad, Variant *&ret, bool copy) { + auto a = asPolicyArray(ad); + if (copy) a = a->PolicyArray::copy(); // Andrei: TODO - append() currently never fails, probably it // should. - auto oldSize = m_size; - append(uninit_null(), false); - assert(m_size == oldSize + 1); - if (UNLIKELY(oldSize == m_size)) { + auto oldSize = a->m_size; + a->append(uninit_null(), false); + assert(a->m_size == oldSize + 1); + if (UNLIKELY(oldSize == a->m_size)) { ret = &Variant::lvalBlackHole(); } else { - assert(lastIndex(m_size) != PosType::invalid); - ret = &lval(lastIndex(m_size)); + assert(a->lastIndex(a->m_size) != PosType::invalid); + ret = &a->lval(a->lastIndex(a->m_size)); } - - return this; + return a; } -ArrayData *PolicyArray::createLvalPtr(StringData* k, Variant *&ret, bool copy) { - APILOG(this) << "(" << keystr(k) << ", " << ret << ", " << copy << ")"; - return addLval(k, ret, copy); +ArrayData *PolicyArray::CreateLvalPtr(ArrayData* ad, StringData* k, + Variant *&ret, bool copy) { + auto a = asPolicyArray(ad); + APILOG(a) << "(" << keystr(k) << ", " << ret << ", " << copy << ")"; + return a->addLval(k, ret, copy); } -ArrayData *PolicyArray::getLvalPtr(StringData* k, Variant *&ret, bool copy) { - APILOG(this) << "(" << keystr(k) << ", " << ret << ", " << copy << ")"; +ArrayData *PolicyArray::GetLvalPtr(ArrayData* ad, StringData* k, + Variant *&ret, bool copy) { + auto a = asPolicyArray(ad); + APILOG(a) << "(" << keystr(k) << ", " << ret << ", " << copy << ")"; if (copy) { - return PolicyArray::copy()->getLvalPtr(k, ret, false); + return a->PolicyArray::copy()->getLvalPtr(k, ret, false); } - const auto pos = find(k, m_size); + const auto pos = a->find(k, a->m_size); ret = pos != PosType::invalid - ? &Store::lval(pos) + ? &a->Store::lval(pos) : nullptr; - return this; + return a; } template @@ -381,6 +405,16 @@ ArrayData *PolicyArray::setRefImpl(K k, CVarRef v, bool copy) { return this; } +ArrayData* +PolicyArray::SetRefInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) { + return asPolicyArray(ad)->setRefImpl(k, v, copy); +} + +ArrayData* +PolicyArray::SetRefStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) { + return asPolicyArray(ad)->setRefImpl(k, v, copy); +} + template ArrayData *PolicyArray::addImpl(K k, const Variant& v, bool copy) { APILOG(this) << "(" << keystr(k) << ", " << valstr(v) << ", " << copy << ");"; @@ -398,8 +432,18 @@ ArrayData *PolicyArray::addImpl(K k, const Variant& v, bool copy) { return this; } +ArrayData* +PolicyArray::AddInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) { + return asPolicyArray(ad)->addImpl(k, v, copy); +} + +ArrayData* +PolicyArray::AddStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) { + return asPolicyArray(ad)->addImpl(k, v, copy); +} + template -PolicyArray *PolicyArray::addLvalImpl(K k, Variant*& ret, bool copy) { +ArrayData* PolicyArray::addLvalImpl(K k, Variant*& ret, bool copy) { APILOG(this) << "(" << k << ", " << ret << ", " << copy << ")"; if (copy) { return PolicyArray::copy()->addLval(k, ret, false); @@ -413,6 +457,16 @@ PolicyArray *PolicyArray::addLvalImpl(K k, Variant*& ret, bool copy) { return this; } +ArrayData* PolicyArray::AddLvalInt(ArrayData* ad, int64_t k, + Variant *&ret, bool copy) { + return asPolicyArray(ad)->addLvalImpl(k, ret, copy); +} + +ArrayData* PolicyArray::AddLvalStr(ArrayData* ad, StringData* k, + Variant *&ret, bool copy) { + return asPolicyArray(ad)->addLvalImpl(k, ret, copy); +} + template ArrayData *PolicyArray::removeImpl(K k, bool copy) { APILOG(this) << "(" << keystr(k) << ", " << copy << ")"; @@ -451,26 +505,40 @@ ArrayData *PolicyArray::removeImpl(K k, bool copy) { return this; } -ssize_t PolicyArray::iter_begin() const { - APILOG(this) << "()"; - return m_size ? toInt(firstIndex(m_size)) : invalid_index; +ArrayData* +PolicyArray::RemoveInt(ArrayData* ad, int64_t k, bool copy) { + return asPolicyArray(ad)->removeImpl(k, copy); } -ssize_t PolicyArray::iter_end() const { - APILOG(this) << "()"; - return ssize_t(lastIndex(m_size)); +ArrayData* +PolicyArray::RemoveStr(ArrayData* ad, const StringData* k, bool copy) { + return asPolicyArray(ad)->removeImpl(k, copy); } -ssize_t PolicyArray::iter_advance(ssize_t prev) const { - APILOG(this) << "(" << prev << ")"; - auto const result = toInt(nextIndex(toPos(prev), m_size)); +ssize_t PolicyArray::IterBegin(const ArrayData* ad) { + auto a = asPolicyArray(ad); + APILOG(a) << "()"; + return a->m_size ? toInt(a->firstIndex(a->m_size)) : invalid_index; +} + +ssize_t PolicyArray::IterEnd(const ArrayData* ad) { + auto a = asPolicyArray(ad); + APILOG(a) << "()"; + return ssize_t(a->lastIndex(a->m_size)); +} + +ssize_t PolicyArray::IterAdvance(const ArrayData* ad, ssize_t prev) { + auto a = asPolicyArray(ad); + APILOG(a) << "(" << prev << ")"; + auto const result = toInt(a->nextIndex(toPos(prev), a->m_size)); MYLOG << "returning " << result; return result; } -ssize_t PolicyArray::iter_rewind(ssize_t prev) const { - APILOG(this) << "(" << prev << ")"; - return toInt(prevIndex(toPos(prev), m_size)); +ssize_t PolicyArray::IterRewind(const ArrayData* ad, ssize_t prev) { + auto a = asPolicyArray(ad); + APILOG(a) << "(" << prev << ")"; + return toInt(a->prevIndex(toPos(prev), a->m_size)); } bool PolicyArray::validFullPos(const FullPos& fp) const { @@ -659,7 +727,7 @@ ArrayData *PolicyArray::merge(const ArrayData *elems, bool copy) { StringData *s = key.getStringData(); Variant *p; // Andrei TODO: make sure this is the right semantics - lval(s, p, false); + LvalStr(this, s, p, false); p->setWithRef(value); } } diff --git a/hphp/runtime/base/policy_array.h b/hphp/runtime/base/policy_array.h index b017a111b..c8fd708d1 100644 --- a/hphp/runtime/base/policy_array.h +++ b/hphp/runtime/base/policy_array.h @@ -331,35 +331,22 @@ public: virtual ~PolicyArray() FOLLY_OVERRIDE; - /** - * Number of elements this array has. - */ - virtual ssize_t vsize() const FOLLY_OVERRIDE { - // vsize() called, but m_size should never be -1 in PolicyArray - assert(false); - return m_size; - } - /** * getValueRef() gets a reference to value at position "pos". */ - virtual CVarRef getValueRef(ssize_t pos) const FOLLY_OVERRIDE; + static CVarRef GetValueRef(const ArrayData*, ssize_t pos); /* * Returns whether or not this array contains "vector-like" data. * I.e. all the keys are contiguous increasing integers. */ - virtual bool isVectorData() const FOLLY_OVERRIDE; + static bool IsVectorData(const ArrayData*); /** * Testing whether a key exists. */ - virtual bool exists(int64_t k) const FOLLY_OVERRIDE { - return Store::find(k, m_size) < toPos(m_size); - } - virtual bool exists(const StringData* k) const FOLLY_OVERRIDE { - return Store::find(k, m_size) < toPos(m_size); - } + static bool ExistsInt(const ArrayData*, int64_t k); + static bool ExistsStr(const ArrayData*, const StringData* k); private: template TypedValue* nvGetImpl(K k) const; @@ -384,16 +371,10 @@ public: * Getting l-value (that Variant pointer) at specified key. Return NULL if * escalation is not needed, or an escalated array data. */ - virtual ArrayData *lval(int64_t k, - Variant *&ret, - bool copy) FOLLY_OVERRIDE { - return lvalImpl(k, ret, copy); - } - virtual ArrayData *lval(StringData* k, - Variant*& ret, - bool copy) FOLLY_OVERRIDE { - return lvalImpl(k, ret, copy); - } + static ArrayData* LvalInt(ArrayData* ad, int64_t k, Variant *&ret, + bool copy); + static ArrayData* LvalStr(ArrayData* ad, StringData* k, Variant*& ret, + bool copy); /** * Getting l-value (that Variant pointer) of a new element with the next @@ -402,17 +383,17 @@ public: * available integer key may fail, in which case ret is set to point to * the lval blackhole (see Variant::lvalBlackHole() for details). */ - virtual ArrayData *lvalNew(Variant *&ret, bool copy) FOLLY_OVERRIDE; + static ArrayData *LvalNew(ArrayData* ad, Variant *&ret, bool copy); /** * Helper functions used for getting a reference to elements of * the dynamic property array in ObjectData or the local cache array * in ShardMap. */ - virtual ArrayData *createLvalPtr(StringData* k, Variant *&ret, bool copy) - FOLLY_OVERRIDE; - virtual ArrayData *getLvalPtr(StringData* k, Variant *&ret, bool copy) - FOLLY_OVERRIDE; + static ArrayData *CreateLvalPtr(ArrayData*, StringData* k, Variant *&ret, + bool copy); + static ArrayData *GetLvalPtr(ArrayData*, StringData* k, Variant *&ret, + bool copy); /** * Setting a value at specified key. If "copy" is true, make a copy first @@ -432,12 +413,9 @@ private: ArrayData *setRefImpl(K k, CVarRef v, bool copy); public: - virtual ArrayData *setRef(int64_t k, CVarRef v, bool copy) FOLLY_OVERRIDE { - return setRefImpl(k, v, copy); - } - virtual ArrayData *setRef(StringData* k, CVarRef v, bool cpy) FOLLY_OVERRIDE { - return setRefImpl(k, v, cpy); - } + static ArrayData* SetRefInt(ArrayData* ad, int64_t k, CVarRef v, bool copy); + static ArrayData* SetRefStr(ArrayData* ad, StringData* k, CVarRef v, + bool cpy); /** * The same as set(), but with the precondition that the key does @@ -446,15 +424,11 @@ public: */ private: template - ArrayData *addImpl(K k, CVarRef v, bool copy); + ArrayData* addImpl(K k, CVarRef v, bool copy); public: - virtual ArrayData *add(int64_t k, CVarRef v, bool copy) FOLLY_OVERRIDE { - return addImpl(k, v, copy); - } - virtual ArrayData *add(StringData* k, CVarRef v, bool copy) FOLLY_OVERRIDE { - return addImpl(k, v, copy); - } + static ArrayData* AddInt(ArrayData*, int64_t k, CVarRef v, bool copy); + static ArrayData* AddStr(ArrayData*, StringData* k, CVarRef v, bool copy); /* * Same semantics as lval(), except with the precondition that the @@ -462,17 +436,13 @@ public: */ private: template - PolicyArray* addLvalImpl(K k, Variant*& ret, bool copy); + ArrayData* addLvalImpl(K k, Variant*& ret, bool copy); public: - virtual PolicyArray *addLval(int64_t k, Variant *&ret, bool copy) - FOLLY_OVERRIDE { - return addLvalImpl(k, ret, copy); - } - virtual PolicyArray *addLval(StringData* k, Variant *&ret, bool copy) - FOLLY_OVERRIDE { - return addLvalImpl(k, ret, copy); - } + static ArrayData* AddLvalInt(ArrayData*, int64_t k, Variant *&ret, + bool copy); + static ArrayData* AddLvalStr(ArrayData*, StringData* k, Variant *&ret, + bool copy); /** * Remove a value at specified key. If "copy" is true, make a copy first @@ -483,17 +453,13 @@ private: template ArrayData *removeImpl(K k, bool copy); public: - virtual ArrayData *remove(int64_t k, bool copy) FOLLY_OVERRIDE { - return removeImpl(k, copy); - } - virtual ArrayData *remove(const StringData* k, bool copy) FOLLY_OVERRIDE { - return removeImpl(k, copy); - } + static ArrayData *RemoveInt(ArrayData*, int64_t k, bool copy); + static ArrayData *RemoveStr(ArrayData*, const StringData* k, bool copy); - virtual ssize_t iter_begin() const FOLLY_OVERRIDE; - virtual ssize_t iter_end() const FOLLY_OVERRIDE; - virtual ssize_t iter_advance(ssize_t prev) const FOLLY_OVERRIDE; - virtual ssize_t iter_rewind(ssize_t prev) const FOLLY_OVERRIDE; + static ssize_t IterBegin(const ArrayData*); + static ssize_t IterEnd(const ArrayData*); + static ssize_t IterAdvance(const ArrayData*, ssize_t prev); + static ssize_t IterRewind(const ArrayData*, ssize_t prev); /** * Mutable iteration APIs diff --git a/hphp/runtime/base/shared_map.cpp b/hphp/runtime/base/shared_map.cpp index 1439a69bd..2af5701eb 100644 --- a/hphp/runtime/base/shared_map.cpp +++ b/hphp/runtime/base/shared_map.cpp @@ -45,6 +45,10 @@ CVarRef SharedMap::getValueRef(ssize_t pos) const { return tvAsCVarRef(tv); } +CVarRef SharedMap::GetValueRef(const ArrayData* ad, ssize_t pos) { + return asSharedMap(ad)->getValueRef(pos); +} + HOT_FUNC SharedMap::~SharedMap() { if (m_localCache) { @@ -86,22 +90,24 @@ ssize_t SharedMap::getIndex(int64_t k) const { return m_map->indexOf(k); } -bool SharedMap::isVectorData() const { - if (isVector()) return true; - const auto n = size(); +bool SharedMap::IsVectorData(const ArrayData* ad) { + auto a = asSharedMap(ad); + if (a->isVector()) return true; + const auto n = a->size(); for (ssize_t i = 0; i < n; i++) { - if (m_map->indexOf(i) != i) return false; + if (a->m_map->indexOf(i) != i) return false; } return true; } -bool SharedMap::exists(const StringData* k) const { - if (isVector()) return false; - return m_map->indexOf(k) != -1; +bool SharedMap::ExistsStr(const ArrayData* ad, const StringData* k) { + auto a = asSharedMap(ad); + if (a->isVector()) return false; + return a->m_map->indexOf(k) != -1; } -bool SharedMap::exists(int64_t k) const { - return getIndex(k) != -1; +bool SharedMap::ExistsInt(const ArrayData* ad, int64_t k) { + return asSharedMap(ad)->getIndex(k) != -1; } /* if a2 is modified copy of a1 (i.e. != a1), then release a1 and return a2 */ @@ -110,18 +116,20 @@ inline ArrayData* releaseIfCopied(ArrayData* a1, ArrayData* a2) { return a2; } -ArrayData *SharedMap::lval(int64_t k, Variant *&ret, bool copy) { - ArrayData *escalated = SharedMap::escalate(); +ArrayData *SharedMap::LvalInt(ArrayData* ad, int64_t k, Variant *&ret, + bool copy) { + ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); return releaseIfCopied(escalated, escalated->lval(k, ret, false)); } -ArrayData *SharedMap::lval(StringData* k, Variant *&ret, bool copy) { - ArrayData *escalated = SharedMap::escalate(); +ArrayData *SharedMap::LvalStr(ArrayData* ad, StringData* k, Variant *&ret, + bool copy) { + ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); return releaseIfCopied(escalated, escalated->lval(k, ret, false)); } -ArrayData *SharedMap::lvalNew(Variant *&ret, bool copy) { - ArrayData *escalated = SharedMap::escalate(); +ArrayData *SharedMap::LvalNew(ArrayData* ad, Variant *&ret, bool copy) { + ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); return releaseIfCopied(escalated, escalated->lvalNew(ret, false)); } @@ -137,23 +145,37 @@ SharedMap::SetStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) { return releaseIfCopied(escalated, escalated->set(k, v, false)); } -ArrayData *SharedMap::setRef(int64_t k, CVarRef v, bool copy) { - ArrayData *escalated = SharedMap::escalate(); +ArrayData* +SharedMap::SetRefInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) { + ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); return releaseIfCopied(escalated, escalated->setRef(k, v, false)); } -ArrayData *SharedMap::setRef(StringData* k, CVarRef v, bool copy) { - ArrayData *escalated = SharedMap::escalate(); +ArrayData* +SharedMap::SetRefStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) { + ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); return releaseIfCopied(escalated, escalated->setRef(k, v, false)); } -ArrayData *SharedMap::remove(int64_t k, bool copy) { - ArrayData *escalated = SharedMap::escalate(); +ArrayData *SharedMap::AddLvalInt(ArrayData* ad, int64_t k, Variant *&ret, + bool copy) { + ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); + return releaseIfCopied(escalated, escalated->addLval(k, ret, false)); +} + +ArrayData *SharedMap::AddLvalStr(ArrayData* ad, StringData* k, Variant *&ret, + bool copy) { + ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); + return releaseIfCopied(escalated, escalated->addLval(k, ret, false)); +} + +ArrayData *SharedMap::RemoveInt(ArrayData* ad, int64_t k, bool copy) { + ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); return releaseIfCopied(escalated, escalated->remove(k, false)); } -ArrayData *SharedMap::remove(const StringData* k, bool copy) { - ArrayData *escalated = SharedMap::escalate(); +ArrayData *SharedMap::RemoveStr(ArrayData* ad, const StringData* k, bool copy) { + ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); return releaseIfCopied(escalated, escalated->remove(k, false)); } @@ -233,28 +255,27 @@ ArrayData* SharedMap::escalateForSort() { return ret; } -ssize_t SharedMap::vsize() const { - assert(false); // should never be called since we set size already. - return m_size; +ssize_t SharedMap::IterBegin(const ArrayData* ad) { + auto a = asSharedMap(ad); + return a->m_size > 0 ? 0 : invalid_index; } -ssize_t SharedMap::iter_begin() const { - return !empty() ? 0 : invalid_index; -} - -ssize_t SharedMap::iter_end() const { - auto n = size(); +ssize_t SharedMap::IterEnd(const ArrayData* ad) { + auto a = asSharedMap(ad); + auto n = a->m_size; return n > 0 ? ssize_t(n - 1) : invalid_index; } -ssize_t SharedMap::iter_advance(ssize_t prev) const { - assert(prev >= 0 && prev < size()); +ssize_t SharedMap::IterAdvance(const ArrayData* ad, ssize_t prev) { + auto a = asSharedMap(ad); + assert(prev >= 0 && prev < a->m_size); ssize_t next = prev + 1; - return next < size() ? next : invalid_index; + return next < a->m_size ? next : invalid_index; } -ssize_t SharedMap::iter_rewind(ssize_t prev) const { - assert(prev >= 0 && prev < size()); +ssize_t SharedMap::IterRewind(const ArrayData* ad, ssize_t prev) { + auto a = asSharedMap(ad); + assert(prev >= 0 && prev < a->m_size); ssize_t next = prev - 1; return next >= 0 ? next : invalid_index; } diff --git a/hphp/runtime/base/shared_map.h b/hphp/runtime/base/shared_map.h index 5751928fd..bd3c72fa7 100644 --- a/hphp/runtime/base/shared_map.h +++ b/hphp/runtime/base/shared_map.h @@ -56,28 +56,34 @@ public: using ArrayData::addLval; using ArrayData::remove; - ssize_t vsize() const; - SharedVariant* getValueImpl(ssize_t pos) const { return isVector() ? m_vec->getValue(pos) : m_map->getValue(pos); } CVarRef getValueRef(ssize_t pos) const; + static CVarRef GetValueRef(const ArrayData* ad, ssize_t pos); - bool exists(int64_t k) const; - bool exists(const StringData* k) const; + static bool ExistsInt(const ArrayData* ad, int64_t k); + static bool ExistsStr(const ArrayData* ad, const StringData* k); - virtual ArrayData *lval(int64_t k, Variant *&ret, bool copy); - virtual ArrayData *lval(StringData* k, Variant *&ret, bool copy); - ArrayData *lvalNew(Variant *&ret, bool copy); + static ArrayData* LvalInt(ArrayData*, int64_t k, Variant *&ret, + bool copy); + static ArrayData* LvalStr(ArrayData*, StringData* k, Variant *&ret, + bool copy); + static ArrayData* LvalNew(ArrayData*, Variant *&ret, bool copy); - static ArrayData *SetInt(ArrayData*, int64_t k, CVarRef v, bool copy); - static ArrayData *SetStr(ArrayData*, StringData* k, CVarRef v, bool copy); - ArrayData *setRef(int64_t k, CVarRef v, bool copy); - ArrayData *setRef(StringData* k, CVarRef v, bool copy); + static ArrayData* SetInt(ArrayData*, int64_t k, CVarRef v, bool copy); + static ArrayData* SetStr(ArrayData*, StringData* k, CVarRef v, bool copy); + static ArrayData* SetRefInt(ArrayData*, int64_t k, CVarRef v, bool copy); + static ArrayData* SetRefStr(ArrayData*, StringData* k, CVarRef v, bool copy); - ArrayData *remove(int64_t k, bool copy); - ArrayData *remove(const StringData* k, bool copy); + static ArrayData* AddLvalInt(ArrayData*, int64_t k, Variant *&ret, + bool copy); + static ArrayData* AddLvalStr(ArrayData*, StringData* k, Variant *&ret, + bool copy); + + static ArrayData *RemoveInt(ArrayData* ad, int64_t k, bool copy); + static ArrayData *RemoveStr(ArrayData* ad, const StringData* k, bool copy); ArrayData *copy() const; /** @@ -98,12 +104,12 @@ public: static TypedValue* NvGetStr(const ArrayData*, const StringData* k); static void NvGetKey(const ArrayData*, TypedValue* out, ssize_t pos); - bool isVectorData() const; + static bool IsVectorData(const ArrayData* ad); - ssize_t iter_begin() const; - ssize_t iter_end() const; - ssize_t iter_advance(ssize_t prev) const; - ssize_t iter_rewind(ssize_t prev) const; + static ssize_t IterBegin(const ArrayData*); + static ssize_t IterEnd(const ArrayData*); + static ssize_t IterAdvance(const ArrayData*, ssize_t prev); + static ssize_t IterRewind(const ArrayData*, ssize_t prev); bool validFullPos(const FullPos& fp) const; bool advanceFullPos(FullPos& fp); diff --git a/hphp/runtime/vm/name_value_table_wrapper.cpp b/hphp/runtime/vm/name_value_table_wrapper.cpp index d7ac45c9c..9be36d6e2 100644 --- a/hphp/runtime/vm/name_value_table_wrapper.cpp +++ b/hphp/runtime/vm/name_value_table_wrapper.cpp @@ -36,14 +36,15 @@ NameValueTableWrapper::asNVTW(const ArrayData* ad) { return static_cast(ad); } -ssize_t NameValueTableWrapper::vsize() const { +size_t NameValueTableWrapper::Vsize(const ArrayData* ad) { // We need to iterate to find out the actual size, since // KindOfIndirect elements in the array may have been set to // KindOfUninit. - ssize_t count = 0; - for (ssize_t iter = iter_begin(); - iter != ArrayData::invalid_index; - iter = iter_advance(iter)) { + auto a = asNVTW(ad); + size_t count = 0; + for (auto iter = IterBegin(a); + iter != invalid_index; + iter = IterAdvance(a, iter)) { ++count; } return count; @@ -63,23 +64,20 @@ void NameValueTableWrapper::NvGetKey(const ArrayData* ad, TypedValue* out, } } -CVarRef NameValueTableWrapper::getValueRef(ssize_t pos) const { - NameValueTable::Iterator iter(m_tab, pos); +CVarRef NameValueTableWrapper::GetValueRef(const ArrayData* ad, ssize_t pos) { + auto a = asNVTW(ad); + NameValueTable::Iterator iter(a->m_tab, pos); return iter.valid() ? tvAsCVarRef(iter.curVal()) : null_variant; } -bool NameValueTableWrapper::noCopyOnWrite() const { - // This just disables a few places that will call copy() on an array - // if it has more than one reference. - return true; +bool +NameValueTableWrapper::ExistsInt(const ArrayData* ad, int64_t k) { + return ExistsStr(ad, String(k).get()); } -bool NameValueTableWrapper::exists(int64_t k) const { - return exists(String(k)); -} - -bool NameValueTableWrapper::exists(const StringData* k) const { - return m_tab->lookup(k); +bool +NameValueTableWrapper::ExistsStr(const ArrayData* ad, const StringData* k) { + return asNVTW(ad)->m_tab->lookup(k) != nullptr; } TypedValue* @@ -91,24 +89,42 @@ TypedValue* NameValueTableWrapper::NvGetInt(const ArrayData* ad, int64_t k) { return asNVTW(ad)->m_tab->lookup(String(k).get()); } -ArrayData* NameValueTableWrapper::lval(int64_t k, Variant*& ret, bool) { - return lval(String(k), ret, false); +ArrayData* +NameValueTableWrapper::LvalInt(ArrayData* ad, int64_t k, Variant*& ret, + bool copy) { + return LvalStr(ad, String(k).get(), ret, copy); } -ArrayData* NameValueTableWrapper::lval(StringData* k, Variant*& ret, bool) { - TypedValue* tv = m_tab->lookup(k); +ArrayData* +NameValueTableWrapper::LvalStr(ArrayData* ad, StringData* k, Variant*& ret, + bool copy) { + auto a = asNVTW(ad); + TypedValue* tv = a->m_tab->lookup(k); if (!tv) { TypedValue nulVal; tvWriteNull(&nulVal); - tv = m_tab->set(k, &nulVal); + tv = a->m_tab->set(k, &nulVal); } ret = &tvAsVariant(tv); - return this; + return a; } -ArrayData* NameValueTableWrapper::lvalNew(Variant*& ret, bool copy) { +ArrayData* +NameValueTableWrapper::AddLvalInt(ArrayData* ad, int64_t k, Variant*& ret, + bool copy) { + return LvalStr(ad, String(k).get(), ret, copy); +} + +ArrayData* +NameValueTableWrapper::AddLvalStr(ArrayData* ad, StringData* k, Variant*& ret, + bool copy) { + return LvalStr(ad, k, ret, copy); +} + +ArrayData* +NameValueTableWrapper::LvalNew(ArrayData* ad, Variant*& ret, bool copy) { ret = &Variant::lvalBlackHole(); - return this; + return ad; } ArrayData* NameValueTableWrapper::SetInt(ArrayData* ad, int64_t k, @@ -123,22 +139,29 @@ ArrayData* NameValueTableWrapper::SetStr(ArrayData* ad, StringData* k, return a; } -ArrayData* NameValueTableWrapper::setRef(int64_t k, CVarRef v, bool copy) { - return setRef(String(k), v, copy); +ArrayData* NameValueTableWrapper::SetRefInt(ArrayData* ad, int64_t k, + CVarRef v, bool copy) { + return asNVTW(ad)->setRef(String(k).get(), v, copy); } -ArrayData* NameValueTableWrapper::setRef(StringData* k, CVarRef v, bool copy) { - tvAsVariant(m_tab->lookupAdd(k)).assignRef(v); - return this; +ArrayData* NameValueTableWrapper::SetRefStr(ArrayData* ad, StringData* k, + CVarRef v, bool copy) { + auto a = asNVTW(ad); + tvAsVariant(a->m_tab->lookupAdd(k)).assignRef(v); + return a; } -ArrayData* NameValueTableWrapper::remove(int64_t k, bool copy) { - return remove(String(k), copy); +ArrayData* +NameValueTableWrapper::RemoveInt(ArrayData* ad, int64_t k, bool copy) { + return RemoveStr(ad, String(k).get(), copy); } -ArrayData* NameValueTableWrapper::remove(const StringData* k, bool copy) { - m_tab->unset(k); - return this; +ArrayData* +NameValueTableWrapper::RemoveStr(ArrayData* ad, const StringData* k, + bool copy) { + auto a = asNVTW(ad); + a->m_tab->unset(k); + return a; } /* @@ -171,23 +194,27 @@ ArrayData* NameValueTableWrapper::prepend(CVarRef v, bool copy) { throw NotImplementedException("prepend on $GLOBALS"); } -ssize_t NameValueTableWrapper::iter_begin() const { - NameValueTable::Iterator iter(m_tab); +ssize_t NameValueTableWrapper::IterBegin(const ArrayData* ad) { + auto a = asNVTW(ad); + NameValueTable::Iterator iter(a->m_tab); return iter.toInteger(); } -ssize_t NameValueTableWrapper::iter_end() const { - return NameValueTable::Iterator::getEnd(m_tab).toInteger(); +ssize_t NameValueTableWrapper::IterEnd(const ArrayData* ad) { + auto a = asNVTW(ad); + return NameValueTable::Iterator::getEnd(a->m_tab).toInteger(); } -ssize_t NameValueTableWrapper::iter_advance(ssize_t prev) const { - NameValueTable::Iterator iter(m_tab, prev); +ssize_t NameValueTableWrapper::IterAdvance(const ArrayData* ad, ssize_t prev) { + auto a = asNVTW(ad); + NameValueTable::Iterator iter(a->m_tab, prev); iter.next(); return iter.toInteger(); } -ssize_t NameValueTableWrapper::iter_rewind(ssize_t prev) const { - NameValueTable::Iterator iter(m_tab, prev); +ssize_t NameValueTableWrapper::IterRewind(const ArrayData* ad, ssize_t prev) { + auto a = asNVTW(ad); + NameValueTable::Iterator iter(a->m_tab, prev); iter.prev(); return iter.toInteger(); } @@ -233,7 +260,7 @@ void NameValueTableWrapper::uksort(CVarRef cmp_function) {} void NameValueTableWrapper::usort(CVarRef cmp_function) {} void NameValueTableWrapper::uasort(CVarRef cmp_function) {} -bool NameValueTableWrapper::isVectorData() const { +bool NameValueTableWrapper::IsVectorData(const ArrayData*) { return false; } diff --git a/hphp/runtime/vm/name_value_table_wrapper.h b/hphp/runtime/vm/name_value_table_wrapper.h index c28aef689..e37c70847 100644 --- a/hphp/runtime/vm/name_value_table_wrapper.h +++ b/hphp/runtime/vm/name_value_table_wrapper.h @@ -77,27 +77,31 @@ public: // ArrayData implementation return tvAsVariant(nvGet(k.get())); } - virtual ssize_t vsize() const; + static size_t Vsize(const ArrayData*); static void NvGetKey(const ArrayData* ad, TypedValue* out, ssize_t pos); - virtual CVarRef getValueRef(ssize_t pos) const; - virtual bool noCopyOnWrite() const; + static CVarRef GetValueRef(const ArrayData*, ssize_t pos); - virtual bool exists(int64_t k) const; - virtual bool exists(const StringData* k) const; + static bool ExistsInt(const ArrayData* ad, int64_t k); + static bool ExistsStr(const ArrayData* ad, const StringData* k); static TypedValue* NvGetInt(const ArrayData*, int64_t k); static TypedValue* NvGetStr(const ArrayData*, const StringData* k); - virtual ArrayData* lval(int64_t k, Variant*& ret, bool copy); - virtual ArrayData* lval(StringData* k, Variant*& ret, bool copy); - virtual ArrayData* lvalNew(Variant*& ret, bool copy); + static ArrayData* LvalInt(ArrayData*, int64_t k, Variant*& ret, bool copy); + static ArrayData* LvalStr(ArrayData*, StringData* k, Variant*& ret, + bool copy); + static ArrayData* LvalNew(ArrayData*, Variant*& ret, bool copy); static ArrayData* SetInt(ArrayData*, int64_t k, CVarRef v, bool copy); static ArrayData* SetStr(ArrayData*, StringData* k, CVarRef v, bool copy); - virtual ArrayData* setRef(int64_t k, CVarRef v, bool copy); - virtual ArrayData* setRef(StringData* k, CVarRef v, bool copy); - virtual ArrayData* remove(int64_t k, bool copy); - virtual ArrayData* remove(const StringData* k, bool copy); + static ArrayData* SetRefInt(ArrayData*, int64_t k, CVarRef v, bool copy); + static ArrayData* SetRefStr(ArrayData*, StringData* k, CVarRef v, bool copy); + static ArrayData* AddLvalInt(ArrayData*, int64_t k, Variant*& ret, + bool copy); + static ArrayData* AddLvalStr(ArrayData*, StringData* k, Variant*& ret, + bool copy); + static ArrayData* RemoveInt(ArrayData*, int64_t k, bool copy); + static ArrayData* RemoveStr(ArrayData*, const StringData* k, bool copy); virtual ArrayData* copy() const { return 0; } @@ -110,14 +114,14 @@ public: // ArrayData implementation virtual ArrayData* prepend(CVarRef v, bool copy); - virtual ssize_t iter_begin() const; - virtual ssize_t iter_end() const; - virtual ssize_t iter_advance(ssize_t prev) const; - virtual ssize_t iter_rewind(ssize_t prev) const; + static ssize_t IterBegin(const ArrayData*); + static ssize_t IterEnd(const ArrayData*); + static ssize_t IterAdvance(const ArrayData*, ssize_t prev); + static ssize_t IterRewind(const ArrayData*, ssize_t prev); virtual bool validFullPos(const FullPos & fp) const; virtual bool advanceFullPos(FullPos&); - virtual bool isVectorData() const; + static bool IsVectorData(const ArrayData*); virtual ArrayData* escalateForSort(); virtual void ksort(int sort_flags, bool ascending);