2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/base/array-provenance.h"
18 #include "hphp/runtime/base/runtime-option.h"
20 #include "hphp/util/portability.h"
24 ///////////////////////////////////////////////////////////////////////////////
27 * NOTE: MixedArray no longer calls this constructor. If you change it, change
28 * the MixedArray::Make functions as appropriate.
30 inline ArrayData::ArrayData(ArrayKind kind
, RefCount initial_count
)
31 : m_sizeAndPos(uint32_t(-1))
33 initHeader(static_cast<HeaderKind
>(kind
), initial_count
);
34 assertx(m_size
== -1);
36 assertx(m_kind
== static_cast<HeaderKind
>(kind
));
39 ///////////////////////////////////////////////////////////////////////////////
41 ALWAYS_INLINE ArrayData
* staticEmptyArray() {
42 return staticEmptyDArray();
45 ALWAYS_INLINE ArrayData
* staticEmptyVArray() {
46 void* vp1
= &s_theEmptyVArray
;
47 void* vp2
= &s_theEmptyVec
;
48 void* vp3
= &s_theEmptyMarkedVec
;
49 return static_cast<ArrayData
*>(
50 RuntimeOption::EvalHackArrDVArrs
?
51 RuntimeOption::EvalHackArrDVArrMark
? vp3
: vp2
56 ALWAYS_INLINE ArrayData
* staticEmptyVec() {
57 void* vp
= &s_theEmptyVec
;
58 return static_cast<ArrayData
*>(vp
);
61 ALWAYS_INLINE ArrayData
* staticEmptyMarkedVec() {
62 void* vp
= &s_theEmptyMarkedVec
;
63 return static_cast<ArrayData
*>(vp
);
66 ALWAYS_INLINE ArrayData
* staticEmptyDArray() {
67 void* vp1
= &s_theEmptyDArray
;
68 void* vp2
= &s_theEmptyDictArray
;
69 void* vp3
= &s_theEmptyMarkedDictArray
;
70 return static_cast<ArrayData
*>(
71 RuntimeOption::EvalHackArrDVArrs
?
72 RuntimeOption::EvalHackArrDVArrMark
? vp3
: vp2
77 ALWAYS_INLINE ArrayData
* staticEmptyDictArray() {
78 void* vp
= &s_theEmptyDictArray
;
79 return static_cast<ArrayData
*>(vp
);
82 ALWAYS_INLINE ArrayData
* staticEmptyMarkedDictArray() {
83 void* vp
= &s_theEmptyMarkedDictArray
;
84 return static_cast<ArrayData
*>(vp
);
87 ALWAYS_INLINE ArrayData
* staticEmptyKeysetArray() {
88 void* vp
= &s_theEmptySetArray
;
89 return static_cast<ArrayData
*>(vp
);
92 ///////////////////////////////////////////////////////////////////////////////
93 // Creation and destruction.
95 ALWAYS_INLINE ArrayData
* ArrayData::Create() {
96 return ArrayData::CreateDArray();
99 ALWAYS_INLINE ArrayData
* ArrayData::CreateVArray(arrprov::Tag tag
/* = {} */) {
100 return RO::EvalArrayProvenance
101 ? arrprov::tagStaticArr(staticEmptyVArray(), tag
)
102 : staticEmptyVArray();
105 ALWAYS_INLINE ArrayData
* ArrayData::CreateDArray(arrprov::Tag tag
/* = {} */) {
106 return RO::EvalArrayProvenance
107 ? arrprov::tagStaticArr(staticEmptyDArray(), tag
)
108 : staticEmptyDArray();
111 ALWAYS_INLINE ArrayData
* ArrayData::CreateVec(arrprov::Tag tag
/* = {} */) {
112 return staticEmptyVec();
115 ALWAYS_INLINE ArrayData
* ArrayData::CreateDict(arrprov::Tag tag
/* = {} */) {
116 return staticEmptyDictArray();
119 ALWAYS_INLINE ArrayData
* ArrayData::CreateKeyset() {
120 return staticEmptyKeysetArray();
123 ALWAYS_INLINE
void ArrayData::decRefAndRelease() {
124 assertx(kindIsValid());
125 if (decReleaseCheck()) release();
128 ///////////////////////////////////////////////////////////////////////////////
129 // ArrayFunction dispatch.
131 inline size_t ArrayData::vsize() const {
132 return g_array_funcs
.vsize
[kind()](this);
135 inline void ArrayData::release() noexcept
{
136 assertx(!hasMultipleRefs());
137 g_array_funcs
.release
[kind()](this);
138 AARCH64_WALKABLE_FRAME();
141 ///////////////////////////////////////////////////////////////////////////////
144 inline size_t ArrayData::size() const {
145 if (UNLIKELY((int)m_size
< 0)) return vsize();
149 inline size_t ArrayData::getSize() const {
153 inline bool ArrayData::empty() const {
157 inline bool ArrayData::kindIsValid() const {
158 return isArrayKind(m_kind
);
161 inline ArrayData::ArrayKind
ArrayData::kind() const {
162 assertx(kindIsValid());
163 return static_cast<ArrayKind
>(m_kind
);
166 inline bool ArrayData::isPackedKind() const { return kind() == kPackedKind
; }
167 inline bool ArrayData::isMixedKind() const { return kind() == kMixedKind
; }
168 inline bool ArrayData::isVecKind() const { return kind() == kVecKind
; }
169 inline bool ArrayData::isDictKind() const { return kind() == kDictKind
; }
170 inline bool ArrayData::isKeysetKind() const { return kind() == kKeysetKind
; }
172 inline bool ArrayData::isPHPArrayType() const {
173 return kind() < kDictKind
;
175 inline bool ArrayData::isHackArrayType() const {
176 return kind() >= kDictKind
;
179 inline bool ArrayData::isVecType() const {
180 return (kind() & ~kBespokeKindMask
) == kVecKind
;
182 inline bool ArrayData::isDictType() const {
183 return (kind() & ~kBespokeKindMask
) == kDictKind
;
185 inline bool ArrayData::isKeysetType() const {
186 return (kind() & ~kBespokeKindMask
) == kKeysetKind
;
189 inline bool ArrayData::hasVanillaPackedLayout() const {
190 return isPackedKind() || isVecKind();
192 inline bool ArrayData::hasVanillaMixedLayout() const {
193 return isMixedKind() || isDictKind();
196 inline bool ArrayData::isVanilla() const {
197 return !(kind() & kBespokeKindMask
);
200 inline bool ArrayData::bothVanilla(const ArrayData
* ad1
, const ArrayData
* ad2
) {
201 return !((ad1
->kind() | ad2
->kind()) & kBespokeKindMask
);
204 inline bool ArrayData::isVArray() const {
205 return (kind() & ~kBespokeKindMask
) == kPackedKind
;
208 inline bool ArrayData::isDArray() const {
209 static_assert(kMixedKind
== 0);
210 static_assert(kBespokeDArrayKind
== 1);
211 return kind() <= kBespokeDArrayKind
;
214 inline bool ArrayData::isDVArray() const {
215 static_assert(kMixedKind
== 0);
216 static_assert(kBespokeDArrayKind
== 1);
217 static_assert(kPackedKind
== 2);
218 static_assert(kBespokeVArrayKind
== 3);
219 return kind() <= kBespokeVArrayKind
;
222 inline bool ArrayData::isNotDVArray() const { return !isDVArray(); }
224 inline bool ArrayData::isHAMSafeVArray() const {
225 return RuntimeOption::EvalHackArrDVArrs
? isVecType() : isVArray();
227 inline bool ArrayData::isHAMSafeDArray() const {
228 return RuntimeOption::EvalHackArrDVArrs
? isDictType() : isDArray();
230 inline bool ArrayData::isHAMSafeDVArray() const {
231 return RuntimeOption::EvalHackArrDVArrs
? isDictType() || isVecType()
235 inline bool ArrayData::dvArrayEqual(const ArrayData
* a
, const ArrayData
* b
) {
236 static_assert(kMixedKind
== 0);
237 static_assert(kBespokeDArrayKind
== 1);
238 static_assert(kPackedKind
== 2);
239 static_assert(kBespokeVArrayKind
== 3);
240 return std::min(uint8_t(a
->kind() & ~kBespokeKindMask
), uint8_t{4}) ==
241 std::min(uint8_t(b
->kind() & ~kBespokeKindMask
), uint8_t{4});
244 inline bool ArrayData::hasApcTv() const { return m_aux16
& kHasApcTv
; }
246 inline bool ArrayData::isLegacyArray() const { return m_aux16
& kLegacyArray
; }
248 inline bool ArrayData::hasStrKeyTable() const {
249 return m_aux16
& kHasStrKeyTable
;
252 inline uint8_t ArrayData::auxBits() const {
253 return isLegacyArray() ? kLegacyArray
: 0;
256 ///////////////////////////////////////////////////////////////////////////////
259 DataType
ArrayData::toDataType() const {
262 case kBespokeVArrayKind
:
266 case kBespokeDArrayKind
:
270 case kBespokeVecKind
:
274 case kBespokeDictKind
:
278 case kBespokeKeysetKind
:
281 case kNumKinds
: not_reached();
287 DataType
ArrayData::toPersistentDataType() const {
290 case kBespokeVArrayKind
:
291 return KindOfPersistentVArray
;
294 case kBespokeDArrayKind
:
295 return KindOfPersistentDArray
;
298 case kBespokeVecKind
:
299 return KindOfPersistentVec
;
302 case kBespokeDictKind
:
303 return KindOfPersistentDict
;
306 case kBespokeKeysetKind
:
307 return KindOfPersistentKeyset
;
309 case kNumKinds
: not_reached();
314 ///////////////////////////////////////////////////////////////////////////////
317 inline int32_t ArrayData::getPosition() const {
318 return isVanilla() ? m_pos
: iter_begin();
321 inline void ArrayData::setPosition(int32_t p
) {
322 auto const cur_pos
= getPosition();
323 assertx(cur_pos
== p
|| (!isStatic() && isVanilla()));
324 if (cur_pos
!= p
) m_pos
= p
;
327 inline bool ArrayData::isHead() const {
328 return getPosition() == iter_begin();
331 inline bool ArrayData::isTail() const {
332 return getPosition() == iter_last();
335 inline bool ArrayData::isInvalid() const {
336 return getPosition() == iter_end();
339 ///////////////////////////////////////////////////////////////////////////////
341 inline bool ArrayData::IsValidKey(const StringData
* k
) {
345 ///////////////////////////////////////////////////////////////////////////////
348 bool ArrayData::hasProvenanceData() const {
349 return m_aux16
& kHasProvenanceData
;
353 void ArrayData::setHasProvenanceData(bool value
) {
354 m_aux16
= (m_aux16
& ~kHasProvenanceData
) |
355 (value
? kHasProvenanceData
: 0);
358 ///////////////////////////////////////////////////////////////////////////////
360 ALWAYS_INLINE
void decRefArr(ArrayData
* arr
) {
361 arr
->decRefAndRelease();
364 ///////////////////////////////////////////////////////////////////////////////
366 ALWAYS_INLINE
bool checkHACCompare() {
367 return RuntimeOption::EvalHackArrCompatNotices
&&
368 RuntimeOption::EvalHackArrCompatCheckCompare
;
370 ALWAYS_INLINE
bool checkHACArrayPlus() {
371 return RuntimeOption::EvalHackArrCompatNotices
&&
372 RuntimeOption::EvalHackArrCompatCheckArrayPlus
;
375 ///////////////////////////////////////////////////////////////////////////////
377 namespace arrprov_detail
{
378 template<typename SrcArray
>
379 ArrayData
* tagArrProvImpl(ArrayData
*, const SrcArray
*);
382 ALWAYS_INLINE ArrayData
* tagArrProv(ArrayData
* ad
, const ArrayData
* src
) {
383 return RO::EvalArrayProvenance
384 ? arrprov_detail::tagArrProvImpl(ad
, src
)
387 ALWAYS_INLINE ArrayData
* tagArrProv(ArrayData
* ad
, const APCArray
* src
) {
388 return RO::EvalArrayProvenance
389 ? arrprov_detail::tagArrProvImpl(ad
, src
)
393 ///////////////////////////////////////////////////////////////////////////////