Esempio n. 1
0
ArrayData*
PackedArray::SetInt(ArrayData* adIn, int64_t k, const Variant& v, bool copy) {
  assert(checkInvariants(adIn));

  // Right now SetInt is used for the AddInt entry point also. This
  // first branch is the only thing we'd be able to omit if we were
  // doing AddInt.
  if (size_t(k) < adIn->m_size) {
    auto const ad = copy ? Copy(adIn) : adIn;
    auto& dst = *tvToCell(&packedData(ad)[k]);
    cellSet(*v.asCell(), dst);
    // TODO(#3888164): we should restructure things so we don't have to
    // check KindOfUninit here.
    if (UNLIKELY(dst.m_type == KindOfUninit)) {
      dst.m_type = KindOfNull;
    }
    return ad;
  }

  // Setting the int at the size of the array can keep it in packed
  // mode---it's the same as an append.
  if (size_t(k) == adIn->m_size) return Append(adIn, v, copy);

  // On the promote-to-mixed path, we can use addVal since we know the
  // key can't exist.
  auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(adIn);
  return mixed->addVal(k, v);
}
Esempio n. 2
0
ArrayData* PackedArray::SetRefStr(ArrayData* adIn,
                                  StringData* k,
                                  Variant& v,
                                  bool copy) {
  auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(adIn);
  // todo t2606310: key can't exist.  use add/findForNewInsert
  return mixed->updateRef(k, v);
}
Esempio n. 3
0
ArrayData* PackedArray::SetStr(ArrayData* adIn,
                               StringData* k,
                               const Variant& v,
                               bool copy) {
  // We must convert to mixed, but can call addVal since the key must
  // not exist.
  auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(adIn);
  return mixed->addVal(k, v);
}
Esempio n. 4
0
ArrayData* PackedArray::LvalStr(ArrayData* adIn,
                                StringData* key,
                                Variant*& ret,
                                bool copy) {
  // We have to promote.  We know the key doesn't exist, but aren't
  // making use of that fact yet.  TODO(#2606310).
  auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(adIn);
  return mixed->addLvalImpl(key, ret);
}
Esempio n. 5
0
ArrayData* StructArray::AppendWithRef(
  ArrayData* ad,
  const Variant& v,
  bool copy
) {
  auto structArray = asStructArray(ad);
  auto mixedArray = copy ? ToMixedCopy(structArray) : ToMixed(structArray);
  return MixedArray::AppendWithRef(mixedArray->asArrayData(), v, false);
}
Esempio n. 6
0
ArrayData* StructArray::LvalInt(
  ArrayData* ad,
  int64_t k,
  Variant*& ret,
  bool copy
) {
  auto structArray = asStructArray(ad);
  auto mixedArray = copy ? ToMixedCopy(structArray) : ToMixed(structArray);
  return mixedArray->addLvalImpl(k, ret);
}
Esempio n. 7
0
ArrayData* StructArray::SetRefStr(
  ArrayData* ad,
  StringData* k,
  Variant& v,
  bool copy
) {
  auto structArray = asStructArray(ad);
  auto mixedArray = copy ? ToMixedCopy(structArray) : ToMixed(structArray);
  return MixedArray::SetRefStr(mixedArray->asArrayData(), k, v, false);
}
Esempio n. 8
0
ArrayData* StructArray::SetStr(
  ArrayData* ad,
  StringData* k,
  Cell v,
  bool copy
) {
  auto structArray = asStructArray(ad);
  auto shape = structArray->shape();
  auto result = structArray;

  auto offset = shape->offsetFor(k);
  bool isNewProperty = offset == PropertyTable::kInvalidOffset;

  auto convertToMixedAndAdd = [&]() {
    auto mixed = copy ? ToMixedCopy(structArray) : ToMixed(structArray);
    return mixed->addValNoAsserts(k, v);
  };

  if (isNewProperty) {
    StringData* staticKey;
    // We don't support adding non-static strings yet.
    if (k->isStatic()) {
      staticKey = k;
    } else {
      staticKey = lookupStaticString(k);
      if (!staticKey) return convertToMixedAndAdd();
    }

    auto newShape = shape->transition(staticKey);
    if (!newShape) return convertToMixedAndAdd();
    result = copy ? CopyAndResizeIfNeeded(structArray, newShape)
                  : ResizeIfNeeded(structArray, newShape);
    offset = result->shape()->offsetFor(staticKey);
    assert(offset != PropertyTable::kInvalidOffset);
    TypedValue* dst = &result->data()[offset];
    // TODO(#3888164): we should restructure things so we don't have to
    // check KindOfUninit here.
    if (UNLIKELY(v.m_type == KindOfUninit)) v = make_tv<KindOfNull>();
    cellDup(v, *dst);
    return result;
  }

  if (copy) {
    result = asStructArray(Copy(structArray));
  }

  assert(offset != PropertyTable::kInvalidOffset);
  TypedValue* dst = &result->data()[offset];
  if (UNLIKELY(v.m_type == KindOfUninit)) v = make_tv<KindOfNull>();
  cellSet(v, *tvToCell(dst));
  return result;
}
Esempio n. 9
0
ArrayData* StructArray::RemoveStr(
  ArrayData* ad,
  const StringData* k,
  bool copy
) {
  auto structArray = asStructArray(ad);
  if (structArray->shape()->hasOffsetFor(k)) {
    auto const mixed = copy ? ToMixedCopy(structArray) : ToMixed(structArray);
    auto pos = mixed->findForRemove(k, k->hash());
    if (validPos(pos)) mixed->erase(pos);
    return mixed;
  }
  return copy ? Copy(structArray) : structArray;
}
Esempio n. 10
0
ArrayData* PackedArray::RemoveInt(ArrayData* adIn, int64_t k, bool copy) {
  assert(checkInvariants(adIn));
  if (size_t(k) < adIn->m_size) {
    // Escalate to mixed for correctness; unset preserves m_nextKI.
    //
    // TODO(#2606310): if we're removing the /last/ element, we
    // probably could stay packed, but this needs to be verified.
    auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(adIn);
    auto pos = mixed->findForRemove(k, false);
    if (validPos(pos)) mixed->erase(pos);
    return mixed;
  }
  // Key doesn't exist---we're still packed.
  return copy ? Copy(adIn) : adIn;
}
Esempio n. 11
0
ArrayData* PackedArray::LvalNew(ArrayData* adIn, Variant*& ret, bool copy) {
  assert(checkInvariants(adIn));
  auto const ad = copy ? CopyAndResizeIfNeeded(adIn)
                       : ResizeIfNeeded(adIn);
  if (UNLIKELY(!ad)) {
    auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(ad);
    return MixedArray::LvalNew(mixed, ret, copy);
  }

  if (ad->m_pos == ArrayData::invalid_index) {
    ad->m_pos = ad->m_size;
  }
  auto& tv = packedData(ad)[ad->m_size++];
  tv.m_type = KindOfNull;
  ret = &tvAsVariant(&tv);
  return ad;
}
Esempio n. 12
0
ArrayData* PackedArray::Append(ArrayData* adIn, const Variant& v, bool copy) {
  assert(checkInvariants(adIn));
  auto const ad = copy ? CopyAndResizeIfNeeded(adIn)
                       : ResizeIfNeeded(adIn);
  if (UNLIKELY(!ad)) {
    auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(adIn);
    return MixedArray::Append(mixed, v, copy);
  }

  if (ad->m_pos == ArrayData::invalid_index) {
    ad->m_pos = ad->m_size;
  }
  auto& dst = packedData(ad)[ad->m_size++];
  cellDup(*v.asCell(), dst);
  // TODO(#3888164): restructure this so we don't need KindOfUninit checks.
  if (dst.m_type == KindOfUninit) dst.m_type = KindOfNull;
  return ad;
}
Esempio n. 13
0
ArrayData* PackedArray::SetRefInt(ArrayData* adIn,
                                  int64_t k,
                                  Variant& v,
                                  bool copy) {
  assert(checkInvariants(adIn));

  if (size_t(k) == adIn->m_size) return AppendRef(adIn, v, copy);
  if (size_t(k) < adIn->m_size) {
    auto const ad = copy ? Copy(adIn) : adIn;
    tvBind(v.asRef(), &packedData(ad)[k]);
    return ad;
  }

  // todo t2606310: key can't exist.  use add/findForNewInsert
  auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(adIn);
  mixed->updateRef(k, v);
  return mixed;
}
Esempio n. 14
0
ArrayData* PackedArray::AppendRef(ArrayData* adIn,
                                  Variant& v,
                                  bool copy) {
  assert(checkInvariants(adIn));
  auto const ad = copy ? CopyAndResizeIfNeeded(adIn)
                       : ResizeIfNeeded(adIn);
  if (UNLIKELY(!ad)) {
    auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(adIn);
    return MixedArray::AppendRef(mixed, v, copy);
  }

  if (ad->m_pos == ArrayData::invalid_index) {
    ad->m_pos = ad->m_size;
  }
  auto& dst = packedData(ad)[ad->m_size++];
  dst.m_data.pref = v.asRef()->m_data.pref;
  dst.m_type = KindOfRef;
  dst.m_data.pref->incRefCount();
  return ad;
}
Esempio n. 15
0
ArrayData* PackedArray::AppendWithRef(ArrayData* adIn,
                                      const Variant& v,
                                      bool copy) {
  assert(checkInvariants(adIn));
  auto const ad = copy ? CopyAndResizeIfNeeded(adIn)
                       : ResizeIfNeeded(adIn);
  if (UNLIKELY(!ad)) {
    auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(adIn);
    // XXX: constness
    return MixedArray::AppendRef(mixed, const_cast<Variant&>(v), copy);
  }

  if (ad->m_pos == ArrayData::invalid_index) {
    ad->m_pos = ad->m_size;
  }
  auto& dst = packedData(ad)[ad->m_size++];
  dst.m_type = KindOfNull;
  tvAsVariant(&dst).setWithRef(v);
  return ad;
}
Esempio n. 16
0
ArrayData* StructArray::LvalStr(
  ArrayData* ad,
  StringData* property,
  Variant*& ret,
  bool copy
) {
  auto structArray = asStructArray(ad);
  auto shape = structArray->shape();
  auto offset = shape->offsetFor(property);
  if (offset != PropertyTable::kInvalidOffset) {
    auto const result = asStructArray(
      copy ? Copy(structArray) : structArray);
    ret = &tvAsVariant(&result->data()[offset]);
    return result;
  }

  auto convertToMixedAndAdd = [&]() {
    auto mixed = copy ? ToMixedCopy(structArray) : ToMixed(structArray);
    return mixed->addLvalImpl(property, ret);
  };

  // We don't support adding non-static strings yet.
  StringData* staticKey;
  if (property->isStatic()) {
    staticKey = property;
  } else {
    staticKey = lookupStaticString(property);
    if (!staticKey) return convertToMixedAndAdd();
  }

  auto newShape = shape->transition(staticKey);
  if (!newShape) return convertToMixedAndAdd();
  auto result = copy ? CopyAndResizeIfNeeded(structArray, newShape)
                     : ResizeIfNeeded(structArray, newShape);

  assert(newShape->hasOffsetFor(staticKey));
  offset = newShape->offsetFor(staticKey);
  tvWriteNull(&result->data()[offset]);
  ret = &tvAsVariant(&result->data()[offset]);
  return result;
}
Esempio n. 17
0
ArrayData* PackedArray::EscalateForSort(ArrayData* ad, SortFunction sf) {
  if (ad->m_size <= 1) {
    return ad;
  }
  if (sf == SORTFUNC_KSORT) {
    return ad;                          // trivial for packed arrays.
  }
  if (isSortFamily(sf)) {               // sort/rsort/usort
    if (UNLIKELY(ad->hasMultipleRefs())) {
      auto ret = PackedArray::Copy(ad);
      assert(ret->hasExactlyOneRef());
      return ret;
    } else {
      return ad;
    }
  }
  assert(checkInvariants(ad));
  auto ret = ToMixedCopy(ad);
  assert(ret->hasExactlyOneRef());
  return ret;
}
Esempio n. 18
0
ArrayData* PackedArray::LvalInt(ArrayData* adIn,
                                int64_t k,
                                Variant*& ret,
                                bool copy) {
  assert(checkInvariants(adIn));

  if (LIKELY(size_t(k) < adIn->m_size)) {
    auto const ad = copy ? Copy(adIn) : adIn;
    ret = &tvAsVariant(&packedData(ad)[k]);
    return ad;
  }

  // We can stay packed if the index is m_size, and the operation does
  // the same thing as LvalNew.
  if (size_t(k) == adIn->m_size) return LvalNew(adIn, ret, copy);

  // Promote-to-mixed path, we know the key is new and should be using
  // findForNewInsert but aren't yet TODO(#2606310).
  auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(adIn);
  return mixed->addLvalImpl(k, ret);
}
Esempio n. 19
0
ArrayData* StructArray::LvalNew(ArrayData* ad, Variant*& ret, bool copy) {
  auto structArray = asStructArray(ad);
  auto mixedArray = copy ? ToMixedCopy(structArray) : ToMixed(structArray);
  return MixedArray::LvalNew(mixedArray->asArrayData(), ret, false);
}
Esempio n. 20
0
ArrayData* StructArray::ZSetInt(ArrayData* ad, int64_t k, RefData* v) {
  return MixedArray::ZSetInt(ToMixedCopy(asStructArray(ad)), k, v);
}
Esempio n. 21
0
ArrayData* StructArray::SetInt(ArrayData* ad, int64_t k, Cell v, bool copy) {
  auto structArray = asStructArray(ad);
  auto mixedArray = copy ? ToMixedCopy(structArray) : ToMixed(structArray);
  return mixedArray->addVal(k, v);
}
Esempio n. 22
0
ArrayData* StructArray::ZAppend(ArrayData* ad, RefData* v, int64_t* key_ptr) {
  return MixedArray::ZAppend(ToMixedCopy(asStructArray(ad)), v, key_ptr);
}
Esempio n. 23
0
ArrayData* StructArray::EscalateForSort(ArrayData* ad, SortFunction) {
  return ToMixedCopy(asStructArray(ad));
}
Esempio n. 24
0
ArrayData* PackedArray::EscalateForSort(ArrayData* ad) {
  // Note: ToMixedCopy also grows so we have !isFull.  We could use
  // ToMixedCopyReserve?
  assert(checkInvariants(ad));
  return ToMixedCopy(ad);
}
Esempio n. 25
0
ArrayData* StructArray::ZSetStr(ArrayData* ad, StringData* k, RefData* v) {
  return MixedArray::ZSetStr(ToMixedCopy(asStructArray(ad)), k, v);
}
Esempio n. 26
0
ArrayData* PackedArray::ZSetInt(ArrayData* ad, int64_t k, RefData* v) {
  assert(checkInvariants(ad));
  return MixedArray::ZSetInt(ToMixedCopy(ad), k, v);
}
Esempio n. 27
0
ArrayData* StructArray::Append(ArrayData* ad, Cell v, bool copy) {
  auto structArray = asStructArray(ad);
  auto mixedArray = copy ? ToMixedCopy(structArray) : ToMixed(structArray);
  return MixedArray::Append(mixedArray->asArrayData(), v, false);
}
Esempio n. 28
0
ArrayData* PackedArray::ZSetStr(ArrayData* ad, StringData* k, RefData* v) {
  assert(checkInvariants(ad));
  return MixedArray::ZSetStr(ToMixedCopy(ad), k, v);
}
Esempio n. 29
0
ArrayData* StructArray::ToDict(ArrayData* ad) {
  auto a = asStructArray(ad);
  auto mixed = ad->cowCheck() ? ToMixedCopy(a) : ToMixed(a);
  return MixedArray::ToDictInPlace(mixed);
}
Esempio n. 30
0
ArrayData* PackedArray::ZAppend(ArrayData* ad, RefData* v) {
  assert(checkInvariants(ad));
  return MixedArray::ZAppend(ToMixedCopy(ad), v);
}