Add static empty legacy arrays
[hiphop-php.git] / hphp / runtime / base / array-data-inl.h
blob1a6ffa87acddc0ddec0251bf8dec9fae0c764c48
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
22 namespace HPHP {
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);
35 assertx(m_pos == 0);
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
52 : vp1
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
73 : vp1
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 ///////////////////////////////////////////////////////////////////////////////
142 // Introspection.
144 inline size_t ArrayData::size() const {
145 if (UNLIKELY((int)m_size < 0)) return vsize();
146 return m_size;
149 inline size_t ArrayData::getSize() const {
150 return m_size;
153 inline bool ArrayData::empty() const {
154 return size() == 0;
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()
232 : isDVArray();
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 ///////////////////////////////////////////////////////////////////////////////
258 ALWAYS_INLINE
259 DataType ArrayData::toDataType() const {
260 switch (kind()) {
261 case kPackedKind:
262 case kBespokeVArrayKind:
263 return KindOfVArray;
265 case kMixedKind:
266 case kBespokeDArrayKind:
267 return KindOfDArray;
269 case kVecKind:
270 case kBespokeVecKind:
271 return KindOfVec;
273 case kDictKind:
274 case kBespokeDictKind:
275 return KindOfDict;
277 case kKeysetKind:
278 case kBespokeKeysetKind:
279 return KindOfKeyset;
281 case kNumKinds: not_reached();
283 not_reached();
286 ALWAYS_INLINE
287 DataType ArrayData::toPersistentDataType() const {
288 switch (kind()) {
289 case kPackedKind:
290 case kBespokeVArrayKind:
291 return KindOfPersistentVArray;
293 case kMixedKind:
294 case kBespokeDArrayKind:
295 return KindOfPersistentDArray;
297 case kVecKind:
298 case kBespokeVecKind:
299 return KindOfPersistentVec;
301 case kDictKind:
302 case kBespokeDictKind:
303 return KindOfPersistentDict;
305 case kKeysetKind:
306 case kBespokeKeysetKind:
307 return KindOfPersistentKeyset;
309 case kNumKinds: not_reached();
311 not_reached();
314 ///////////////////////////////////////////////////////////////////////////////
315 // Iteration.
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) {
342 return k;
345 ///////////////////////////////////////////////////////////////////////////////
347 ALWAYS_INLINE
348 bool ArrayData::hasProvenanceData() const {
349 return m_aux16 & kHasProvenanceData;
352 ALWAYS_INLINE
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)
385 : ad;
387 ALWAYS_INLINE ArrayData* tagArrProv(ArrayData* ad, const APCArray* src) {
388 return RO::EvalArrayProvenance
389 ? arrprov_detail::tagArrProvImpl(ad, src)
390 : ad;
393 ///////////////////////////////////////////////////////////////////////////////