From 7204d561e5150f32ba97770e2f9c3b646a5c199a Mon Sep 17 00:00:00 2001 From: Edwin Smith Date: Tue, 16 Jul 2013 14:32:52 -0700 Subject: [PATCH] Devirtualize ArrayData part 2 Convert remaining virtual methods to static methods dispatched by kind. This makes ArrayData a non-virtual class, so shuffle fields and adjust static_asserts. --- hphp/runtime/base/array_data-defs.h | 88 ++++++ hphp/runtime/base/array_data.cpp | 185 +++++++++--- hphp/runtime/base/array_data.h | 178 +++++++----- hphp/runtime/base/countable.h | 3 +- hphp/runtime/base/hphp_array-defs.h | 2 - hphp/runtime/base/hphp_array.cpp | 189 +++++++------ hphp/runtime/base/hphp_array.h | 52 ++-- hphp/runtime/base/hphp_array_sort.cpp | 58 ++-- hphp/runtime/base/policy_array.cpp | 278 +++++++++---------- hphp/runtime/base/policy_array.h | 35 +-- hphp/runtime/base/shared_map.cpp | 66 +++-- hphp/runtime/base/shared_map.h | 27 +- hphp/runtime/vm/backup_gc.cpp | 4 - hphp/runtime/vm/name_value_table_wrapper.cpp | 57 ++-- hphp/runtime/vm/name_value_table_wrapper.h | 33 +-- 15 files changed, 768 insertions(+), 487 deletions(-) diff --git a/hphp/runtime/base/array_data-defs.h b/hphp/runtime/base/array_data-defs.h index b99e46a60..1f8492100 100644 --- a/hphp/runtime/base/array_data-defs.h +++ b/hphp/runtime/base/array_data-defs.h @@ -173,6 +173,14 @@ inline ArrayData* ArrayData::append(CVarRef v, bool copy) { return g_array_funcs.append[m_kind](this, v, copy); } +inline ArrayData* ArrayData::appendRef(CVarRef v, bool copy) { + return g_array_funcs.appendRef[m_kind](this, v, copy); +} + +inline ArrayData* ArrayData::appendWithRef(CVarRef v, bool copy) { + return g_array_funcs.appendWithRef[m_kind](this, v, copy); +} + inline TypedValue* ArrayData::nvGet(int64_t ikey) const { return g_array_funcs.nvGetInt[m_kind](this, ikey); } @@ -287,6 +295,86 @@ inline ssize_t ArrayData::iter_rewind(ssize_t pos) const { return g_array_funcs.iterRewind[m_kind](this, pos); } +inline bool ArrayData::validFullPos(const FullPos& fp) const { + return g_array_funcs.validFullPos[m_kind](this, fp); +} + +inline bool ArrayData::advanceFullPos(FullPos& fp) { + return g_array_funcs.advanceFullPos[m_kind](this, fp); +} + +inline ArrayData* ArrayData::escalateForSort() { + return g_array_funcs.escalateForSort[m_kind](this); +} + +inline void ArrayData::ksort(int sort_flags, bool ascending) { + return g_array_funcs.ksort[m_kind](this, sort_flags, ascending); +} + +inline void ArrayData::sort(int sort_flags, bool ascending) { + return g_array_funcs.sort[m_kind](this, sort_flags, ascending); +} + +inline void ArrayData::asort(int sort_flags, bool ascending) { + return g_array_funcs.asort[m_kind](this, sort_flags, ascending); +} + +inline void ArrayData::uksort(CVarRef compare) { + return g_array_funcs.uksort[m_kind](this, compare); +} + +inline void ArrayData::usort(CVarRef compare) { + return g_array_funcs.usort[m_kind](this, compare); +} + +inline void ArrayData::uasort(CVarRef compare) { + return g_array_funcs.uasort[m_kind](this, compare); +} + +inline ArrayData* ArrayData::copy() const { + return g_array_funcs.copy[m_kind](this); +} + +inline ArrayData* ArrayData::copyWithStrongIterators() const { + return g_array_funcs.copyWithStrongIterators[m_kind](this); +} + +inline ArrayData* ArrayData::nonSmartCopy() const { + return g_array_funcs.nonSmartCopy[m_kind](this); +} + +inline ArrayData* ArrayData::pop(Variant& value) { + return g_array_funcs.pop[m_kind](this, value); +} + +inline ArrayData* ArrayData::dequeue(Variant& value) { + return g_array_funcs.dequeue[m_kind](this, value); +} + +inline ArrayData* ArrayData::prepend(CVarRef value, bool copy) { + return g_array_funcs.prepend[m_kind](this, value, copy); +} + +inline void ArrayData::renumber() { + return g_array_funcs.renumber[m_kind](this); +} + +inline void ArrayData::onSetEvalScalar() { + return g_array_funcs.onSetEvalScalar[m_kind](this); +} + +inline ArrayData* ArrayData::escalate() const { + return g_array_funcs.escalate[m_kind](this); +} + +inline ArrayData* ArrayData::plus(const ArrayData* elms, bool copy) { + return g_array_funcs.plus[m_kind](this, elms, copy); +} + +inline ArrayData* ArrayData::merge(const ArrayData* elms, bool copy) { + return g_array_funcs.merge[m_kind](this, elms, copy); +} + /////////////////////////////////////////////////////////////////////////////// } diff --git a/hphp/runtime/base/array_data.cpp b/hphp/runtime/base/array_data.cpp index 451492c67..506882a92 100644 --- a/hphp/runtime/base/array_data.cpp +++ b/hphp/runtime/base/array_data.cpp @@ -36,7 +36,7 @@ namespace HPHP { /////////////////////////////////////////////////////////////////////////////// static_assert( - sizeof(ArrayData) == 32, + sizeof(ArrayData) == 24, "Performance is sensitive to sizeof(ArrayData)." " Make sure you changed it with good reason and then update this assert."); @@ -76,11 +76,6 @@ extern const ArrayFunctions g_array_funcs = { &SharedMap::Release, &NameValueTableWrapper::Release, &PolicyArray::Release }, - // append - { &HphpArray::AppendVec, &HphpArray::Append, - &SharedMap::Append, - &NameValueTableWrapper::Append, - &PolicyArray::Append }, // nvGetInt { &HphpArray::NvGetIntVec, &HphpArray::NvGetInt, &SharedMap::NvGetInt, @@ -221,6 +216,121 @@ extern const ArrayFunctions g_array_funcs = { &SharedMap::IterRewind, &NameValueTableWrapper::IterRewind, &PolicyArray::IterRewind }, + // validFullPos + { &HphpArray::ValidFullPos, &HphpArray::ValidFullPos, + &SharedMap::ValidFullPos, + &NameValueTableWrapper::ValidFullPos, + &PolicyArray::ValidFullPos }, + // advanceFullPos + { &HphpArray::AdvanceFullPos, &HphpArray::AdvanceFullPos, + &SharedMap::AdvanceFullPos, + &NameValueTableWrapper::AdvanceFullPos, + &PolicyArray::AdvanceFullPos }, + // escalateForSort + { &HphpArray::EscalateForSort, &HphpArray::EscalateForSort, + &SharedMap::EscalateForSort, + &NameValueTableWrapper::EscalateForSort, + &PolicyArray::EscalateForSort }, + // ksort + { &HphpArray::Ksort, &HphpArray::Ksort, + &ArrayData::Ksort, + &NameValueTableWrapper::Ksort, + &ArrayData::Ksort }, + // sort + { &HphpArray::Sort, &HphpArray::Sort, + &ArrayData::Sort, + &NameValueTableWrapper::Sort, + &ArrayData::Sort }, + // asort + { &HphpArray::Asort, &HphpArray::Asort, + &ArrayData::Asort, + &NameValueTableWrapper::Asort, + &ArrayData::Asort }, + // uksort + { &HphpArray::Uksort, &HphpArray::Uksort, + &ArrayData::Uksort, + &NameValueTableWrapper::Uksort, + &ArrayData::Uksort }, + // usort + { &HphpArray::Usort, &HphpArray::Usort, + &ArrayData::Usort, + &NameValueTableWrapper::Usort, + &ArrayData::Usort }, + // uasort + { &HphpArray::Uasort, &HphpArray::Uasort, + &ArrayData::Uasort, + &NameValueTableWrapper::Uasort, + &ArrayData::Uasort }, + // copy + { &HphpArray::CopyVec, &HphpArray::Copy, + &SharedMap::Copy, + &NameValueTableWrapper::Copy, + &PolicyArray::Copy }, + // copyWithStrongIterators + { &HphpArray::CopyWithStrongIterators, &HphpArray::CopyWithStrongIterators, + &SharedMap::CopyWithStrongIterators, + &NameValueTableWrapper::CopyWithStrongIterators, + &PolicyArray::CopyWithStrongIterators }, + // nonSmartCopy + { &HphpArray::NonSmartCopy, &HphpArray::NonSmartCopy, + &ArrayData::NonSmartCopy, + &ArrayData::NonSmartCopy, + &PolicyArray::NonSmartCopy }, + // append + { &HphpArray::AppendVec, &HphpArray::Append, + &SharedMap::Append, + &NameValueTableWrapper::Append, + &PolicyArray::Append }, + // appendRef + { &HphpArray::AppendRefVec, &HphpArray::AppendRef, + &SharedMap::AppendRef, + &NameValueTableWrapper::AppendRef, + &PolicyArray::AppendRef }, + // appendWithRef + { &HphpArray::AppendWithRefVec, &HphpArray::AppendWithRef, + &SharedMap::AppendRef, + &NameValueTableWrapper::AppendRef, + &PolicyArray::AppendRef }, + // plus + { &HphpArray::Plus, &HphpArray::Plus, + &SharedMap::Plus, + &NameValueTableWrapper::Plus, + &PolicyArray::Plus }, + // merge + { &HphpArray::Merge, &HphpArray::Merge, + &SharedMap::Merge, + &NameValueTableWrapper::Merge, + &PolicyArray::Merge }, + // pop + { &HphpArray::PopVec, &HphpArray::Pop, + &SharedMap::Pop, + &NameValueTableWrapper::Pop, + &PolicyArray::Pop }, + // dequeue + { &HphpArray::Dequeue, &HphpArray::Dequeue, + &SharedMap::Dequeue, + &NameValueTableWrapper::Dequeue, + &PolicyArray::Dequeue }, + // prepend + { &HphpArray::Prepend, &HphpArray::Prepend, + &SharedMap::Prepend, + &NameValueTableWrapper::Prepend, + &PolicyArray::Prepend }, + // renumber + { &HphpArray::RenumberVec, &HphpArray::Renumber, + &SharedMap::Renumber, + &NameValueTableWrapper::Renumber, + &PolicyArray::Renumber }, + // onSetEvalScalar + { &HphpArray::OnSetEvalScalarVec, &HphpArray::OnSetEvalScalar, + &SharedMap::OnSetEvalScalar, + &NameValueTableWrapper::OnSetEvalScalar, + &PolicyArray::OnSetEvalScalar }, + // escalate + { &ArrayData::Escalate, &ArrayData::Escalate, + &SharedMap::Escalate, + &ArrayData::Escalate, + &PolicyArray::Escalate }, }; /////////////////////////////////////////////////////////////////////////////// @@ -272,7 +382,7 @@ ArrayData *ArrayData::CreateRef(CVarRef name, CVarRef value) { return init.create(); } -ArrayData *ArrayData::nonSmartCopy() const { +ArrayData *ArrayData::NonSmartCopy(const ArrayData*) { throw FatalErrorException("nonSmartCopy not implemented."); } @@ -351,28 +461,28 @@ ArrayData *ArrayData::GetLvalPtr(ArrayData* ad, StringData* k, /////////////////////////////////////////////////////////////////////////////// // stack and queue operations -ArrayData *ArrayData::pop(Variant &value) { - if (!empty()) { - ssize_t pos = iter_end(); - value = getValue(pos); - return remove(getKey(pos), getCount() > 1); +ArrayData *ArrayData::Pop(ArrayData* a, Variant &value) { + if (!a->empty()) { + ssize_t pos = a->iter_end(); + value = a->getValue(pos); + return a->remove(a->getKey(pos), a->getCount() > 1); } value = uninit_null(); - return this; + return a; } -ArrayData *ArrayData::dequeue(Variant &value) { - if (!empty()) { - auto const pos = iter_begin(); - value = getValue(pos); - ArrayData *ret = remove(getKey(pos), getCount() > 1); +ArrayData *ArrayData::Dequeue(ArrayData* a, Variant &value) { + if (!a->empty()) { + auto const pos = a->iter_begin(); + value = a->getValue(pos); + ArrayData *ret = a->remove(a->getKey(pos), a->getCount() > 1); // In PHP, array_shift() will cause all numerically key-ed values re-keyed ret->renumber(); return ret; } value = uninit_null(); - return this; + return a; } /////////////////////////////////////////////////////////////////////////////// @@ -430,31 +540,31 @@ CVarRef ArrayData::endRef() { throw FatalErrorException("invalid ArrayData::m_pos"); } -ArrayData* ArrayData::escalateForSort() { - if (getCount() > 1) { - return copy(); - } - return this; -} -void ArrayData::ksort(int sort_flags, bool ascending) { +void ArrayData::Ksort(ArrayData*, int sort_flags, bool ascending) { throw FatalErrorException("Unimplemented ArrayData::ksort"); } -void ArrayData::sort(int sort_flags, bool ascending) { + +void ArrayData::Sort(ArrayData*, int sort_flags, bool ascending) { throw FatalErrorException("Unimplemented ArrayData::sort"); } -void ArrayData::asort(int sort_flags, bool ascending) { + +void ArrayData::Asort(ArrayData*, int sort_flags, bool ascending) { throw FatalErrorException("Unimplemented ArrayData::asort"); } -void ArrayData::uksort(CVarRef cmp_function) { + +void ArrayData::Uksort(ArrayData*, CVarRef cmp_function) { throw FatalErrorException("Unimplemented ArrayData::uksort"); } -void ArrayData::usort(CVarRef cmp_function) { + +void ArrayData::Usort(ArrayData*, CVarRef cmp_function) { throw FatalErrorException("Unimplemented ArrayData::usort"); } -void ArrayData::uasort(CVarRef cmp_function) { + +void ArrayData::Uasort(ArrayData*, CVarRef cmp_function) { throw FatalErrorException("Unimplemented ArrayData::uasort"); } -ArrayData* ArrayData::copyWithStrongIterators() const { + +ArrayData* ArrayData::CopyWithStrongIterators(const ArrayData* ad) { throw FatalErrorException("Unimplemented ArrayData::copyWithStrongIterators"); } @@ -624,6 +734,17 @@ CVarRef ArrayData::getNotFound(CVarRef k) { return null_variant; } +void ArrayData::Renumber(ArrayData*) { +} + +void ArrayData::OnSetEvalScalar(ArrayData*) { + assert(false); +} + +ArrayData* ArrayData::Escalate(const ArrayData* ad) { + return const_cast(ad); +} + void ArrayData::dump() { string out; dump(out); fwrite(out.c_str(), out.size(), 1, stdout); } diff --git a/hphp/runtime/base/array_data.h b/hphp/runtime/base/array_data.h index d38f68d1b..2d4eb5405 100644 --- a/hphp/runtime/base/array_data.h +++ b/hphp/runtime/base/array_data.h @@ -33,7 +33,7 @@ class HphpArray; /** * Base class/interface for all types of specialized array data. */ -class ArrayData : public Countable { +class ArrayData { public: enum class AllocationMode : bool { smart, nonSmart }; @@ -56,46 +56,54 @@ 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_kind(kind) , m_allocMode(AllocationMode::smart) + , m_size(-1) + , _count(0) + , m_pos(0) + , m_strongIterators(nullptr) {} explicit ArrayData(ArrayKind kind, AllocationMode m) - : m_size(-1) - , m_strongIterators(nullptr) - , m_pos(0) - , m_kind(kind) - , m_allocMode(m) + : m_kind(kind) + , m_allocMode(m) + , m_size(-1) + , _count(0) + , m_pos(0) + , m_strongIterators(nullptr) {} ArrayData(ArrayKind kind, AllocationMode m, uint size) - : m_size(size) - , m_strongIterators(nullptr) - , m_pos(size ? 0 : ArrayData::invalid_index) - , m_kind(kind) - , m_allocMode(m) + : m_kind(kind) + , m_allocMode(m) + , m_size(size) + , _count(0) + , m_pos(size ? 0 : ArrayData::invalid_index) + , 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_kind(src->m_kind) , m_allocMode(m) + , _count(0) + , m_pos(src->m_pos) + , m_strongIterators(nullptr) {} static HphpArray* Make(uint capacity); static HphpArray* Make(uint size, const TypedValue*); - virtual ~ArrayData() { + void destroy() { // If there are any strong iterators pointing to this array, they need // to be invalidated. - freeStrongIterators(); + if (UNLIKELY(m_strongIterators != nullptr)) freeStrongIterators(); } + ~ArrayData() { destroy(); } + + IMPLEMENT_COUNTABLE_METHODS + /** * Create a new ArrayData with specified array element(s). */ @@ -150,8 +158,8 @@ public: } // 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. + // to the 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; } @@ -185,10 +193,9 @@ public: return m_kind == kNvtwKind; } - /* * Returns whether or not this array contains "vector-like" data. - * I.e. all the keys are contiguous increasing integers. + * I.e. iteration order produces int keys 0 to m_size-1 in sequence. */ bool isVectorData() const; @@ -201,8 +208,8 @@ public: bool detectSerializable = false) const; /** - * non-virtual Position-based iterations, implemented using iter_begin, - * iter_advance, iter_prev, iter_rewind pure virtual methods. + * Position-based iterations, implemented using iter_begin, + * iter_advance, iter_prev, iter_rewind. */ Variant reset(); Variant prev(); @@ -226,15 +233,13 @@ public: /** * Interface for VM helpers. ArrayData implements generic versions * using the other ArrayData api; subclasses may customize methods either - * by overriding a virtual method or providing a custom static method, - * depending on how the method is dispatched. - * todo: t2608483 eliminate the remaining virtual methods. + * by providing a custom static method in g_array_funcs. */ TypedValue* nvGet(int64_t k) const; TypedValue* nvGet(const StringData* k) const; void nvGetKey(TypedValue* out, ssize_t pos) const; - // nonvirtual wrappers that call virtual getValueRef() + // wrappers that call getValueRef() TypedValue* nvGetValueRef(ssize_t pos); Variant getValue(ssize_t pos) const; Variant getKey(ssize_t pos) const; @@ -303,7 +308,8 @@ public: /** * Inline accessors that convert keys to StringData* before delegating to - * the virtual method. + * the virtual method. Helpers that take a CVarRef key dispatch to either + * the StringData* or int64_t key-type helpers. */ bool exists(CStrRef k) const; bool exists(CVarRef k) const; @@ -368,24 +374,32 @@ public: * This will return false if the iterator points past the last element, or * if the iterator points before the first element. */ - virtual bool validFullPos(const FullPos& fp) const = 0; + bool validFullPos(const FullPos& fp) const; /** * Advances the mutable iterator to the next element in the array. Returns * false if the iterator has moved past the last element, otherwise returns * true. */ - virtual bool advanceFullPos(FullPos& fp) = 0; + bool advanceFullPos(FullPos& fp); CVarRef endRef(); - virtual ArrayData* escalateForSort(); - virtual void ksort(int sort_flags, bool ascending); - virtual void sort(int sort_flags, bool ascending); - virtual void asort(int sort_flags, bool ascending); - virtual void uksort(CVarRef cmp_function); - virtual void usort(CVarRef cmp_function); - virtual void uasort(CVarRef cmp_function); + ArrayData* escalateForSort(); + void ksort(int sort_flags, bool ascending); + void sort(int sort_flags, bool ascending); + void asort(int sort_flags, bool ascending); + void uksort(CVarRef cmp_function); + void usort(CVarRef cmp_function); + void uasort(CVarRef cmp_function); + + // default sort implementations + static void Ksort(ArrayData*, int sort_flags, bool ascending); + static void Sort(ArrayData*, int sort_flags, bool ascending); + static void Asort(ArrayData*, int sort_flags, bool ascending); + static void Uksort(ArrayData*, CVarRef cmp_function); + static void Usort(ArrayData*, CVarRef cmp_function); + static void Uasort(ArrayData*, CVarRef cmp_function); /** * Make a copy of myself. @@ -394,9 +408,11 @@ public: * Is only implemented for array types that need to be able to go * into the static array list. */ - virtual ArrayData *copy() const = 0; - virtual ArrayData *copyWithStrongIterators() const; - virtual ArrayData *nonSmartCopy() const; + ArrayData* copy() const; + ArrayData* copyWithStrongIterators() const; + ArrayData* nonSmartCopy() const; + static ArrayData* CopyWithStrongIterators(const ArrayData*); + static ArrayData* NonSmartCopy(const ArrayData*); /** * Append a value to the array. If "copy" is true, make a copy first @@ -404,42 +420,42 @@ public: * escalated array data. */ ArrayData* append(CVarRef v, bool copy); - virtual ArrayData* appendRef(CVarRef v, bool copy) = 0; + ArrayData* appendRef(CVarRef v, bool copy); /** * Similar to append(v, copy), with reference in v preserved. */ - virtual ArrayData *appendWithRef(CVarRef v, bool copy) = 0; + ArrayData* appendWithRef(CVarRef v, bool copy); /** * Implementing array appending and merging. If "copy" is true, make a copy * first then append/merge arrays. Return NULL if escalation is not needed, * or an escalated array data. */ - virtual ArrayData *plus(const ArrayData *elems, bool copy) = 0; - virtual ArrayData *merge(const ArrayData *elems, bool copy) = 0; + ArrayData* plus(const ArrayData *elems, bool copy); + ArrayData* merge(const ArrayData *elems, bool copy); /** * Stack function: pop the last item and return it. */ - virtual ArrayData *pop(Variant &value); + ArrayData* pop(Variant &value); /** * Queue function: remove the 1st item and return it. */ - virtual ArrayData *dequeue(Variant &value); + ArrayData* dequeue(Variant &value); /** * Array function: prepend a new item. */ - virtual ArrayData *prepend(CVarRef v, bool copy) = 0; + ArrayData* prepend(CVarRef v, bool copy); /** * Only map classes need this. Re-index all numeric keys to start from 0. */ - virtual void renumber() {} + void renumber(); - virtual void onSetEvalScalar() { assert(false);} + void onSetEvalScalar(); /** * Serialize this array. We could have made this virtual function to ask @@ -452,9 +468,9 @@ public: void serialize(VariableSerializer *serializer, bool skipNestCheck = false) const; - virtual void dump(); - virtual void dump(std::string &out); - virtual void dump(std::ostream &os); + void dump(); + void dump(std::string &out); + void dump(std::ostream &os); /** * Comparisons. @@ -464,9 +480,17 @@ public: void setPosition(ssize_t p) { m_pos = p; } - virtual ArrayData *escalate() const { - return const_cast(this); - } + ArrayData *escalate() const; + + // default implementations + static ArrayData* Plus(ArrayData*, const ArrayData *elems, bool copy); + static ArrayData* Merge(ArrayData*, const ArrayData *elems, bool copy); + static ArrayData* Pop(ArrayData*, Variant &value); + static ArrayData* Dequeue(ArrayData*, Variant &value); + static ArrayData* Prepend(ArrayData*, CVarRef v, bool copy); + static void Renumber(ArrayData*); + static void OnSetEvalScalar(ArrayData*); + static ArrayData* Escalate(const ArrayData* ad); static ArrayData *GetScalarArray(ArrayData *arr, const StringData *key = nullptr); @@ -505,22 +529,20 @@ public: void modeFree(void* ptr) const; protected: - // Layout starts with 64 bits for vtable, then 32 bits for m_count - // from Countable base, then... - uint m_size; -private: - FullPos* m_strongIterators; // head of linked list -protected: - int32_t m_pos; ArrayKind m_kind; const AllocationMode m_allocMode; + uint32_t m_size; + mutable int32_t _count; + int32_t m_pos; + private: + FullPos* m_strongIterators; // head of linked list public: // for the JIT static uint32_t getKindOff() { return (uintptr_t)&((ArrayData*)0)->m_kind; } - public: + public: // for heap profiler void getChildren(std::vector &out); }; @@ -534,7 +556,6 @@ struct ArrayFunctions { // NK stands for number of array kinds; here just for shorthand. static auto const NK = size_t(ArrayData::ArrayKind::kNumKinds); void (*release[NK])(ArrayData*); - ArrayData* (*append[NK])(ArrayData*, CVarRef v, bool copy); TypedValue* (*nvGetInt[NK])(const ArrayData*, int64_t k); TypedValue* (*nvGetStr[NK])(const ArrayData*, const StringData* k); void (*nvGetKey[NK])(const ArrayData*, TypedValue* out, ssize_t pos); @@ -569,6 +590,29 @@ struct ArrayFunctions { ssize_t (*iterEnd[NK])(const ArrayData*); ssize_t (*iterAdvance[NK])(const ArrayData*, ssize_t pos); ssize_t (*iterRewind[NK])(const ArrayData*, ssize_t pos); + bool (*validFullPos[NK])(const ArrayData*, const FullPos&); + bool (*advanceFullPos[NK])(ArrayData*, FullPos&); + ArrayData* (*escalateForSort[NK])(ArrayData*); + void (*ksort[NK])(ArrayData* ad, int sort_flags, bool ascending); + void (*sort[NK])(ArrayData* ad, int sort_flags, bool ascending); + void (*asort[NK])(ArrayData* ad, int sort_flags, bool ascending); + void (*uksort[NK])(ArrayData* ad, CVarRef cmp_function); + void (*usort[NK])(ArrayData* ad, CVarRef cmp_function); + void (*uasort[NK])(ArrayData* ad, CVarRef cmp_function); + ArrayData* (*copy[NK])(const ArrayData*); + ArrayData* (*copyWithStrongIterators[NK])(const ArrayData*); + ArrayData* (*nonSmartCopy[NK])(const ArrayData*); + ArrayData* (*append[NK])(ArrayData*, CVarRef v, bool copy); + ArrayData* (*appendRef[NK])(ArrayData*, CVarRef v, bool copy); + ArrayData* (*appendWithRef[NK])(ArrayData*, CVarRef v, bool copy); + ArrayData* (*plus[NK])(ArrayData*, const ArrayData* elems, bool copy); + ArrayData* (*merge[NK])(ArrayData*, const ArrayData* elems, bool copy); + ArrayData* (*pop[NK])(ArrayData*, Variant& value); + ArrayData* (*dequeue[NK])(ArrayData*, Variant& value); + ArrayData* (*prepend[NK])(ArrayData*, CVarRef value, bool copy); + void (*renumber[NK])(ArrayData*); + void (*onSetEvalScalar[NK])(ArrayData*); + ArrayData* (*escalate[NK])(const ArrayData*); }; extern const ArrayFunctions g_array_funcs; diff --git a/hphp/runtime/base/countable.h b/hphp/runtime/base/countable.h index af2c77a42..06af32b70 100644 --- a/hphp/runtime/base/countable.h +++ b/hphp/runtime/base/countable.h @@ -78,7 +78,7 @@ inline DEBUG_ONLY bool is_refcount_realistic(int32_t count) { } \ bool isStatic() const { \ assert(is_refcount_realistic(_count)); \ - return _count == STATIC_FLAG; \ + return _count == RefCountStaticValue; \ } \ IMPLEMENT_COUNTABLE_METHODS_NO_STATIC @@ -89,7 +89,6 @@ inline DEBUG_ONLY bool is_refcount_realistic(int32_t count) { */ class Countable { public: - static const int32_t STATIC_FLAG = RefCountStaticValue; Countable() : _count(0) {} IMPLEMENT_COUNTABLE_METHODS protected: diff --git a/hphp/runtime/base/hphp_array-defs.h b/hphp/runtime/base/hphp_array-defs.h index fbecb3989..e919bbadb 100644 --- a/hphp/runtime/base/hphp_array-defs.h +++ b/hphp/runtime/base/hphp_array-defs.h @@ -119,7 +119,6 @@ inline const HphpArray* HphpArray::asHphpArray(const ArrayData* ad) { inline HphpArray* HphpArray::asVector(ArrayData* ad) { assert(ad->kind() == kVectorKind); - assert(dynamic_cast(ad)); auto a = static_cast(ad); assert(a->checkInvariants()); return a; @@ -127,7 +126,6 @@ inline HphpArray* HphpArray::asVector(ArrayData* ad) { inline const HphpArray* HphpArray::asVector(const ArrayData* ad) { assert(ad->kind() == kVectorKind); - 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 c3c0d1d8d..3b05a6d25 100644 --- a/hphp/runtime/base/hphp_array.cpp +++ b/hphp/runtime/base/hphp_array.cpp @@ -46,7 +46,7 @@ namespace HPHP { static_assert( - sizeof(HphpArray) == 160, + sizeof(HphpArray) == 152, "Performance is sensitive to sizeof(HphpArray)." " Make sure you changed it with good reason and then update this assert."); @@ -238,7 +238,7 @@ HOT_FUNC_VM void HphpArray::ReleaseVec(ArrayData* ad) { auto a = asVector(ad); a->destroyVec(); - if (UNLIKELY(a->strongIterators() != nullptr)) a->freeStrongIterators(); + a->ArrayData::destroy(); HphpArray::AllocatorType::getNoCheck()->dealloc(a); } @@ -246,7 +246,7 @@ HOT_FUNC_VM void HphpArray::Release(ArrayData* ad) { auto a = asGeneric(ad); a->destroy(); - if (UNLIKELY(a->strongIterators() != nullptr)) a->freeStrongIterators(); + a->ArrayData::destroy(); HphpArray::AllocatorType::getNoCheck()->dealloc(a); } @@ -1455,15 +1455,18 @@ HphpArray::RemoveStr(ArrayData* ad, const StringData* key, bool copy) { return a->erase(a->findForInsert(key, key->hash())); } -ArrayData* HphpArray::copy() const { - assert(checkInvariants()); - return copyImpl(); +ArrayData* HphpArray::CopyVec(const ArrayData* ad) { + return asVector(ad)->copyVec(); } -ArrayData* HphpArray::copyWithStrongIterators() const { - assert(checkInvariants()); - HphpArray* copied = copyImpl(); - moveStrongIterators(copied, const_cast(this)); +ArrayData* HphpArray::Copy(const ArrayData* ad) { + return asGeneric(ad)->copyGeneric(); +} + +ArrayData* HphpArray::CopyWithStrongIterators(const ArrayData* ad) { + auto a = asHphpArray(ad); + auto copied = a->copyImpl(); + moveStrongIterators(copied, const_cast(a)); return copied; } @@ -1590,32 +1593,38 @@ ArrayData* HphpArray::AddNewElemC(ArrayData* a, TypedValue value) { return genericAddNewElemC(a, value); } -ArrayData* HphpArray::appendRef(CVarRef v, bool copy) { - assert(checkInvariants()); - HphpArray *a = !copy ? this : copyImpl(); - if (a->isVector()) { - auto &tv = a->allocNextElm(a->m_size); - tvAsUninitializedVariant(&tv).constructRefHelper(v); - return a; - } +ArrayData* HphpArray::AppendRefVec(ArrayData* ad, CVarRef v, bool copy) { + auto a = asVector(ad); + if (copy) a = a->copyVec(); + auto &tv = a->allocNextElm(a->m_size); + tvAsUninitializedVariant(&tv).constructRefHelper(v); + return a; +} + +ArrayData* HphpArray::AppendRef(ArrayData* ad, CVarRef v, bool copy) { + auto a = asGeneric(ad); + if (copy) a = a->copyGeneric(); return a->nextInsertRef(v); } -ArrayData *HphpArray::appendWithRef(CVarRef v, bool copy) { - assert(checkInvariants()); - HphpArray *a = !copy ? this : copyImpl(); - if (a->isVector()) { - auto& tv = a->allocNextElm(a->m_size); - tvWriteNull(&tv); - tvAsVariant(&tv).setWithRef(v); - return a; - } +ArrayData *HphpArray::AppendWithRefVec(ArrayData* ad, CVarRef v, bool copy) { + auto a = asVector(ad); + if (copy) a = a->copyVec(); + auto& tv = a->allocNextElm(a->m_size); + tvWriteNull(&tv); + tvAsVariant(&tv).setWithRef(v); + return a; +} + +ArrayData *HphpArray::AppendWithRef(ArrayData* ad, CVarRef v, bool copy) { + auto a = asGeneric(ad); + if (copy) a = a->copyGeneric(); return a->nextInsertWithRef(v); } -ArrayData* HphpArray::plus(const ArrayData* elems, bool copy) { - assert(checkInvariants()); - HphpArray* a = !copy ? this : copyImpl(); +ArrayData* HphpArray::Plus(ArrayData* ad, const ArrayData* elems, bool copy) { + auto a = asHphpArray(ad); + if (copy) a = a->copyImpl(); if (a->isVector()) { // todo t2606310: is there a fast path if elems is also a vector? a->vectorToGeneric(); @@ -1632,9 +1641,9 @@ ArrayData* HphpArray::plus(const ArrayData* elems, bool copy) { return a; } -ArrayData* HphpArray::merge(const ArrayData* elems, bool copy) { - assert(checkInvariants()); - HphpArray* a = !copy ? this : copyImpl(); +ArrayData* HphpArray::Merge(ArrayData* ad, const ArrayData* elems, bool copy) { + auto a = asHphpArray(ad); + if (copy) a = a->copyImpl(); if (a->isVector()) { // todo t2606310: is there a fast path if elems is also a vector? a->vectorToGeneric(); @@ -1654,22 +1663,30 @@ ArrayData* HphpArray::merge(const ArrayData* elems, bool copy) { return a; } -ArrayData* HphpArray::pop(Variant& value) { - assert(checkInvariants()); - HphpArray* a = getCount() <= 1 ? this : copyImpl(); +ArrayData* HphpArray::PopVec(ArrayData* ad, Variant& value) { + auto a = asVector(ad); + if (a->getCount() > 1) a = a->copyImpl(); + if (a->m_size > 0) { + auto i = a->m_size - 1; + value = tvAsCVarRef(&a->m_data[i].data); + a->m_size = a->m_used = i; + a->m_pos = i > 0 ? 0 : invalid_index; // reset internal iterator + } else { + value = uninit_null(); + a->m_pos = invalid_index; // reset internal iterator + } + return a; +} + +ArrayData* HphpArray::Pop(ArrayData* ad, Variant& value) { + auto a = asGeneric(ad); + if (a->getCount() > 1) a = a->copyImpl(); Elm* elms = a->m_data; ElmInd pos = IterEnd(a); if (validElmInd(pos)) { Elm* e = &elms[pos]; assert(!isTombstone(e->data.m_type)); value = tvAsCVarRef(&e->data); - if (a->isVector()) { - assert(pos == a->m_size - 1); - a->m_size = a->m_used = pos; - a->m_pos = pos ? 0 : invalid_index; - tvRefcountedDecRef(&e->data); - return a; - } ElmInd* ei = e->hasStrKey() ? a->findForInsert(e->key, e->hash()) : a->findForInsert(e->ikey); @@ -1683,9 +1700,9 @@ ArrayData* HphpArray::pop(Variant& value) { return a; } -ArrayData* HphpArray::dequeue(Variant& value) { - assert(checkInvariants()); - HphpArray* a = getCount() <= 1 ? this : copyImpl(); +ArrayData* HphpArray::Dequeue(ArrayData* ad, Variant& value) { + auto a = asHphpArray(ad); + if (a->getCount() > 1) a = a->copyImpl(); // To conform to PHP behavior, we invalidate all strong iterators when an // element is removed from the beginning of the array. a->freeStrongIterators(); @@ -1717,9 +1734,9 @@ ArrayData* HphpArray::dequeue(Variant& value) { return a; } -ArrayData* HphpArray::prepend(CVarRef v, bool copy) { - assert(checkInvariants()); - HphpArray* a = getCount() <= 1 ? this : copyImpl(); +ArrayData* HphpArray::Prepend(ArrayData* ad, CVarRef v, bool copy) { + auto a = asHphpArray(ad); + if (a->getCount() > 1) a = a->copyImpl(); if (a->isVector()) { // todo t2606310: fast path - same as add for empty vectors a->vectorToGeneric(); @@ -1757,69 +1774,71 @@ ArrayData* HphpArray::prepend(CVarRef v, bool copy) { return a; } -void HphpArray::renumber() { - assert(checkInvariants()); - if (isVector()) { - // iterators don't move and nothing else happens. - return; - } - compact(true); +void HphpArray::RenumberVec(ArrayData* ad) { + assert(asVector(ad)); // for the checkInvariants() call + // renumber has no effect on Vector and doesn't move internal pos } -void HphpArray::onSetEvalScalar() { - assert(checkInvariants()); - Elm* elms = m_data; - if (isVector()) { - for (uint32_t i = 0, limit = m_used; i < limit; ++i) { - tvAsVariant(&elms[i].data).setEvalScalar(); - } - } else { - for (uint32_t i = 0, limit = m_used; i < limit; ++i) { - Elm* e = &elms[i]; - if (!isTombstone(e->data.m_type)) { - StringData *key = e->key; - if (e->hasStrKey() && !key->isStatic()) { - e->key = StringData::GetStaticString(key); - decRefStr(key); - } - tvAsVariant(&e->data).setEvalScalar(); +void HphpArray::Renumber(ArrayData* ad) { + asGeneric(ad)->compact(true); +} + +void HphpArray::OnSetEvalScalarVec(ArrayData* ad) { + auto a = asVector(ad); + Elm* elms = a->m_data; + for (uint32_t i = 0, limit = a->m_size; i < limit; ++i) { + tvAsVariant(&elms[i].data).setEvalScalar(); + } +} + +void HphpArray::OnSetEvalScalar(ArrayData* ad) { + auto a = asGeneric(ad); + Elm* elms = a->m_data; + for (uint32_t i = 0, limit = a->m_used; i < limit; ++i) { + Elm* e = &elms[i]; + if (!isTombstone(e->data.m_type)) { + StringData *key = e->key; + if (e->hasStrKey() && !key->isStatic()) { + e->key = StringData::GetStaticString(key); + decRefStr(key); } + tvAsVariant(&e->data).setEvalScalar(); } } } -bool HphpArray::validFullPos(const FullPos &fp) const { - assert(checkInvariants()); - assert(fp.getContainer() == (ArrayData*)this); +bool HphpArray::ValidFullPos(const ArrayData* ad, const FullPos &fp) { + assert(fp.getContainer() == asHphpArray(ad)); if (fp.getResetFlag()) return false; return (fp.m_pos != ssize_t(ElmIndEmpty)); } -bool HphpArray::advanceFullPos(FullPos& fp) { - assert(checkInvariants()); - Elm* elms = m_data; +bool HphpArray::AdvanceFullPos(ArrayData* ad, FullPos& fp) { + auto a = asHphpArray(ad); + Elm* elms = a->m_data; if (fp.getResetFlag()) { fp.setResetFlag(false); fp.m_pos = ElmIndEmpty; } else if (fp.m_pos == ssize_t(ElmIndEmpty)) { return false; } - fp.m_pos = nextElm(elms, fp.m_pos); + fp.m_pos = a->nextElm(elms, fp.m_pos); if (fp.m_pos == ssize_t(ElmIndEmpty)) { return false; } // To conform to PHP behavior, we need to set the internal // cursor to point to the next element. - m_pos = nextElm(elms, fp.m_pos); + a->m_pos = a->nextElm(elms, fp.m_pos); return true; } //============================================================================= -NEVER_INLINE ArrayData* HphpArray::nonSmartCopy() const { - return isVector() ? - new HphpArray(*this, AllocationMode::nonSmart, CopyVector()) : - new HphpArray(*this, AllocationMode::nonSmart, CopyGeneric()); +NEVER_INLINE ArrayData* HphpArray::NonSmartCopy(const ArrayData* ad) { + auto a = asHphpArray(ad); + return a->isVector() ? + new HphpArray(*a, AllocationMode::nonSmart, CopyVector()) : + new HphpArray(*a, AllocationMode::nonSmart, CopyGeneric()); } NEVER_INLINE HphpArray* HphpArray::copyVec() const { diff --git a/hphp/runtime/base/hphp_array.h b/hphp/runtime/base/hphp_array.h index 08ec88a5b..4bbc5e5a4 100644 --- a/hphp/runtime/base/hphp_array.h +++ b/hphp/runtime/base/hphp_array.h @@ -70,7 +70,7 @@ public: // moving (without refcounting) and reversing vals. HphpArray(uint size, const TypedValue* vals); // make tuple - virtual ~HphpArray(); + ~HphpArray(); void destroyVec(); void destroy(); @@ -177,30 +177,36 @@ public: static ArrayData* RemoveIntVec(ArrayData*, int64_t k, bool copy); static ArrayData* RemoveStrVec(ArrayData*, const StringData* k, bool copy); - // overrides/implements ArrayData - ArrayData* copy() const; - ArrayData* copyWithStrongIterators() const; + // overrides ArrayData + static ArrayData* Copy(const ArrayData*); + static ArrayData* CopyVec(const ArrayData*); + static ArrayData* CopyWithStrongIterators(const ArrayData*); + static ArrayData* NonSmartCopy(const ArrayData*); - ArrayData* nonSmartCopy() const; HphpArray* copyImpl() const; HphpArray* copyVec() const; HphpArray* copyGeneric() const; static ArrayData* AppendVec(ArrayData*, CVarRef v, bool copy); static ArrayData* Append(ArrayData*, CVarRef v, bool copy); - ArrayData* appendRef(CVarRef v, bool copy); - ArrayData* appendWithRef(CVarRef v, bool copy); - ArrayData* plus(const ArrayData* elems, bool copy); - ArrayData* merge(const ArrayData* elems, bool copy); - ArrayData* pop(Variant& value); - ArrayData* dequeue(Variant& value); - ArrayData* prepend(CVarRef v, bool copy); - void renumber(); - void onSetEvalScalar(); + static ArrayData* AppendRef(ArrayData*, CVarRef v, bool copy); + static ArrayData* AppendRefVec(ArrayData*, CVarRef v, bool copy); + static ArrayData* AppendWithRef(ArrayData*, CVarRef v, bool copy); + static ArrayData* AppendWithRefVec(ArrayData*, CVarRef v, bool copy); + static ArrayData* Plus(ArrayData*, const ArrayData* elems, bool copy); + static ArrayData* Merge(ArrayData*, const ArrayData* elems, bool copy); + static ArrayData* Pop(ArrayData*, Variant& value); + static ArrayData* PopVec(ArrayData*, Variant& value); + static ArrayData* Dequeue(ArrayData*, Variant& value); + static ArrayData* Prepend(ArrayData*, CVarRef v, bool copy); + static void Renumber(ArrayData*); + static void RenumberVec(ArrayData*); + static void OnSetEvalScalar(ArrayData*); + static void OnSetEvalScalarVec(ArrayData*); // overrides ArrayData - bool validFullPos(const FullPos &fp) const; - bool advanceFullPos(FullPos& fp); + static bool ValidFullPos(const ArrayData*, const FullPos &fp); + static bool AdvanceFullPos(ArrayData*, FullPos& fp); // END overide/implements section @@ -245,13 +251,13 @@ private: void postSort(bool resetKeys); public: - ArrayData* escalateForSort(); - void ksort(int sort_flags, bool ascending); - void sort(int sort_flags, bool ascending); - void asort(int sort_flags, bool ascending); - void uksort(CVarRef cmp_function); - void usort(CVarRef cmp_function); - void uasort(CVarRef cmp_function); + static ArrayData* EscalateForSort(ArrayData* ad); + static void Ksort(ArrayData*, int sort_flags, bool ascending); + static void Sort(ArrayData*, int sort_flags, bool ascending); + static void Asort(ArrayData*, int sort_flags, bool ascending); + static void Uksort(ArrayData*, CVarRef cmp_function); + static void Usort(ArrayData*, CVarRef cmp_function); + static void Uasort(ArrayData*, CVarRef cmp_function); // Elm's data.m_type == KindOfInvalid for deleted slots. static bool isTombstone(DataType t) { diff --git a/hphp/runtime/base/hphp_array_sort.cpp b/hphp/runtime/base/hphp_array_sort.cpp index 9c649300a..a25074297 100644 --- a/hphp/runtime/base/hphp_array_sort.cpp +++ b/hphp/runtime/base/hphp_array_sort.cpp @@ -143,19 +143,19 @@ void HphpArray::postSort(bool resetKeys) { m_hLoad = m_size; } -ArrayData* HphpArray::escalateForSort() { +ArrayData* HphpArray::EscalateForSort(ArrayData* ad) { // task #1910931 only do this for refCount() > 1 - return copyImpl(); + return asHphpArray(ad)->copyImpl(); } #define SORT_CASE(flag, cmp_type, acc_type) \ case flag: { \ if (ascending) { \ cmp_type##Compare comp; \ - HPHP::Sort::sort(m_data, m_data + m_size, comp); \ + HPHP::Sort::sort(a->m_data, a->m_data + a->m_size, comp); \ } else { \ cmp_type##Compare comp; \ - HPHP::Sort::sort(m_data, m_data + m_size, comp); \ + HPHP::Sort::sort(a->m_data, a->m_data + a->m_size, comp); \ } \ break; \ } @@ -179,34 +179,37 @@ ArrayData* HphpArray::escalateForSort() { } #define SORT_BODY(acc_type, resetKeys) \ do { \ - freeStrongIterators(); \ - if (!m_size) { \ + a->freeStrongIterators(); \ + if (!a->m_size) { \ if (resetKeys) { \ - m_nextKI = 0; \ + a->m_nextKI = 0; \ } \ return; \ } \ - SortFlavor flav = preSort(acc_type(), true); \ - m_pos = ssize_t(0); \ + SortFlavor flav = a->preSort(acc_type(), true); \ + a->m_pos = ssize_t(0); \ try { \ CALL_SORT(acc_type); \ } catch (...) { \ /* Make sure we leave the array in a consistent state */ \ - postSort(resetKeys); \ + a->postSort(resetKeys); \ throw; \ } \ - postSort(resetKeys); \ + a->postSort(resetKeys); \ } while (0) -void HphpArray::ksort(int sort_flags, bool ascending) { +void HphpArray::Ksort(ArrayData* ad, int sort_flags, bool ascending) { + auto a = asHphpArray(ad); SORT_BODY(KeyAccessor, false); } -void HphpArray::sort(int sort_flags, bool ascending) { +void HphpArray::Sort(ArrayData* ad, int sort_flags, bool ascending) { + auto a = asHphpArray(ad); SORT_BODY(ValAccessor, true); } -void HphpArray::asort(int sort_flags, bool ascending) { +void HphpArray::Asort(ArrayData* ad, int sort_flags, bool ascending) { + auto a = asHphpArray(ad); SORT_BODY(ValAccessor, false); } @@ -216,39 +219,42 @@ void HphpArray::asort(int sort_flags, bool ascending) { #define USER_SORT_BODY(acc_type, resetKeys) \ do { \ - freeStrongIterators(); \ - if (!m_size) { \ + a->freeStrongIterators(); \ + if (!a->m_size) { \ if (resetKeys) { \ - m_nextKI = 0; \ + a->m_nextKI = 0; \ } \ return; \ } \ - preSort(acc_type(), false); \ - m_pos = ssize_t(0); \ + a->preSort(acc_type(), false); \ + a->m_pos = ssize_t(0); \ try { \ ElmUCompare comp; \ - Transl::CallerFrame cf; \ + Transl::CallerFrame cf; \ CallCtx ctx; \ vm_decode_function(cmp_function, cf(), false, ctx); \ comp.ctx = &ctx; \ - HPHP::Sort::sort(m_data, m_data + m_size, comp); \ + HPHP::Sort::sort(a->m_data, a->m_data + a->m_size, comp); \ } catch (...) { \ /* Make sure we leave the array in a consistent state */ \ - postSort(resetKeys); \ + a->postSort(resetKeys); \ throw; \ } \ - postSort(resetKeys); \ + a->postSort(resetKeys); \ } while (0) -void HphpArray::uksort(CVarRef cmp_function) { +void HphpArray::Uksort(ArrayData* ad, CVarRef cmp_function) { + auto a = asHphpArray(ad); USER_SORT_BODY(KeyAccessor, false); } -void HphpArray::usort(CVarRef cmp_function) { +void HphpArray::Usort(ArrayData* ad, CVarRef cmp_function) { + auto a = asHphpArray(ad); USER_SORT_BODY(ValAccessor, true); } -void HphpArray::uasort(CVarRef cmp_function) { +void HphpArray::Uasort(ArrayData* ad, CVarRef cmp_function) { + auto a = asHphpArray(ad); USER_SORT_BODY(ValAccessor, false); } diff --git a/hphp/runtime/base/policy_array.cpp b/hphp/runtime/base/policy_array.cpp index d1c27892a..af756a9e7 100644 --- a/hphp/runtime/base/policy_array.cpp +++ b/hphp/runtime/base/policy_array.cpp @@ -208,7 +208,7 @@ PolicyArray::PolicyArray(const PolicyArray& rhs, uint capacity, PolicyArray::~PolicyArray() { APILOG(this) << "()"; - destroy(m_size, m_allocMode); + SimpleArrayStore::destroy(m_size, m_allocMode); } void PolicyArray::Release(ArrayData* ad) { @@ -217,13 +217,11 @@ void PolicyArray::Release(ArrayData* ad) { inline PolicyArray* PolicyArray::asPolicyArray(ArrayData* ad) { assert(ad->kind() == kPolicyKind); - assert(dynamic_cast(ad)); return static_cast(ad); } inline const PolicyArray* PolicyArray::asPolicyArray(const ArrayData* ad) { assert(ad->kind() == kPolicyKind); - assert(dynamic_cast(ad)); return static_cast(ad); } @@ -285,7 +283,7 @@ ArrayData *PolicyArray::lvalImpl(K k, Variant*& ret, bool copy) { << copy << ", " << ")"; if (copy) { - return PolicyArray::copy()->lvalImpl(k, ret, false); + return asPolicyArray(Copy(this))->lvalImpl(k, ret, false); } PosType pos = find(k, m_size); @@ -319,7 +317,7 @@ ArrayData* PolicyArray::LvalStr(ArrayData* ad, StringData* k, Variant*& ret, ArrayData *PolicyArray::LvalNew(ArrayData* ad, Variant *&ret, bool copy) { auto a = asPolicyArray(ad); - if (copy) a = a->PolicyArray::copy(); + if (copy) a = asPolicyArray(Copy(a)); // Andrei: TODO - append() currently never fails, probably it // should. @@ -346,9 +344,7 @@ ArrayData *PolicyArray::GetLvalPtr(ArrayData* ad, StringData* k, Variant *&ret, bool copy) { auto a = asPolicyArray(ad); APILOG(a) << "(" << keystr(k) << ", " << ret << ", " << copy << ")"; - if (copy) { - return a->PolicyArray::copy()->getLvalPtr(k, ret, false); - } + if (copy) a = asPolicyArray(Copy(a)); const auto pos = a->find(k, a->m_size); ret = pos != PosType::invalid ? &a->Store::lval(pos) @@ -361,7 +357,7 @@ PolicyArray* PolicyArray::setImpl(K k, const Variant& v, bool copy) { APILOG(this) << "(" << keystr(k) << ", " << valstr(v) << ", " << copy << ")"; PolicyArray* result = this; - if (copy) result = PolicyArray::copy(); + if (copy) result = asPolicyArray(Copy(this)); 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; @@ -385,7 +381,7 @@ ArrayData *PolicyArray::setRefImpl(K k, CVarRef v, bool copy) { APILOG(this) << "(" << keystr(k) << ", " << valstr(v) << ", " << copy << ")"; if (copy) { - return PolicyArray::copy()->setRef(k, v, false); + return asPolicyArray(Copy(this))->setRef(k, v, false); } auto const pos = find(k, m_size); @@ -446,7 +442,7 @@ template ArrayData* PolicyArray::addLvalImpl(K k, Variant*& ret, bool copy) { APILOG(this) << "(" << k << ", " << ret << ", " << copy << ")"; if (copy) { - return PolicyArray::copy()->addLval(k, ret, false); + return asPolicyArray(Copy(this))->addLval(k, ret, false); } assert(!exists(k) && m_size <= capacity()); if (m_size == capacity()) { @@ -472,7 +468,7 @@ ArrayData *PolicyArray::removeImpl(K k, bool copy) { APILOG(this) << "(" << keystr(k) << ", " << copy << ")"; if (copy) { - return PolicyArray::copy()->remove(k, false); + return asPolicyArray(Copy(this))->remove(k, false); } auto const pos = find(k, m_size); @@ -541,28 +537,30 @@ ssize_t PolicyArray::IterRewind(const ArrayData* ad, ssize_t prev) { return toInt(a->prevIndex(toPos(prev), a->m_size)); } -bool PolicyArray::validFullPos(const FullPos& fp) const { - APILOG(this) << "(" << fp.m_pos << ";" << fp.getResetFlag() << ")"; - assert(fp.getContainer() == this); +bool PolicyArray::ValidFullPos(const ArrayData* ad, const FullPos& fp) { + auto a = asPolicyArray(ad); + APILOG(a) << "(" << fp.m_pos << ";" << fp.getResetFlag() << ")"; + assert(fp.getContainer() == a); return fp.m_pos != invalid_index; } -bool PolicyArray::advanceFullPos(FullPos &fp) { - APILOG(this) << "(" << fp.m_pos << ";" << fp.getResetFlag() << ")"; - assert(fp.getContainer() == this); +bool PolicyArray::AdvanceFullPos(ArrayData* ad, FullPos &fp) { + auto a = asPolicyArray(ad); + APILOG(a) << "(" << fp.m_pos << ";" << fp.getResetFlag() << ")"; + assert(fp.getContainer() == a); if (fp.getResetFlag()) { fp.setResetFlag(false); fp.m_pos = invalid_index; } else if (fp.m_pos == invalid_index) { return false; } - fp.m_pos = toInt(nextIndex(toPos(fp.m_pos), m_size)); + fp.m_pos = toInt(a->nextIndex(toPos(fp.m_pos), a->m_size)); if (fp.m_pos == invalid_index) { return false; } // To conform to PHP behavior, we need to set the internal // cursor to point to the next element. - m_pos = toInt(nextIndex(toPos(fp.m_pos), m_size)); + a->m_pos = toInt(a->nextIndex(toPos(fp.m_pos), a->m_size)); return true; } @@ -578,17 +576,17 @@ HphpArray* PolicyArray::toHphpArray() const { return result; } -ArrayData* PolicyArray::escalateForSort() { - APILOG(this) << "()"; - return toHphpArray(); +ArrayData* PolicyArray::EscalateForSort(ArrayData* ad) { + auto a = asPolicyArray(ad); + APILOG(a) << "()"; + return a->toHphpArray(); } -PolicyArray *PolicyArray::copy() const { - APILOG(this) << "()"; - auto result = NEW(PolicyArray)( - *this, - capacity() + (m_size == capacity()), - m_allocMode); +ArrayData* PolicyArray::Copy(const ArrayData* ad) { + auto a = asPolicyArray(ad); + APILOG(a) << "()"; + auto result = NEW(PolicyArray)(*a, + a->capacity() + (a->m_size == a->capacity()), a->m_allocMode); assert(result->getCount() == 0); return result; } @@ -598,58 +596,56 @@ PolicyArray* PolicyArray::copy(uint capacity) { return NEW(PolicyArray)(*this, capacity, m_allocMode); } -PolicyArray *PolicyArray::copyWithStrongIterators() const { - APILOG(this) << "()"; - auto result = PolicyArray::copy(); - moveStrongIterators(result, const_cast(this)); +ArrayData* PolicyArray::CopyWithStrongIterators(const ArrayData* ad) { + auto a = asPolicyArray(ad); + APILOG(a) << "()"; + auto result = Copy(a); + moveStrongIterators(result, const_cast(a)); assert(result->getCount() == 0); return result; } -ArrayData *PolicyArray::nonSmartCopy() const { - APILOG(this) << "()"; - //return NEW(PolicyArray)(*this, capacity(), true); - return toHphpArray()->nonSmartCopy(); +ArrayData* PolicyArray::NonSmartCopy(const ArrayData* ad) { + auto a = asPolicyArray(ad); + APILOG(a) << "()"; + return a->toHphpArray()->nonSmartCopy(); } -ArrayData *PolicyArray::Append(ArrayData* ad, const Variant& v, bool copy) { - auto a = static_cast(ad); +ArrayData* PolicyArray::Append(ArrayData* ad, const Variant& v, bool copy) { + auto a = asPolicyArray(ad); APILOG(a) << "(" << valstr(v) << ", " << copy << ")"; - if (copy) a = a->PolicyArray::copy(); + if (copy) a = asPolicyArray(Copy(a)); a->grow(a->m_size, a->m_size + 1, a->m_size * 2 + 1, a->m_allocMode); a->appendNoGrow(a->nextKeyBump(), v); return a; } -PolicyArray *PolicyArray::appendRef(const Variant& v, bool copy) { - APILOG(this) << "(" << valstr(v) << ", " << copy << ")"; - if (copy) { - return PolicyArray::copy()->appendRef(v, false); +ArrayData* PolicyArray::AppendRef(ArrayData* ad, const Variant& v, bool copy) { + auto a = asPolicyArray(ad); + APILOG(a) << "(" << valstr(v) << ", " << copy << ")"; + if (copy) a = asPolicyArray(Copy(a)); + auto const k = a->nextKeyBump(); + if (a->m_size == a->capacity()) { + a->grow(a->m_size, a->m_size + 1, a->m_size * 2 + 1, a->m_allocMode); } - //addValWithRef(nextKeyBump(), v); - auto const k = nextKeyBump(); - if (m_size == capacity()) { - grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode); - } - assert(m_size < capacity()); - appendNoGrow(k, Variant::NoInit())->constructRefHelper(v); - return this; + assert(a->m_size < a->capacity()); + a->appendNoGrow(k, Variant::NoInit())->constructRefHelper(v); + return a; } /** * Similar to append(v, copy), with reference in v preserved. */ -ArrayData *PolicyArray::appendWithRef(CVarRef v, bool copy) { - APILOG(this) << "(" << valstr(v) << ", " << copy << ")"; - if (copy) { - return PolicyArray::copy()->appendWithRef(v, false); +ArrayData* PolicyArray::AppendWithRef(ArrayData* ad, CVarRef v, bool copy) { + auto a = asPolicyArray(ad); + APILOG(a) << "(" << valstr(v) << ", " << copy << ")"; + if (copy) a = asPolicyArray(Copy(a)); + if (a->m_size == a->capacity()) { + a->grow(a->m_size, a->m_size + 1, a->m_size * 2 + 1, a->m_allocMode); } - if (m_size == capacity()) { - grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode); - } - assert(m_size < capacity()); - appendNoGrow(nextKeyBump(), Variant::NullInit())->setWithRef(v); - return this; + assert(a->m_size < a->capacity()); + a->appendNoGrow(a->nextKeyBump(), Variant::NullInit())->setWithRef(v); + return a; } template @@ -688,127 +684,125 @@ void PolicyArray::nextInsertWithRef(const Variant& v) { appendNoGrow(k, Variant::NullInit())->setWithRef(v); } -ArrayData *PolicyArray::plus(const ArrayData *elems, bool copy) { - APILOG(this) << "(" << elems << ", " << copy << ")"; - if (copy) { - return PolicyArray::copy()->plus(elems, false); - } +ArrayData* +PolicyArray::Plus(ArrayData* ad, const ArrayData *elems, bool copy) { + auto a = asPolicyArray(ad); + APILOG(a) << "(" << elems << ", " << copy << ")"; + if (copy) a = asPolicyArray(Copy(a)); assert(elems); - grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode); + a->grow(a->m_size, a->m_size + 1, a->m_size * 2 + 1, a->m_allocMode); for (ArrayIter it(elems); !it.end(); it.next()) { Variant key = it.first(); const Variant& value = it.secondRef(); if (key.isNumeric()) { - addValWithRef(key.toInt64(), value); + a->addValWithRef(key.toInt64(), value); } else { - addValWithRef(key.getStringData(), value); + a->addValWithRef(key.getStringData(), value); } } - return this; + return a; } -ArrayData *PolicyArray::merge(const ArrayData *elems, bool copy) { - APILOG(this) << "(" << elems << ", " << copy << ")"; - if (copy) { - return PolicyArray::copy()->merge(elems, false); - } +ArrayData* +PolicyArray::Merge(ArrayData* ad, const ArrayData *elems, bool copy) { + auto a = asPolicyArray(ad); + APILOG(a) << "(" << elems << ", " << copy << ")"; + if (copy) a = asPolicyArray(Copy(a)); assert(elems); - grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode); + a->grow(a->m_size, a->m_size + 1, a->m_size * 2 + 1, a->m_allocMode); for (ArrayIter it(elems); !it.end(); it.next()) { Variant key = it.first(); const Variant& value = it.secondRef(); if (key.isNumeric()) { - nextInsertWithRef(value); + a->nextInsertWithRef(value); } else { StringData *s = key.getStringData(); Variant *p; // Andrei TODO: make sure this is the right semantics - LvalStr(this, s, p, false); + LvalStr(a, s, p, false); p->setWithRef(value); } } - return this; + return a; } - /** - * Stack function: pop the last item and return it. - */ -ArrayData* PolicyArray::pop(Variant &value) { - APILOG(this) << "(" << &value << ")"; - if (getCount() > 1) { - return PolicyArray::copy()->pop(value); - } - if (!m_size) { +/** + * Stack function: pop the last item and return it. + */ +ArrayData* PolicyArray::Pop(ArrayData* ad, Variant &value) { + auto a = asPolicyArray(ad); + APILOG(a) << "(" << &value << ")"; + if (a->getCount() > 1) a = asPolicyArray(Copy(a)); + if (!a->m_size) { value = uninit_null(); - return this; + return a; } - auto pos = lastIndex(m_size); - assert(size_t(pos) < m_size); - value = val(pos); + auto pos = a->lastIndex(a->m_size); + assert(size_t(pos) < a->m_size); + value = a->val(pos); // Match PHP 5.3.1 semantics - if (!hasStrKey(pos) - && Store::nextKey() == 1 + key(pos).toInt64()) { - nextKeyPop(); + if (!a->hasStrKey(pos) + && a->Store::nextKey() == 1 + a->key(pos).toInt64()) { + a->nextKeyPop(); } - Store::erase(pos, m_size); - --m_size; + a->Store::erase(pos, a->m_size); + --a->m_size; // To match PHP-like semantics, the pop operation resets the array's // internal iterator. - m_pos = m_size ? toInt(firstIndex(m_size)) : invalid_index; - return this; + a->m_pos = a->m_size ? toInt(a->firstIndex(a->m_size)) : + invalid_index; + return a; } -ArrayData *PolicyArray::dequeue(Variant &value) { - APILOG(this) << "(" << &value << ")"; - if (getCount() > 1) { - return PolicyArray::copy()->dequeue(value); - } +ArrayData* PolicyArray::Dequeue(ArrayData* ad, Variant &value) { + auto a = asPolicyArray(ad); + APILOG(a) << "(" << &value << ")"; + if (a->getCount() > 1) a = asPolicyArray(Copy(ad)); // To match PHP-like semantics, we invalidate all strong iterators when an // element is removed from the beginning of the array. - freeStrongIterators(); - if (!m_size) { + a->freeStrongIterators(); + if (!a->m_size) { value = uninit_null(); - return this; + return a; } - auto& front = lval(firstIndex(m_size)); + auto& front = a->lval(a->firstIndex(a->m_size)); value = std::move(front); new(&front) Variant; - erase(firstIndex(m_size), m_size); - --m_size; - renumber(); + a->erase(a->firstIndex(a->m_size), a->m_size); + --a->m_size; + a->renumber(); // To match PHP-like semantics, the dequeue operation resets the array's // internal iterator - m_pos = m_size ? toInt(firstIndex(m_size)) : invalid_index; - return this; + a->m_pos = a->m_size ? toInt(a->firstIndex(a->m_size)) : + invalid_index; + return a; } -ArrayData* PolicyArray::prepend(CVarRef v, bool copy) { - APILOG(this) << "(" << valstr(v) << ", " << copy << ")"; - if (copy) { - return PolicyArray::copy()->prepend(v, false); - } +ArrayData* PolicyArray::Prepend(ArrayData* ad, CVarRef v, bool copy) { + auto a = asPolicyArray(ad); + APILOG(a) << "(" << valstr(v) << ", " << copy << ")"; + if (copy) a = asPolicyArray(Copy(a)); // 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_allocMode); - ++m_size; - auto first = firstIndex(m_size); - setKey(first, int64_t(0)); - // Renumber. - renumber(); + a->freeStrongIterators(); + a->Store::prepend(v, a->m_size, a->m_allocMode); + ++a->m_size; + auto first = a->firstIndex(a->m_size); + a->setKey(first, int64_t(0)); + a->renumber(); // To match PHP-like semantics, the prepend operation resets the array's // internal iterator - m_pos = toInt(first); - return this; + a->m_pos = toInt(first); + return a; } void PolicyArray::renumber() { @@ -867,30 +861,36 @@ void PolicyArray::renumber() { assert(i == siKeys.cend()); } -void PolicyArray::onSetEvalScalar() { - APILOG(this) << "()"; +void PolicyArray::Renumber(ArrayData* ad) { + return asPolicyArray(ad)->renumber(); +} + +void PolicyArray::OnSetEvalScalar(ArrayData* ad) { + auto a = asPolicyArray(ad); + APILOG(a) << "()"; //FOR_EACH_RANGE (pos, 0, m_size) { - for (auto pos = firstIndex(m_size); pos != PosType::invalid; - pos = nextIndex(pos, m_size)) { - if (hasStrKey(pos)) { - auto k = key(pos).getStringData(); + for (auto pos = a->firstIndex(a->m_size); pos != PosType::invalid; + pos = a->nextIndex(pos, a->m_size)) { + if (a->hasStrKey(pos)) { + auto k = a->key(pos).getStringData(); if (!k->isStatic()) { auto sk = StringData::GetStaticString(k); if (k->decRefCount() == 0) { DELETE(StringData)(k); } // Andrei TODO: inefficient, does one incref and then decref - setKey(pos, sk); + a->setKey(pos, sk); sk->decRefCount(); } } - lval(pos).setEvalScalar(); + a->lval(pos).setEvalScalar(); } } -ArrayData *PolicyArray::escalate() const { - APILOG(this) << "()"; - return ArrayData::escalate(); +ArrayData *PolicyArray::Escalate(const ArrayData* ad) { + auto a = asPolicyArray(ad); + APILOG(a) << "()"; + return ArrayData::Escalate(a); } } // namespace HPHP diff --git a/hphp/runtime/base/policy_array.h b/hphp/runtime/base/policy_array.h index c8fd708d1..ff20136c5 100644 --- a/hphp/runtime/base/policy_array.h +++ b/hphp/runtime/base/policy_array.h @@ -329,7 +329,7 @@ public: explicit PolicyArray(uint size); - virtual ~PolicyArray() FOLLY_OVERRIDE; + ~PolicyArray(); /** * getValueRef() gets a reference to value at position "pos". @@ -475,16 +475,16 @@ public: * This will return false if the iterator points past the last element, or * if the iterator points before the first element. */ - virtual bool validFullPos(const FullPos& fp) const FOLLY_OVERRIDE; + static bool ValidFullPos(const ArrayData*, const FullPos& fp); /** * Advances the mutable iterator to the next element in the array. Returns * false if the iterator has moved past the last element, otherwise returns * true. */ - virtual bool advanceFullPos(FullPos& fp) FOLLY_OVERRIDE; + static bool AdvanceFullPos(ArrayData* ad, FullPos& fp); - virtual ArrayData* escalateForSort() FOLLY_OVERRIDE; + static ArrayData* EscalateForSort(ArrayData* ad); /** * Make a copy of myself. @@ -494,9 +494,9 @@ public: * into the static array list. */ PolicyArray* copy(uint minCapacity); - virtual PolicyArray *copy() const FOLLY_OVERRIDE; - virtual PolicyArray *copyWithStrongIterators() const FOLLY_OVERRIDE; - virtual ArrayData *nonSmartCopy() const FOLLY_OVERRIDE; + static ArrayData* Copy(const ArrayData* ad); + static ArrayData* CopyWithStrongIterators(const ArrayData* ad); + static ArrayData* NonSmartCopy(const ArrayData* ad); private: template @@ -520,44 +520,45 @@ public: * escalated array data. */ static ArrayData* Append(ArrayData*, CVarRef v, bool copy); - virtual PolicyArray *appendRef(CVarRef v, bool copy) FOLLY_OVERRIDE; + static ArrayData* AppendRef(ArrayData*, CVarRef v, bool copy); /** * Similar to append(v, copy), with reference in v preserved. */ - virtual ArrayData *appendWithRef(CVarRef v, bool copy) FOLLY_OVERRIDE; + static ArrayData* AppendWithRef(ArrayData*, CVarRef v, bool copy); /** * Implementing array appending and merging. If "copy" is true, make a copy * first then append/merge arrays. Return NULL if escalation is not needed, * or an escalated array data. */ - virtual ArrayData *plus(const ArrayData *elems, bool copy) FOLLY_OVERRIDE; - virtual ArrayData *merge(const ArrayData *elems, bool copy) FOLLY_OVERRIDE; + static ArrayData* Plus(ArrayData* ad, const ArrayData *elems, bool copy); + static ArrayData* Merge(ArrayData* ad, const ArrayData *elems, bool copy); /** * Stack function: pop the last item and return it. */ - virtual ArrayData *pop(Variant &value) FOLLY_OVERRIDE; + static ArrayData* Pop(ArrayData*, Variant &value); /** * Queue function: remove the 1st item and return it. */ - virtual ArrayData *dequeue(Variant &value) FOLLY_OVERRIDE; + static ArrayData* Dequeue(ArrayData*, Variant &value); /** * Array function: prepend a new item. */ - virtual ArrayData *prepend(CVarRef v, bool copy) FOLLY_OVERRIDE; + static ArrayData* Prepend(ArrayData*, CVarRef v, bool copy); /** * Only map classes need this. Re-index all numeric keys to start from 0. */ - virtual void renumber() FOLLY_OVERRIDE; + void renumber(); + static void Renumber(ArrayData*); - virtual void onSetEvalScalar() FOLLY_OVERRIDE; + static void OnSetEvalScalar(ArrayData*); - virtual ArrayData *escalate() const FOLLY_OVERRIDE; + static ArrayData* Escalate(const ArrayData*); }; /////////////////////////////////////////////////////////////////////////////// diff --git a/hphp/runtime/base/shared_map.cpp b/hphp/runtime/base/shared_map.cpp index 408377561..cfd246090 100644 --- a/hphp/runtime/base/shared_map.cpp +++ b/hphp/runtime/base/shared_map.cpp @@ -67,13 +67,11 @@ void SharedMap::Release(ArrayData* ad) { inline SharedMap* SharedMap::asSharedMap(ArrayData* ad) { assert(ad->kind() == kSharedKind); - assert(dynamic_cast(ad)); return static_cast(ad); } inline const SharedMap* SharedMap::asSharedMap(const ArrayData* ad) { assert(ad->kind() == kSharedKind); - assert(dynamic_cast(ad)); return static_cast(ad); } @@ -118,104 +116,103 @@ inline ArrayData* releaseIfCopied(ArrayData* a1, ArrayData* a2) { ArrayData *SharedMap::LvalInt(ArrayData* ad, int64_t k, Variant *&ret, bool copy) { - ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->lval(k, ret, false)); } ArrayData *SharedMap::LvalStr(ArrayData* ad, StringData* k, Variant *&ret, bool copy) { - ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->lval(k, ret, false)); } ArrayData *SharedMap::LvalNew(ArrayData* ad, Variant *&ret, bool copy) { - ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->lvalNew(ret, false)); } ArrayData* SharedMap::SetInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) { - ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->set(k, v, false)); } ArrayData* SharedMap::SetStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) { - ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->set(k, v, false)); } ArrayData* SharedMap::SetRefInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) { - ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->setRef(k, v, false)); } ArrayData* SharedMap::SetRefStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) { - ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->setRef(k, v, false)); } ArrayData *SharedMap::AddLvalInt(ArrayData* ad, int64_t k, Variant *&ret, bool copy) { - ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); + ArrayData *escalated = Escalate(ad); 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(); + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->addLval(k, ret, false)); } ArrayData *SharedMap::RemoveInt(ArrayData* ad, int64_t k, bool copy) { - ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->remove(k, false)); } ArrayData *SharedMap::RemoveStr(ArrayData* ad, const StringData* k, bool copy) { - ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate(); + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->remove(k, false)); } -ArrayData *SharedMap::copy() const { - return SharedMap::escalate(); +ArrayData* SharedMap::Copy(const ArrayData* ad) { + return Escalate(ad); } ArrayData *SharedMap::Append(ArrayData* ad, CVarRef v, bool copy) { - auto a = asSharedMap(ad); - ArrayData *escalated = a->SharedMap::escalate(); + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->append(v, false)); } -ArrayData *SharedMap::appendRef(CVarRef v, bool copy) { - ArrayData *escalated = SharedMap::escalate(); +ArrayData *SharedMap::AppendRef(ArrayData* ad, CVarRef v, bool copy) { + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->appendRef(v, false)); } -ArrayData *SharedMap::appendWithRef(CVarRef v, bool copy) { - ArrayData *escalated = SharedMap::escalate(); +ArrayData *SharedMap::AppendWithRef(ArrayData* ad, CVarRef v, bool copy) { + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->appendWithRef(v, false)); } -ArrayData *SharedMap::plus(const ArrayData *elems, bool copy) { - ArrayData *escalated = SharedMap::escalate(); +ArrayData *SharedMap::Plus(ArrayData* ad, const ArrayData *elems, bool copy) { + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->plus(elems, false)); } -ArrayData *SharedMap::merge(const ArrayData *elems, bool copy) { - ArrayData *escalated = SharedMap::escalate(); +ArrayData *SharedMap::Merge(ArrayData* ad, const ArrayData *elems, bool copy) { + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->merge(elems, false)); } -ArrayData *SharedMap::prepend(CVarRef v, bool copy) { - ArrayData *escalated = SharedMap::escalate(); +ArrayData *SharedMap::Prepend(ArrayData* ad, CVarRef v, bool copy) { + ArrayData *escalated = Escalate(ad); return releaseIfCopied(escalated, escalated->prepend(v, false)); } -ArrayData *SharedMap::escalate() const { - ArrayData *ret = loadElems(); +ArrayData *SharedMap::Escalate(const ArrayData* ad) { + auto ret = asSharedMap(ad)->loadElems(); assert(!ret->isStatic()); return ret; } @@ -249,8 +246,9 @@ void SharedMap::NvGetKey(const ArrayData* ad, TypedValue* out, ssize_t pos) { } } -ArrayData* SharedMap::escalateForSort() { - ArrayData *ret = loadElems(true /* mapInit */); +ArrayData* SharedMap::EscalateForSort(ArrayData* ad) { + auto a = asSharedMap(ad); + auto ret = a->loadElems(true /* mapInit */); assert(!ret->isStatic()); return ret; } @@ -279,12 +277,12 @@ ssize_t SharedMap::IterRewind(const ArrayData* ad, ssize_t prev) { return next >= 0 ? next : invalid_index; } -bool SharedMap::validFullPos(const FullPos& fp) const { - assert(fp.getContainer() == (ArrayData*)this); +bool SharedMap::ValidFullPos(const ArrayData* ad, const FullPos& fp) { + assert(fp.getContainer() == ad); return false; } -bool SharedMap::advanceFullPos(FullPos& fp) { +bool SharedMap::AdvanceFullPos(ArrayData* ad, FullPos& fp) { return false; } diff --git a/hphp/runtime/base/shared_map.h b/hphp/runtime/base/shared_map.h index bd3c72fa7..fa48ca83a 100644 --- a/hphp/runtime/base/shared_map.h +++ b/hphp/runtime/base/shared_map.h @@ -42,8 +42,6 @@ public: ~SharedMap(); - virtual bool isSharedMap() const { return true; } - // these using directives ensure the full set of overloaded functions // are visible in this class, to avoid triggering implicit conversions // from a CVarRef key to int64. @@ -85,20 +83,19 @@ public: static ArrayData *RemoveInt(ArrayData* ad, int64_t k, bool copy); static ArrayData *RemoveStr(ArrayData* ad, const StringData* k, bool copy); - ArrayData *copy() const; + static ArrayData* Copy(const ArrayData*); /** * Copy (escalate) the SharedMap without triggering local cache. */ - static ArrayData *Append(ArrayData* a, CVarRef v, bool copy); - ArrayData *appendRef(CVarRef v, bool copy); - ArrayData *appendWithRef(CVarRef v, bool copy); - ArrayData *plus(const ArrayData *elems, bool copy); - ArrayData *merge(const ArrayData *elems, bool copy); - - ArrayData *prepend(CVarRef v, bool copy); + static ArrayData* Append(ArrayData* a, CVarRef v, bool copy); + static ArrayData* AppendRef(ArrayData*, CVarRef v, bool copy); + static ArrayData* AppendWithRef(ArrayData*, CVarRef v, bool copy); + static ArrayData* Plus(ArrayData*, const ArrayData *elems, bool copy); + static ArrayData* Merge(ArrayData*, const ArrayData *elems, bool copy); + static ArrayData* Prepend(ArrayData*, CVarRef v, bool copy); /** - * Non-Variant virtual methods that override ArrayData + * Non-Variant methods that override ArrayData */ static TypedValue* NvGetInt(const ArrayData*, int64_t k); static TypedValue* NvGetStr(const ArrayData*, const StringData* k); @@ -111,8 +108,8 @@ public: 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); + static bool ValidFullPos(const ArrayData*, const FullPos& fp); + static bool AdvanceFullPos(ArrayData*, FullPos& fp); /** * Memory allocator methods. @@ -120,8 +117,8 @@ public: DECLARE_SMART_ALLOCATION(SharedMap); static void Release(ArrayData*); - virtual ArrayData *escalate() const; - virtual ArrayData* escalateForSort(); + static ArrayData* Escalate(const ArrayData*); + static ArrayData* EscalateForSort(ArrayData*); ArrayData* loadElems(bool mapInit = false) const; diff --git a/hphp/runtime/vm/backup_gc.cpp b/hphp/runtime/vm/backup_gc.cpp index 7ff665e2b..df517b271 100644 --- a/hphp/runtime/vm/backup_gc.cpp +++ b/hphp/runtime/vm/backup_gc.cpp @@ -378,10 +378,6 @@ struct GarbageCollector { } void dealloc(SmartAllocatorImpl* sa, ArrayData* ar) const { - if (Sweepable* s = dynamic_cast(ar)) { - s->sweep(); - s->unregister(); - } sa->dealloc(ar); } diff --git a/hphp/runtime/vm/name_value_table_wrapper.cpp b/hphp/runtime/vm/name_value_table_wrapper.cpp index 9be36d6e2..ece6d740d 100644 --- a/hphp/runtime/vm/name_value_table_wrapper.cpp +++ b/hphp/runtime/vm/name_value_table_wrapper.cpp @@ -25,14 +25,12 @@ namespace HPHP { inline NameValueTableWrapper* NameValueTableWrapper::asNVTW(ArrayData* ad) { assert(ad->kind() == kNvtwKind); - assert(dynamic_cast(ad)); return static_cast(ad); } inline const NameValueTableWrapper* NameValueTableWrapper::asNVTW(const ArrayData* ad) { assert(ad->kind() == kNvtwKind); - assert(dynamic_cast(ad)); return static_cast(ad); } @@ -170,27 +168,33 @@ NameValueTableWrapper::RemoveStr(ArrayData* ad, const StringData* k, * is currently $GLOBALS. */ -ArrayData* NameValueTableWrapper::Append(ArrayData*, CVarRef v, bool copy) { +ArrayData* +NameValueTableWrapper::Append(ArrayData*, CVarRef v, bool copy) { throw NotImplementedException("append on $GLOBALS"); } -ArrayData* NameValueTableWrapper::appendRef(CVarRef v, bool copy) { +ArrayData* +NameValueTableWrapper::AppendRef(ArrayData*, CVarRef v, bool copy) { throw NotImplementedException("appendRef on $GLOBALS"); } -ArrayData* NameValueTableWrapper::appendWithRef(CVarRef v, bool copy) { +ArrayData* +NameValueTableWrapper::AppendWithRef(ArrayData*, CVarRef v, bool copy) { throw NotImplementedException("appendWithRef on $GLOBALS"); } -ArrayData* NameValueTableWrapper::plus(const ArrayData* elems, bool copy) { +ArrayData* +NameValueTableWrapper::Plus(ArrayData*, const ArrayData* elems, bool copy) { throw NotImplementedException("plus on $GLOBALS"); } -ArrayData* NameValueTableWrapper::merge(const ArrayData* elems, bool copy) { +ArrayData* +NameValueTableWrapper::Merge(ArrayData*, const ArrayData* elems, bool copy) { throw NotImplementedException("merge on $GLOBALS"); } -ArrayData* NameValueTableWrapper::prepend(CVarRef v, bool copy) { +ArrayData* +NameValueTableWrapper::Prepend(ArrayData*, CVarRef v, bool copy) { throw NotImplementedException("prepend on $GLOBALS"); } @@ -219,19 +223,22 @@ ssize_t NameValueTableWrapper::IterRewind(const ArrayData* ad, ssize_t prev) { return iter.toInteger(); } -bool NameValueTableWrapper::validFullPos(const FullPos & fp) const { - assert(fp.getContainer() == (ArrayData*)this); +bool +NameValueTableWrapper::ValidFullPos(const ArrayData* ad, const FullPos & fp) { + assert(fp.getContainer() == ad); + auto a = asNVTW(ad); if (fp.getResetFlag()) return false; - if (fp.m_pos == ArrayData::invalid_index) return false; - NameValueTable::Iterator iter(m_tab, fp.m_pos); - return (iter.valid()); + if (fp.m_pos == invalid_index) return false; + NameValueTable::Iterator iter(a->m_tab, fp.m_pos); + return iter.valid(); } -bool NameValueTableWrapper::advanceFullPos(FullPos& fp) { +bool NameValueTableWrapper::AdvanceFullPos(ArrayData* ad, FullPos& fp) { + auto a = asNVTW(ad); bool reset = fp.getResetFlag(); NameValueTable::Iterator iter = reset ? - NameValueTable::Iterator(m_tab) : - NameValueTable::Iterator(m_tab, fp.m_pos); + NameValueTable::Iterator(a->m_tab) : + NameValueTable::Iterator(a->m_tab, fp.m_pos); if (reset) { fp.setResetFlag(false); } else { @@ -245,20 +252,20 @@ bool NameValueTableWrapper::advanceFullPos(FullPos& fp) { // To conform to PHP behavior, we need to set the internal // cursor to point to the next element. iter.next(); - m_pos = iter.toInteger(); + a->m_pos = iter.toInteger(); return true; } -ArrayData* NameValueTableWrapper::escalateForSort() { +ArrayData* NameValueTableWrapper::EscalateForSort(ArrayData* ad) { raise_warning("Sorting the $GLOBALS array is not supported"); - return this; + return ad; } -void NameValueTableWrapper::ksort(int sort_flags, bool ascending) {} -void NameValueTableWrapper::sort(int sort_flags, bool ascending) {} -void NameValueTableWrapper::asort(int sort_flags, bool ascending) {} -void NameValueTableWrapper::uksort(CVarRef cmp_function) {} -void NameValueTableWrapper::usort(CVarRef cmp_function) {} -void NameValueTableWrapper::uasort(CVarRef cmp_function) {} +void NameValueTableWrapper::Ksort(ArrayData*, int sort_flags, bool ascending) {} +void NameValueTableWrapper::Sort(ArrayData*, int sort_flags, bool ascending) {} +void NameValueTableWrapper::Asort(ArrayData*, int sort_flags, bool ascending) {} +void NameValueTableWrapper::Uksort(ArrayData*, CVarRef cmp_function) {} +void NameValueTableWrapper::Usort(ArrayData*, CVarRef cmp_function) {} +void NameValueTableWrapper::Uasort(ArrayData*, CVarRef cmp_function) {} 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 e37c70847..7fe02c12d 100644 --- a/hphp/runtime/vm/name_value_table_wrapper.h +++ b/hphp/runtime/vm/name_value_table_wrapper.h @@ -103,33 +103,34 @@ public: // ArrayData implementation static ArrayData* RemoveInt(ArrayData*, int64_t k, bool copy); static ArrayData* RemoveStr(ArrayData*, const StringData* k, bool copy); - virtual ArrayData* copy() const { return 0; } + static ArrayData* Copy(const ArrayData* ad) { + return const_cast(ad); + } static ArrayData* Append(ArrayData*, CVarRef v, bool copy); - virtual ArrayData* appendRef(CVarRef v, bool copy); - virtual ArrayData* appendWithRef(CVarRef v, bool copy); + static ArrayData* AppendRef(ArrayData*, CVarRef v, bool copy); + static ArrayData* AppendWithRef(ArrayData*, CVarRef v, bool copy); - virtual ArrayData* plus(const ArrayData* elems, bool copy); - virtual ArrayData* merge(const ArrayData* elems, bool copy); - - virtual ArrayData* prepend(CVarRef v, bool copy); + static ArrayData* Plus(ArrayData*, const ArrayData* elems, bool copy); + static ArrayData* Merge(ArrayData*, const ArrayData* elems, bool copy); + static ArrayData* Prepend(ArrayData*, CVarRef v, bool copy); 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&); + static bool ValidFullPos(const ArrayData*, const FullPos & fp); + static bool AdvanceFullPos(ArrayData*, FullPos&); static bool IsVectorData(const ArrayData*); - virtual ArrayData* escalateForSort(); - virtual void ksort(int sort_flags, bool ascending); - virtual void sort(int sort_flags, bool ascending); - virtual void asort(int sort_flags, bool ascending); - virtual void uksort(CVarRef cmp_function); - virtual void usort(CVarRef cmp_function); - virtual void uasort(CVarRef cmp_function); + static ArrayData* EscalateForSort(ArrayData*); + static void Ksort(ArrayData*, int sort_flags, bool ascending); + static void Sort(ArrayData*, int sort_flags, bool ascending); + static void Asort(ArrayData*, int sort_flags, bool ascending); + static void Uksort(ArrayData*, CVarRef cmp_function); + static void Usort(ArrayData*, CVarRef cmp_function); + static void Uasort(ArrayData*, CVarRef cmp_function); private: static NameValueTableWrapper* asNVTW(ArrayData* ad);