Beispiel #1
0
ArrayData* PackedArray::Dequeue(ArrayData* adIn, Variant& value) {
  assert(checkInvariants(adIn));

  auto const ad = adIn->hasMultipleRefs() ? Copy(adIn) : adIn;
  // To conform to PHP behavior, we invalidate all strong iterators when an
  // element is removed from the beginning of the array.
  if (UNLIKELY(strong_iterators_exist())) {
    free_strong_iterators(ad);
  }

  if (UNLIKELY(ad->m_size == 0)) {
    value = uninit_null();
    ad->m_pos = ArrayData::invalid_index;
    return ad;
  }

  // This is O(N), but so is Dequeue on a mixed array, because it
  // needs to renumber keys.  So it makes sense to stay packed.
  auto n = ad->m_size - 1;
  auto const data = packedData(ad);
  value = std::move(tvAsVariant(data)); // no incref+decref
  std::memmove(data, data + 1, n * sizeof *data);
  ad->m_size = n;
  ad->m_pos = n > 0 ? 0 : ArrayData::invalid_index;
  return ad;
}
Beispiel #2
0
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;
}
Beispiel #3
0
void PackedArray::Sort(ArrayData* ad, int sort_flags, bool ascending) {
  assert(ad->isPacked());
  if (ad->m_size <= 1) {
    return;
  }
  assert(!ad->hasMultipleRefs());
  auto a = ad;
  if (UNLIKELY(strong_iterators_exist())) {
    free_strong_iterators(a);
  }
  SortFlavor flav = preSort(ad);
  a->m_pos = 0;
  auto data_begin = packedData(ad);
  auto data_end = data_begin + a->m_size;
  CALL_SORT(TVAccessor);
}
Beispiel #4
0
void StructArray::Release(ArrayData* ad) {
  assert(ad->isRefCounted());
  assert(ad->hasExactlyOneRef());
  auto array = asStructArray(ad);

  auto const size = array->size();
  auto const data = array->data();
  auto const stop = data + size;
  for (auto ptr = data; ptr != stop; ++ptr) {
    tvRefcountedDecRef(ptr);
  }
  if (UNLIKELY(strong_iterators_exist())) {
    free_strong_iterators(ad);
  }

  auto const cap = array->capacity();
  MM().objFree(array, sizeof(StructArray) + sizeof(TypedValue) * cap);
}
Beispiel #5
0
NEVER_INLINE
void PackedArray::Release(ArrayData* ad) {
  assert(checkInvariants(ad));
  assert(ad->isRefCounted());

  auto const size = ad->m_size;
  auto const data = packedData(ad);
  auto const stop = data + size;
  for (auto ptr = data; ptr != stop; ++ptr) {
    tvRefcountedDecRef(*ptr);
  }
  if (UNLIKELY(strong_iterators_exist())) {
    free_strong_iterators(ad);
  }

  auto const cap = ad->m_packedCap;
  MM().objFreeLogged(ad, sizeof(ArrayData) + sizeof(TypedValue) * cap);
}
Beispiel #6
0
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;
}
Beispiel #7
0
void StructArray::ReleaseUncounted(ArrayData* ad) {
  assert(ad->isUncounted());
  auto structArray = asStructArray(ad);

  auto const data = structArray->data();
  auto const stop = data + structArray->size();
  for (auto ptr = data; ptr != stop; ++ptr) {
    ReleaseUncountedTv(*ptr);
  }

  // We better not have strong iterators associated with uncounted
  // arrays.
  if (debug && UNLIKELY(strong_iterators_exist())) {
    for_each_strong_iterator([&] (const MIterTable::Ent& miEnt) {
      assert(miEnt.array != structArray);
    });
  }

  std::free(structArray);
}
Beispiel #8
0
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;
}
Beispiel #9
0
bool PackedArray::Usort(ArrayData* ad, const Variant& cmp_function) {
  assert(ad->isPacked());
  if (ad->m_size <= 1) {
    return true;
  }
  assert(!ad->hasMultipleRefs());
  if (UNLIKELY(strong_iterators_exist())) {
    free_strong_iterators(ad);
  }
  ElmUCompare<TVAccessor> comp;
  CallCtx ctx;
  CallerFrame cf;
  vm_decode_function(cmp_function, cf(), false, ctx);
  if (!ctx.func) {
    return false;
  }
  comp.ctx = &ctx;
  auto const data = packedData(ad);
  Sort::sort(data, data + ad->m_size, comp);
  return true;
}
Beispiel #10
0
ArrayData* PackedArray::Prepend(ArrayData* adIn,
                                const Variant& v,
                                bool copy) {
  assert(checkInvariants(adIn));

  auto const ad = adIn->hasMultipleRefs() ? CopyAndResizeIfNeeded(adIn)
                                          : ResizeIfNeeded(adIn);
  // To conform to PHP behavior, we invalidate all strong iterators when an
  // element is added to the beginning of the array.
  if (UNLIKELY(strong_iterators_exist())) {
    free_strong_iterators(ad);
  }

  auto const size = ad->m_size;
  auto const data = packedData(ad);
  std::memmove(data + 1, data, sizeof *data * size);
  // TODO(#3888164): constructValHelper is making KindOfUninit checks.
  tvAsUninitializedVariant(&data[0]).constructValHelper(v);
  ad->m_size = size + 1;
  ad->m_pos = 0;
  return ad;
}
Beispiel #11
0
ArrayData* PackedArray::Pop(ArrayData* adIn, Variant& value) {
  assert(checkInvariants(adIn));

  auto const ad = adIn->hasMultipleRefs() ? Copy(adIn) : adIn;

  if (UNLIKELY(ad->m_size == 0)) {
    value = uninit_null();
    ad->m_pos = ArrayData::invalid_index;
    return ad;
  }

  auto const oldSize = ad->m_size;
  auto& tv = packedData(ad)[oldSize - 1];
  value = tvAsCVarRef(&tv);
  if (UNLIKELY(strong_iterators_exist())) {
    adjustMArrayIter(ad, oldSize - 1);
  }
  auto const oldType = tv.m_type;
  auto const oldDatum = tv.m_data.num;
  ad->m_size = oldSize - 1;
  ad->m_pos = oldSize - 1 > 0 ? 0 : ArrayData::invalid_index;
  tvRefcountedDecRefHelper(oldType, oldDatum);
  return ad;
}