ArrayData* StructArray::CopyWithStrongIterators(const ArrayData* ad) { auto const cpy = Copy(ad); if (LIKELY(strong_iterators_exist())) { // This returns its first argument just so we can tail call it. return move_strong_iterators(cpy, const_cast<ArrayData*>(ad)); } return cpy; }
NEVER_INLINE ArrayData* PackedArray::Grow(ArrayData* old) { assert(checkInvariants(old)); assert(old->m_size == old->m_packedCap); DEBUG_ONLY auto const oldPos = old->m_pos; auto const oldCap = old->m_packedCap; auto const cap = oldCap * 2; if (UNLIKELY(cap >= kMaxPackedCap)) return nullptr; auto const ad = static_cast<ArrayData*>( MM().objMallocLogged(sizeof(ArrayData) + cap * sizeof(TypedValue)) ); auto const oldSize = old->m_size; auto const oldPosUnsigned = uint64_t{static_cast<uint32_t>(old->m_pos)}; ad->m_kindAndSize = uint64_t{oldSize} << 32 | cap; ad->m_posAndCount = oldPosUnsigned; if (UNLIKELY(strong_iterators_exist())) { move_strong_iterators(ad, old); } // Steal the old array payload. At the time of this writing, it was // better not to reuse the memcpy return value here because gcc had // `ad' in a callee saved register anyway. The reg-to-reg move was // smaller than subtracting sizeof(ArrayData) from rax to return. old->m_size = 0; std::memcpy(packedData(ad), packedData(old), oldSize * sizeof(TypedValue)); // TODO(#2926276): it would be good to refactor callers to expect // our refcount to start at 1. assert(ad->m_kind == ArrayData::kPackedKind); assert(ad->m_pos == oldPos); assert(ad->m_count == 0); assert(ad->m_packedCap == cap); assert(ad->m_size == oldSize); assert(checkInvariants(ad)); return ad; }
StructArray* StructArray::Grow(StructArray* old, Shape* newShape) { assert(old->shape()->transitionRequiresGrowth()); auto result = StructArray::create(newShape, old->data(), old->shape()->size()); result->m_size = newShape->size(); if (UNLIKELY(strong_iterators_exist())) { move_strong_iterators(result, old); } old->m_size = 0; if (debug) { // For debug builds, set m_pos to 0 as well to make the // asserts in checkInvariants() happy. old->m_pos = 0; } assert(result->hasExactlyOneRef()); return result; }