3 +----------------------------------------------------------------------+
5 +----------------------------------------------------------------------+
6 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
18 #include "hphp/runtime/base/bespoke/monotype-vec.h"
20 #include "hphp/runtime/base/bespoke/entry-types.h"
21 #include "hphp/runtime/base/array-init.h"
22 #include "hphp/runtime/base/memory-manager.h"
23 #include "hphp/runtime/base/mixed-array-defs.h"
24 #include "hphp/runtime/base/type-variant.h"
25 #include "hphp/runtime/base/tv-refcount.h"
27 #include "hphp/runtime/vm/jit/type.h"
29 #include "hphp/util/word-mem.h"
31 namespace HPHP
{ namespace bespoke
{
35 //////////////////////////////////////////////////////////////////////////////
37 uint16_t packSizeIndexAndAuxBits(uint8_t idx
, uint8_t aux
) {
38 return (static_cast<uint16_t>(idx
) << 8) | aux
;
41 inline constexpr uint32_t sizeClassParams2MonotypeVecCapacity(
47 static_assert(sizeof(MonotypeVec
) <=
48 kSizeIndex2Size
[MonotypeVec::kMinSizeIndex
]);
50 if (index
< MonotypeVec::kMinSizeIndex
) return 0;
51 return (((size_t{1} << lg_grp
) + (ndelta
<< lg_delta
)) - sizeof(MonotypeVec
))
55 alignas(64) constexpr uint32_t kSizeIndex2MonotypeVecCapacity
[] = {
56 #define SIZE_CLASS(index, lg_grp, lg_delta, ndelta, lg_delta_lookup, ncontig) \
57 sizeClassParams2MonotypeVecCapacity(index, lg_grp, lg_delta, ndelta),
62 //////////////////////////////////////////////////////////////////////////////
66 //////////////////////////////////////////////////////////////////////////////
67 // Static initialization
68 //////////////////////////////////////////////////////////////////////////////
72 using StaticVec
= std::aligned_storage
<sizeof(EmptyMonotypeVec
), 16>::type
;
74 StaticVec s_emptyMonotypeVec
;
75 StaticVec s_emptyMonotypeVArray
;
76 StaticVec s_emptyMonotypeVecMarked
;
77 StaticVec s_emptyMonotypeVArrayMarked
;
79 static_assert(sizeof(DataType
) == 1);
80 constexpr LayoutIndex kBaseLayoutIndex
= {1 << 9};
81 auto const s_monotypeVecVtable
= fromArray
<MonotypeVec
>();
82 auto const s_emptyMonotypeVecVtable
= fromArray
<EmptyMonotypeVec
>();
84 constexpr DataType kEmptyDataType
= static_cast<DataType
>(1);
85 constexpr DataType kAbstractDataTypeMask
= static_cast<DataType
>(0x80);
87 constexpr LayoutIndex
getLayoutIndex(DataType type
) {
88 return LayoutIndex
{uint16_t(kBaseLayoutIndex
.raw
+ uint8_t(type
))};
91 constexpr LayoutIndex
getEmptyLayoutIndex() {
92 auto constexpr offset
= (1 << 8);
93 return LayoutIndex
{uint16_t(kBaseLayoutIndex
.raw
) + offset
};
96 Layout::LayoutSet
getAllEmptyOrMonotypeVecLayouts() {
97 Layout::LayoutSet result
;
98 #define DT(name, value) { \
99 auto const type = KindOf##name; \
100 if (type == dt_modulo_persistence(type)) { \
101 result.insert(EmptyOrMonotypeVecLayout::Index(type)); \
109 LayoutIndex
getMonotypeParentLayout(DataType dt
) {
110 if (!hasPersistentFlavor(dt
) || isRefcountedType(dt
)) {
111 return EmptyOrMonotypeVecLayout::Index(dt_modulo_persistence(dt
));
114 return MonotypeVecLayout::Index(dt_modulo_persistence(dt
));
119 //////////////////////////////////////////////////////////////////////////////
121 //////////////////////////////////////////////////////////////////////////////
123 EmptyMonotypeVec
* EmptyMonotypeVec::As(ArrayData
* ad
) {
124 auto const ead
= reinterpret_cast<EmptyMonotypeVec
*>(ad
);
125 assertx(ead
->checkInvariants());
129 const EmptyMonotypeVec
* EmptyMonotypeVec::As(const ArrayData
* ad
) {
130 return EmptyMonotypeVec::As(const_cast<ArrayData
*>(ad
));
133 EmptyMonotypeVec
* EmptyMonotypeVec::GetVec(bool legacy
) {
134 auto const src
= legacy
? &s_emptyMonotypeVecMarked
: &s_emptyMonotypeVec
;
135 return reinterpret_cast<EmptyMonotypeVec
*>(src
);
138 EmptyMonotypeVec
* EmptyMonotypeVec::GetVArray(bool legacy
) {
139 auto const src
= legacy
? &s_emptyMonotypeVArrayMarked
140 : &s_emptyMonotypeVArray
;
141 return reinterpret_cast<EmptyMonotypeVec
*>(src
);
144 bool EmptyMonotypeVec::checkInvariants() const {
146 assertx(kindIsValid());
147 assertx(size() == 0);
148 assertx(isVecType() || isVArray());
149 assertx(layoutIndex() == getEmptyLayoutIndex());
154 size_t EmptyMonotypeVec::HeapSize(const EmptyMonotypeVec
* ead
) {
155 return sizeof(EmptyMonotypeVec
);
158 void EmptyMonotypeVec::Scan(const EmptyMonotypeVec
* ead
, type_scan::Scanner
&) {
161 ArrayData
* EmptyMonotypeVec::EscalateToVanilla(const EmptyMonotypeVec
* ead
,
162 const char* reason
) {
163 auto const legacy
= ead
->isLegacyArray();
164 return ead
->isVecType()
165 ? (legacy
? staticEmptyMarkedVec() : staticEmptyVec())
166 : (legacy
? staticEmptyMarkedVArray() : staticEmptyVArray());
169 void EmptyMonotypeVec::ConvertToUncounted(EmptyMonotypeVec
*,
170 DataWalker::PointerMap
*) {
173 void EmptyMonotypeVec::ReleaseUncounted(EmptyMonotypeVec
* ead
) {
176 void EmptyMonotypeVec::Release(EmptyMonotypeVec
* ead
) {
177 // All EmptyMonotypeVecs are static, and should therefore never be released.
178 always_assert(false);
181 bool EmptyMonotypeVec::IsVectorData(const EmptyMonotypeVec
*) {
185 TypedValue
EmptyMonotypeVec::NvGetInt(const EmptyMonotypeVec
*, int64_t) {
186 return make_tv
<KindOfUninit
>();
189 TypedValue
EmptyMonotypeVec::NvGetStr(const EmptyMonotypeVec
*,
191 return make_tv
<KindOfUninit
>();
194 TypedValue
EmptyMonotypeVec::GetPosKey(const EmptyMonotypeVec
*, ssize_t
) {
195 always_assert(false);
198 TypedValue
EmptyMonotypeVec::GetPosVal(const EmptyMonotypeVec
*, ssize_t
) {
199 always_assert(false);
202 ssize_t
EmptyMonotypeVec::GetIntPos(const EmptyMonotypeVec
* ead
, int64_t k
) {
206 ssize_t
EmptyMonotypeVec::GetStrPos(const EmptyMonotypeVec
* ead
,
211 arr_lval
EmptyMonotypeVec::LvalInt(EmptyMonotypeVec
* ead
, int64_t k
) {
212 throwOOBArrayKeyException(k
, ead
);
215 arr_lval
EmptyMonotypeVec::LvalStr(EmptyMonotypeVec
* ead
, StringData
* k
) {
216 throwInvalidArrayKeyException(k
, ead
);
219 tv_lval
EmptyMonotypeVec::ElemInt(
220 tv_lval lval
, int64_t k
, bool throwOnMissing
) {
221 if (throwOnMissing
) throwOOBArrayKeyException(k
, lval
.val().parr
);
222 return const_cast<TypedValue
*>(&immutable_null_base
);
225 tv_lval
EmptyMonotypeVec::ElemStr(
226 tv_lval lval
, StringData
* k
, bool throwOnMissing
) {
227 if (throwOnMissing
) throwInvalidArrayKeyException(k
, lval
.val().parr
);
228 return const_cast<TypedValue
*>(&immutable_null_base
);
231 ArrayData
* EmptyMonotypeVec::SetInt(EmptyMonotypeVec
* eadIn
, int64_t k
,
233 throwOOBArrayKeyException(k
, eadIn
);
236 ArrayData
* EmptyMonotypeVec::SetStr(EmptyMonotypeVec
* eadIn
, StringData
* k
,
238 throwInvalidArrayKeyException(k
, eadIn
);
241 ArrayData
* EmptyMonotypeVec::SetIntMove(EmptyMonotypeVec
* eadIn
, int64_t k
,
243 throwOOBArrayKeyException(k
, eadIn
);
246 ArrayData
* EmptyMonotypeVec::SetStrMove(EmptyMonotypeVec
* eadIn
, StringData
* k
,
248 throwInvalidArrayKeyException(k
, eadIn
);
251 ArrayData
* EmptyMonotypeVec::RemoveInt(EmptyMonotypeVec
* eadIn
, int64_t) {
255 ArrayData
* EmptyMonotypeVec::RemoveStr(EmptyMonotypeVec
* eadIn
,
260 ssize_t
EmptyMonotypeVec::IterBegin(const EmptyMonotypeVec
*) {
264 ssize_t
EmptyMonotypeVec::IterLast(const EmptyMonotypeVec
*) {
268 ssize_t
EmptyMonotypeVec::IterEnd(const EmptyMonotypeVec
*) {
272 ssize_t
EmptyMonotypeVec::IterAdvance(const EmptyMonotypeVec
*, ssize_t
) {
276 ssize_t
EmptyMonotypeVec::IterRewind(const EmptyMonotypeVec
*, ssize_t pos
) {
280 ArrayData
* EmptyMonotypeVec::Append(EmptyMonotypeVec
* ead
, TypedValue v
) {
281 auto const mad
= MonotypeVec::MakeReserve(
282 ead
->m_kind
, ead
->isLegacyArray(), 1, type(v
));
283 auto const res
= MonotypeVec::Append(mad
, v
);
288 ArrayData
* EmptyMonotypeVec::AppendMove(EmptyMonotypeVec
* ead
, TypedValue v
) {
289 auto const mad
= MonotypeVec::MakeReserve(
290 ead
->m_kind
, ead
->isLegacyArray(), 1, type(v
));
291 auto const res
= MonotypeVec::AppendMove(mad
, v
);
296 ArrayData
* EmptyMonotypeVec::Pop(EmptyMonotypeVec
* ead
, Variant
& value
) {
297 value
= uninit_null();
301 ArrayData
* EmptyMonotypeVec::ToDVArray(EmptyMonotypeVec
* eadIn
, bool copy
) {
303 assertx(eadIn
->isVecType());
304 return GetVArray(eadIn
->isLegacyArray());
307 ArrayData
* EmptyMonotypeVec::ToHackArr(EmptyMonotypeVec
* eadIn
, bool copy
) {
309 assertx(eadIn
->isVArray());
310 return GetVec(false);
313 ArrayData
* EmptyMonotypeVec::PreSort(EmptyMonotypeVec
* ead
, SortFunction sf
) {
314 always_assert(false);
317 ArrayData
* EmptyMonotypeVec::PostSort(EmptyMonotypeVec
* ead
, ArrayData
* vad
) {
318 always_assert(false);
321 ArrayData
* EmptyMonotypeVec::SetLegacyArray(EmptyMonotypeVec
* eadIn
,
322 bool copy
, bool legacy
) {
323 if (eadIn
->isVecType()) {
324 return GetVec(legacy
);
326 assertx(eadIn
->isVArray());
327 return GetVArray(legacy
);
332 //////////////////////////////////////////////////////////////////////////////
334 //////////////////////////////////////////////////////////////////////////////
336 template <typename CountableFn
, typename MaybeCountableFn
>
337 void MonotypeVec::forEachCountableValue(CountableFn c
, MaybeCountableFn mc
) {
338 auto const dt
= type();
339 if (isRefcountedType(dt
)) {
340 if (hasPersistentFlavor(dt
)) {
341 for (auto i
= 0; i
< m_size
; i
++) {
342 mc(dt
, valueRefUnchecked(i
).pcnt
);
345 for (auto i
= 0; i
< m_size
; i
++) {
346 c(dt
, reinterpret_cast<Countable
*>(valueRefUnchecked(i
).pcnt
));
352 void MonotypeVec::decRefValues() {
353 forEachCountableValue(
354 [&](auto t
, auto v
) { if (v
->decReleaseCheck()) destructorForType(t
)(v
); },
355 [&](auto t
, auto v
) { if (v
->decReleaseCheck()) destructorForType(t
)(v
); }
359 void MonotypeVec::incRefValues() {
360 forEachCountableValue(
361 [&](auto t
, auto v
) { v
->incRefCount(); },
362 [&](auto t
, auto v
) { v
->incRefCount(); }
366 template <bool Static
>
367 MonotypeVec
* MonotypeVec::MakeReserve(
368 HeaderKind hk
, bool legacy
, uint32_t capacity
, DataType dt
) {
369 auto const bytes
= sizeof(MonotypeVec
) + capacity
* sizeof(Value
);
370 auto const index
= std::max(MemoryManager::size2Index(bytes
), kMinSizeIndex
);
371 auto const alloc
= [&]{
372 if (!Static
) return tl_heap
->objMallocIndex(index
);
373 auto const size
= MemoryManager::sizeIndex2Size(index
);
374 return RO::EvalLowStaticArrays
? low_malloc(size
) : uncounted_malloc(size
);
377 auto const mad
= static_cast<MonotypeVec
*>(alloc
);
378 auto const aux
= packSizeIndexAndAuxBits(
379 index
, legacy
? ArrayData::kLegacyArray
: 0);
381 mad
->initHeader_16(hk
, OneReference
, aux
);
382 mad
->setLayoutIndex(getLayoutIndex(dt
));
385 assertx(mad
->checkInvariants());
389 MonotypeVec
* MonotypeVec::MakeFromVanilla(ArrayData
* ad
, DataType dt
) {
390 assertx(ad
->hasVanillaPackedLayout());
391 auto const kind
= ad
->isVArray() ? HeaderKind::BespokeVArray
392 : HeaderKind::BespokeVec
;
393 auto result
= ad
->isStatic()
394 ? MakeReserve
<true>(kind
, ad
->isLegacyArray(), ad
->size(), dt
)
395 : MakeReserve
<false>(kind
, ad
->isLegacyArray(), ad
->size(), dt
);
397 PackedArray::IterateVNoInc(ad
, [&](auto v
) {
398 auto const next
= Append(result
, v
);
399 assertx(result
== next
);
403 if (ad
->isStatic()) {
404 auto const aux
= packSizeIndexAndAuxBits(
405 result
->sizeIndex(), result
->auxBits());
406 result
->initHeader_16(kind
, StaticValue
, aux
);
409 assertx(result
->checkInvariants());
413 Value
* MonotypeVec::rawData() {
414 return reinterpret_cast<Value
*>(this + 1);
417 const Value
* MonotypeVec::rawData() const {
418 return const_cast<MonotypeVec
*>(this)->rawData();
421 Value
& MonotypeVec::valueRefUnchecked(uint32_t idx
) {
422 return rawData()[idx
];
425 const Value
& MonotypeVec::valueRefUnchecked(uint32_t idx
) const {
426 return const_cast<MonotypeVec
*>(this)->valueRefUnchecked(idx
);
429 TypedValue
MonotypeVec::typedValueUnchecked(uint32_t idx
) const {
430 return make_tv_of_type(valueRefUnchecked(idx
), type());
433 uint8_t MonotypeVec::sizeIndex() const {
437 size_t MonotypeVec::capacity() const {
438 return kSizeIndex2MonotypeVecCapacity
[sizeIndex()];
441 MonotypeVec
* MonotypeVec::copyHelper(uint8_t newSizeIndex
, bool incRef
) const {
443 static_cast<MonotypeVec
*>(tl_heap
->objMallocIndex(newSizeIndex
));
445 // Copy elements 16 bytes at a time. We may copy an extra value this way,
446 // but our heap allocations are in multiples of 16 bytes, so it is safe.
447 assertx(HeapSize(this) % 16 == 0);
448 auto const bytes
= sizeof(MonotypeVec
) + m_size
* sizeof(Value
);
449 memcpy16_inline(mad
, this, size_t(bytes
+ 15) & ~size_t(15));
451 mad
->initHeader_16(m_kind
, OneReference
,
452 packSizeIndexAndAuxBits(newSizeIndex
, auxBits()));
454 if (incRef
) mad
->incRefValues();
459 MonotypeVec
* MonotypeVec::copy() const {
460 return copyHelper(sizeIndex(), true);
463 MonotypeVec
* MonotypeVec::grow() {
464 auto const cow
= cowCheck();
465 auto const mad
= copyHelper(sizeIndex() + kSizeClassesPerDoubling
, cow
);
466 if (!cow
) m_size
= 0;
470 DataType
MonotypeVec::type() const {
471 return DataType(int8_t(m_extra_hi16
& 0xff));
474 MonotypeVec
* MonotypeVec::prepareForInsert() {
475 if (m_size
== capacity()) return grow();
476 if (cowCheck()) return copy();
481 * Escalates the MonotypeVec to a vanilla PackedArray with the contents of the
482 * current array and the specified capacity. The new array will match the
483 * MonotypeVec in size, contents, and legacy bit status.
485 ArrayData
* MonotypeVec::escalateWithCapacity(size_t capacity
) const {
486 assertx(capacity
>= size());
487 auto const ad
= isVecType() ? PackedArray::MakeReserveVec(capacity
)
488 : PackedArray::MakeReserveVArray(capacity
);
489 for (uint32_t i
= 0; i
< size(); i
++) {
490 auto const tv
= typedValueUnchecked(i
);
491 tvCopy(tv
, PackedArray::LvalUncheckedInt(ad
, i
));
494 ad
->setLegacyArrayInPlace(isLegacyArray());
499 bool MonotypeVec::checkInvariants() const {
500 assertx(kindIsValid());
501 assertx(isVecType() || isVArray());
502 assertx(size() <= capacity());
503 assertx(sizeIndex() >= kMinSizeIndex
);
504 assertx(layoutIndex() != getEmptyLayoutIndex());
505 assertx(layoutIndex() == getLayoutIndex(type()));
506 assertx(isRealType(type()));
508 assertx(tvIsPlausible(typedValueUnchecked(0)));
514 MonotypeVec
* MonotypeVec::As(ArrayData
* ad
) {
515 auto const mad
= reinterpret_cast<MonotypeVec
*>(ad
);
516 assertx(mad
->checkInvariants());
520 const MonotypeVec
* MonotypeVec::As(const ArrayData
* ad
) {
521 auto const mad
= reinterpret_cast<const MonotypeVec
*>(ad
);
522 assertx(mad
->checkInvariants());
526 size_t MonotypeVec::HeapSize(const MonotypeVec
* mad
) {
527 return MemoryManager::sizeIndex2Size(mad
->sizeIndex());
530 void MonotypeVec::Scan(const MonotypeVec
* mad
, type_scan::Scanner
& scan
) {
531 if (isRefcountedType(mad
->type())) {
532 static_assert(sizeof(MaybeCountable
*) == sizeof(Value
));
533 scan
.scan(mad
->rawData()->pcnt
, mad
->size() * sizeof(Value
));
537 ArrayData
* MonotypeVec::EscalateToVanilla(const MonotypeVec
* mad
,
538 const char* reason
) {
539 return mad
->escalateWithCapacity(mad
->size());
542 void MonotypeVec::ConvertToUncounted(MonotypeVec
* madIn
,
543 DataWalker::PointerMap
* seen
) {
544 auto const oldType
= madIn
->type();
545 for (uint32_t i
= 0; i
< madIn
->size(); i
++) {
546 DataType dt
= oldType
;
547 auto const lval
= tv_lval(&dt
, &madIn
->rawData()[i
]);
548 ConvertTvToUncounted(lval
, seen
);
549 assertx(equivDataTypes(dt
, madIn
->type()));
551 auto const newType
= hasPersistentFlavor(oldType
)
552 ? dt_with_persistence(oldType
)
554 madIn
->setLayoutIndex(getLayoutIndex(newType
));
557 void MonotypeVec::ReleaseUncounted(MonotypeVec
* mad
) {
558 for (uint32_t i
= 0; i
< mad
->size(); i
++) {
559 auto tv
= mad
->typedValueUnchecked(i
);
560 ReleaseUncountedTv(&tv
);
564 void MonotypeVec::Release(MonotypeVec
* mad
) {
565 mad
->fixCountForRelease();
566 assertx(mad
->isRefCounted());
567 assertx(mad
->hasExactlyOneRef());
569 tl_heap
->objFreeIndex(mad
, mad
->sizeIndex());
572 bool MonotypeVec::IsVectorData(const MonotypeVec
* mad
) {
576 TypedValue
MonotypeVec::NvGetInt(const MonotypeVec
* mad
, int64_t k
) {
577 if (size_t(k
) >= mad
->size()) return make_tv
<KindOfUninit
>();
578 return mad
->typedValueUnchecked(k
);
581 TypedValue
MonotypeVec::NvGetStr(const MonotypeVec
* mad
, const StringData
*) {
582 return make_tv
<KindOfUninit
>();
585 TypedValue
MonotypeVec::GetPosKey(const MonotypeVec
* mad
, ssize_t pos
) {
586 assertx(pos
< mad
->size());
587 return make_tv
<KindOfInt64
>(pos
);
590 TypedValue
MonotypeVec::GetPosVal(const MonotypeVec
* mad
, ssize_t pos
) {
591 assertx(size_t(pos
) < mad
->size());
592 return mad
->typedValueUnchecked(pos
);
595 ssize_t
MonotypeVec::GetIntPos(const MonotypeVec
* mad
, int64_t k
) {
596 return LIKELY(size_t(k
) < mad
->size()) ? k
: mad
->size();
599 ssize_t
MonotypeVec::GetStrPos(const MonotypeVec
* mad
, const StringData
*) {
603 arr_lval
MonotypeVec::LvalInt(MonotypeVec
* mad
, int64_t k
) {
604 auto const vad
= EscalateToVanilla(mad
, __func__
);
605 auto const res
= vad
->lval(k
);
606 assertx(res
.arr
== vad
);
610 arr_lval
MonotypeVec::LvalStr(MonotypeVec
* mad
, StringData
* k
) {
611 throwInvalidArrayKeyException(k
, mad
);
614 arr_lval
MonotypeVec::elemImpl(int64_t k
, bool throwOnMissing
) {
615 if (size_t(k
) >= size()) {
616 if (throwOnMissing
) throwOOBArrayKeyException(k
, this);
617 return {this, const_cast<TypedValue
*>(&immutable_null_base
)};
620 auto const dt
= type();
621 if (dt
== KindOfClsMeth
) return LvalInt(this, k
);
623 auto const cow
= cowCheck();
624 auto const mad
= cow
? copy() : this;
625 mad
->setLayoutIndex(getLayoutIndex(dt_modulo_persistence(dt
)));
627 static_assert(folly::kIsLittleEndian
);
628 auto const type_ptr
= reinterpret_cast<DataType
*>(&mad
->m_extra_hi16
);
629 assertx(*type_ptr
== mad
->type());
630 return arr_lval
{mad
, type_ptr
, &mad
->valueRefUnchecked(k
)};
633 tv_lval
MonotypeVec::ElemInt(tv_lval lvalIn
, int64_t k
, bool throwOnMissing
) {
634 auto const madIn
= As(lvalIn
.val().parr
);
635 auto const lval
= madIn
->elemImpl(k
, throwOnMissing
);
636 if (lval
.arr
!= madIn
) {
637 lvalIn
.type() = dt_with_rc(lvalIn
.type());
638 lvalIn
.val().parr
= lval
.arr
;
639 if (madIn
->decReleaseCheck()) Release(madIn
);
644 tv_lval
MonotypeVec::ElemStr(tv_lval lval
, StringData
* k
, bool throwOnMissing
) {
645 if (throwOnMissing
) throwInvalidArrayKeyException(k
, lval
.val().parr
);
646 return const_cast<TypedValue
*>(&immutable_null_base
);
650 ArrayData
* MonotypeVec::setIntImpl(int64_t k
, TypedValue v
) {
651 assertx(cowCheck() || notCyclic(v
));
653 if (UNLIKELY(size_t(k
) >= size())) {
654 throwOOBArrayKeyException(k
, this);
657 auto const dt
= type();
658 if (!equivDataTypes(dt
, v
.type())) {
659 auto const vad
= EscalateToVanilla(this, __func__
);
660 auto const res
= vad
->set(k
, v
);
662 if constexpr (Move
) {
663 if (decReleaseCheck()) Release(this);
669 if constexpr (!Move
) {
672 auto const cow
= cowCheck();
673 auto const mad
= cow
? copy() : this;
674 if (dt
!= v
.type()) {
675 mad
->setLayoutIndex(getLayoutIndex(dt_with_rc(dt
)));
677 mad
->valueRefUnchecked(k
) = val(v
);
678 if constexpr (Move
) {
679 if (cow
&& decReleaseCheck()) Release(this);
684 ArrayData
* MonotypeVec::SetInt(MonotypeVec
* madIn
, int64_t k
, TypedValue v
) {
685 return madIn
->setIntImpl
<false>(k
, v
);
688 ArrayData
* MonotypeVec::SetIntMove(MonotypeVec
* madIn
, int64_t k
, TypedValue v
) {
689 return madIn
->setIntImpl
<true>(k
, v
);
692 ArrayData
* MonotypeVec::SetStr(MonotypeVec
* madIn
, StringData
* k
, TypedValue
) {
693 throwInvalidArrayKeyException(k
, madIn
);
696 ArrayData
* MonotypeVec::SetStrMove(MonotypeVec
* madIn
, StringData
* k
, TypedValue
) {
697 throwInvalidArrayKeyException(k
, madIn
);
700 ArrayData
* MonotypeVec::RemoveInt(MonotypeVec
* madIn
, int64_t k
) {
701 if (UNLIKELY(size_t(k
) >= madIn
->m_size
)) return madIn
;
702 if (LIKELY(size_t(k
) + 1 == madIn
->m_size
)) {
703 auto const mad
= madIn
->cowCheck() ? madIn
->copy() : madIn
;
705 tvDecRefGen(mad
->typedValueUnchecked(mad
->m_size
));
709 if (madIn
->isVecType()) {
710 throwVecUnsetException();
712 throwVarrayUnsetException();
716 ArrayData
* MonotypeVec::RemoveStr(MonotypeVec
* madIn
, const StringData
*) {
720 ssize_t
MonotypeVec::IterBegin(const MonotypeVec
* mad
) {
724 ssize_t
MonotypeVec::IterLast(const MonotypeVec
* mad
) {
725 return mad
->size() > 0 ? mad
->size() - 1 : 0;
728 ssize_t
MonotypeVec::IterEnd(const MonotypeVec
* mad
) {
732 ssize_t
MonotypeVec::IterAdvance(const MonotypeVec
* mad
, ssize_t pos
) {
733 return pos
< mad
->size() ? pos
+ 1 : pos
;
736 ssize_t
MonotypeVec::IterRewind(const MonotypeVec
* mad
, ssize_t pos
) {
737 return pos
> 0 ? pos
- 1 : mad
->size();
741 ArrayData
* MonotypeVec::appendImpl(TypedValue v
) {
742 auto const dt
= type();
743 if (!equivDataTypes(dt
, v
.type())) {
744 auto const ad
= escalateWithCapacity(size() + 1);
745 auto const result
= PackedArray::Append(ad
, v
);
746 assertx(ad
== result
);
750 auto const mad
= prepareForInsert();
751 if (dt
!= v
.type()) {
752 mad
->setLayoutIndex(getLayoutIndex(dt_with_rc(dt
)));
754 mad
->valueRefUnchecked(mad
->m_size
++) = val(v
);
756 if constexpr (Move
) {
757 if (mad
!= this && decReleaseCheck()) Release(this);
765 ArrayData
* MonotypeVec::Append(MonotypeVec
* madIn
, TypedValue v
) {
766 return madIn
->appendImpl
<false>(v
);
769 ArrayData
* MonotypeVec::AppendMove(MonotypeVec
* madIn
, TypedValue v
) {
770 return madIn
->appendImpl
<true>(v
);
773 ArrayData
* MonotypeVec::Pop(MonotypeVec
* madIn
, Variant
& value
) {
774 auto const mad
= madIn
->cowCheck() ? madIn
->copy() : madIn
;
775 if (UNLIKELY(mad
->m_size
) == 0) {
776 value
= uninit_null();
780 auto const newSize
= mad
->size() - 1;
781 value
= Variant::attach(mad
->typedValueUnchecked(newSize
));
782 mad
->m_size
= newSize
;
787 ArrayData
* MonotypeVec::ToDVArray(MonotypeVec
* madIn
, bool copy
) {
788 if (madIn
->isVArray()) return madIn
;
789 auto const mad
= copy
? madIn
->copy() : madIn
;
790 mad
->m_kind
= HeaderKind::BespokeVArray
;
791 assertx(mad
->checkInvariants());
796 ArrayData
* MonotypeVec::ToHackArr(MonotypeVec
* madIn
, bool copy
) {
797 if (madIn
->isVecType()) return madIn
;
798 auto const mad
= copy
? madIn
->copy() : madIn
;
799 mad
->setLegacyArrayInPlace(false);
800 mad
->m_kind
= HeaderKind::BespokeVec
;
801 assertx(mad
->checkInvariants());
806 ArrayData
* MonotypeVec::PreSort(MonotypeVec
* mad
, SortFunction sf
) {
807 return mad
->escalateWithCapacity(mad
->size());
810 ArrayData
* MonotypeVec::PostSort(MonotypeVec
* mad
, ArrayData
* vad
) {
811 auto const result
= MakeFromVanilla(vad
, mad
->type());
812 PackedArray::Release(vad
);
816 ArrayData
* MonotypeVec::SetLegacyArray(MonotypeVec
* madIn
,
817 bool copy
, bool legacy
) {
818 auto const mad
= copy
? madIn
->copy() : madIn
;
819 mad
->setLegacyArrayInPlace(legacy
);
823 //////////////////////////////////////////////////////////////////////////////
827 std::pair
<Type
, bool> EmptyMonotypeVecLayout::elemType(Type key
) const {
828 return {TBottom
, false};
831 std::pair
<Type
, bool> EmptyMonotypeVecLayout::firstLastType(
832 bool isFirst
, bool isKey
) const {
833 return {TBottom
, false};
836 Type
EmptyMonotypeVecLayout::iterPosType(Type pos
, bool isKey
) const {
840 std::pair
<Type
, bool> MonotypeVecLayout::elemType(Type key
) const {
841 return {Type(m_fixedType
), false};
844 std::pair
<Type
, bool> MonotypeVecLayout::firstLastType(
845 bool isFirst
, bool isKey
) const {
846 return {isKey
? TInt
: Type(m_fixedType
), false};
849 Type
MonotypeVecLayout::iterPosType(Type pos
, bool isKey
) const {
850 return isKey
? TInt
: Type(m_fixedType
);
854 std::pair
<Type
, bool> EmptyOrMonotypeVecLayout::elemType(Type key
) const {
855 return {Type(m_fixedType
), false};
858 std::pair
<Type
, bool> EmptyOrMonotypeVecLayout::firstLastType(
859 bool isFirst
, bool isKey
) const {
860 return {isKey
? TInt
: Type(m_fixedType
), false};
863 Type
EmptyOrMonotypeVecLayout::iterPosType(Type pos
, bool isKey
) const {
864 return isKey
? TInt
: Type(m_fixedType
);
867 //////////////////////////////////////////////////////////////////////////////
868 // Layout creation and usage API
869 //////////////////////////////////////////////////////////////////////////////
871 void MonotypeVec::InitializeLayouts() {
872 auto const base
= Layout::ReserveIndices(1 << 9);
873 always_assert(base
== kBaseLayoutIndex
);
875 new TopMonotypeVecLayout();
877 #define DT(name, value) { \
878 auto const type = KindOf##name; \
879 if (type == dt_modulo_persistence(type)) { \
880 new EmptyOrMonotypeVecLayout(type); \
886 new EmptyMonotypeVecLayout();
888 // Create all the potentially internal concrete layouts first
889 #define DT(name, value) { \
890 auto const type = KindOf##name; \
891 if (type == dt_modulo_persistence(type)) { \
892 new MonotypeVecLayout(type); \
898 #define DT(name, value) { \
899 auto const type = KindOf##name; \
900 if (type != dt_modulo_persistence(type)) { \
901 new MonotypeVecLayout(type); \
907 auto const init
= [&](EmptyMonotypeVec
* ead
, HeaderKind hk
, bool legacy
) {
909 packSizeIndexAndAuxBits(0, legacy
? ArrayData::kLegacyArray
: 0);
910 ead
->initHeader_16(hk
, StaticValue
, aux
);
912 ead
->setLayoutIndex(getEmptyLayoutIndex());
913 assertx(ead
->checkInvariants());
916 init(EmptyMonotypeVec::GetVec(false), HeaderKind::BespokeVec
, false);
917 init(EmptyMonotypeVec::GetVArray(false), HeaderKind::BespokeVArray
, false);
918 init(EmptyMonotypeVec::GetVec(true), HeaderKind::BespokeVec
, true);
919 init(EmptyMonotypeVec::GetVArray(true), HeaderKind::BespokeVArray
, true);
922 TopMonotypeVecLayout::TopMonotypeVecLayout()
924 Index(), "MonotypeVec<Top>",
925 {AbstractLayout::GetBespokeTopIndex()})
928 LayoutIndex
TopMonotypeVecLayout::Index() {
929 auto const t
= int8_t(kEmptyDataType
) ^ int8_t(kAbstractDataTypeMask
);
930 return MonotypeVecLayout::Index(static_cast<DataType
>(t
));
933 EmptyOrMonotypeVecLayout::EmptyOrMonotypeVecLayout(DataType type
)
935 Index(type
), folly::sformat("MonotypeVec<Empty|{}>", tname(type
)),
936 {TopMonotypeVecLayout::Index()}),
940 LayoutIndex
EmptyOrMonotypeVecLayout::Index(DataType type
) {
941 assertx(type
== dt_modulo_persistence(type
));
942 auto const t
= int8_t(type
) ^ int8_t(kAbstractDataTypeMask
);
943 return MonotypeVecLayout::Index(static_cast<DataType
>(t
));
946 EmptyMonotypeVecLayout::EmptyMonotypeVecLayout()
948 Index(), "MonotypeVec<Empty>", &s_emptyMonotypeVecVtable
,
949 {getAllEmptyOrMonotypeVecLayouts()})
952 LayoutIndex
EmptyMonotypeVecLayout::Index() {
953 return getEmptyLayoutIndex();
956 MonotypeVecLayout::MonotypeVecLayout(DataType type
)
959 folly::sformat("MonotypeVec<{}>", tname(type
)),
960 &s_monotypeVecVtable
,
961 {getMonotypeParentLayout(type
)})
965 LayoutIndex
MonotypeVecLayout::Index(DataType type
) {
966 return getLayoutIndex(type
);
969 bool isMonotypeVecLayout(LayoutIndex index
) {
970 return kBaseLayoutIndex
.raw
<= index
.raw
&&
971 index
.raw
< 2 * kBaseLayoutIndex
.raw
;