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/runtime-option.h"
19 #include "hphp/util/portability.h"
23 ///////////////////////////////////////////////////////////////////////////////
26 * NOTE: MixedArray no longer calls this constructor. If you change it, change
27 * the MixedArray::Make functions as appropriate.
29 inline ArrayData::ArrayData(ArrayKind kind
, RefCount initial_count
)
30 : m_sizeAndPos(uint32_t(-1))
32 initHeader(static_cast<HeaderKind
>(kind
), initial_count
);
33 assertx(m_size
== -1);
35 assertx(m_kind
== static_cast<HeaderKind
>(kind
));
36 assertx(dvArraySanityCheck());
39 ///////////////////////////////////////////////////////////////////////////////
41 ALWAYS_INLINE ArrayData
* staticEmptyArray() {
42 void* vp
= &s_theEmptyArray
;
43 return static_cast<ArrayData
*>(vp
);
46 ALWAYS_INLINE ArrayData
* staticEmptyVArray() {
47 void* vp1
= &s_theEmptyVArray
;
48 void* vp2
= &s_theEmptyVecArray
;
49 return static_cast<ArrayData
*>(RuntimeOption::EvalHackArrDVArrs
? vp2
: vp1
);
52 ALWAYS_INLINE ArrayData
* staticEmptyVecArray() {
53 void* vp
= &s_theEmptyVecArray
;
54 return static_cast<ArrayData
*>(vp
);
57 ALWAYS_INLINE ArrayData
* staticEmptyDArray() {
58 void* vp1
= &s_theEmptyDArray
;
59 void* vp2
= &s_theEmptyDictArray
;
60 return static_cast<ArrayData
*>(RuntimeOption::EvalHackArrDVArrs
? vp2
: vp1
);
63 ALWAYS_INLINE ArrayData
* staticEmptyDictArray() {
64 void* vp
= &s_theEmptyDictArray
;
65 return static_cast<ArrayData
*>(vp
);
68 ALWAYS_INLINE ArrayData
* staticEmptyShapeArray() {
69 void* vp
= RuntimeOption::EvalHackArrDVArrs
70 ? &s_theEmptyShapeDict
: &s_theEmptyShapeDArray
;
71 return static_cast<ArrayData
*>(vp
);
74 ALWAYS_INLINE ArrayData
* staticEmptyKeysetArray() {
75 void* vp
= &s_theEmptySetArray
;
76 return static_cast<ArrayData
*>(vp
);
79 ///////////////////////////////////////////////////////////////////////////////
80 // Creation and destruction.
82 ALWAYS_INLINE ArrayData
* ArrayData::Create() {
83 return staticEmptyArray();
86 ALWAYS_INLINE ArrayData
* ArrayData::CreateVArray() {
87 return staticEmptyVArray();
90 ALWAYS_INLINE ArrayData
* ArrayData::CreateVec() {
91 return staticEmptyVecArray();
94 ALWAYS_INLINE ArrayData
* ArrayData::CreateDArray() {
95 return staticEmptyDArray();
98 ALWAYS_INLINE ArrayData
* ArrayData::CreateDict() {
99 return staticEmptyDictArray();
102 ALWAYS_INLINE ArrayData
* ArrayData::CreateShape() {
103 return staticEmptyShapeArray();
106 ALWAYS_INLINE ArrayData
* ArrayData::CreateKeyset() {
107 return staticEmptyKeysetArray();
110 ALWAYS_INLINE
void ArrayData::decRefAndRelease() {
111 assertx(kindIsValid());
112 if (decReleaseCheck()) release();
115 ///////////////////////////////////////////////////////////////////////////////
116 // ArrayFunction dispatch.
118 inline size_t ArrayData::vsize() const {
119 return g_array_funcs
.vsize
[kind()](this);
122 ///////////////////////////////////////////////////////////////////////////////
125 inline size_t ArrayData::size() const {
126 if (UNLIKELY((int)m_size
) < 0) return vsize();
130 inline size_t ArrayData::getSize() const {
134 inline bool ArrayData::empty() const {
138 inline bool ArrayData::kindIsValid() const {
139 return isArrayKind(m_kind
);
142 inline ArrayData::ArrayKind
ArrayData::kind() const {
143 assertx(kindIsValid());
144 return static_cast<ArrayKind
>(m_kind
);
147 inline bool ArrayData::noCopyOnWrite() const {
148 // GlobalsArray doesn't support COW.
149 return kind() == kGlobalsKind
;
152 inline bool ArrayData::isPacked() const { return kind() == kPackedKind
; }
153 inline bool ArrayData::isMixed() const { return kind() == kMixedKind
; }
156 * isMixedOrShape checks whether the ArrayData is kMixedKind or a Shape that
157 * behaves like a mixed PHP Array. This is important because this check is
158 * often used to check that a piece of code is only operating on
159 * mixed PHP array-like objects and not dict-like objects.
161 inline bool ArrayData::isMixedOrShape() const {
162 return kind() == kMixedKind
||
163 (!RuntimeOption::EvalHackArrDVArrs
&& kind() == kShapeKind
);
165 inline bool ArrayData::isApcArray() const { return kind() == kApcKind
; }
166 inline bool ArrayData::isGlobalsArray() const { return kind() == kGlobalsKind
; }
167 inline bool ArrayData::isEmptyArray() const { return kind() == kEmptyKind
; }
168 inline bool ArrayData::isDict() const { return kind() == kDictKind
; }
171 * isDictOrShape checks whether the ArrayData is a dict or a Shape that
172 * behaves like a dict. This is important because this check is often used
173 * to check that a piece of code is only operating on dict-like objects and
174 * not array-like objects.
176 inline bool ArrayData::isDictOrShape() const {
177 return kind() == kDictKind
||
178 (RuntimeOption::EvalHackArrDVArrs
&& kind() == kShapeKind
);
180 inline bool ArrayData::isVecArray() const { return kind() == kVecKind
; }
181 inline bool ArrayData::isKeyset() const { return kind() == kKeysetKind
; }
182 inline bool ArrayData::isShape() const { return kind() == kShapeKind
; }
184 inline bool ArrayData::hasPackedLayout() const {
185 return isPacked() || isVecArray();
187 inline bool ArrayData::hasMixedLayout() const {
188 return isMixed() || isDict() || isShape();
191 inline bool ArrayData::isPHPArray() const {
192 return RuntimeOption::EvalHackArrDVArrs
193 ? kind() < kShapeKind
194 : kind() <= kShapeKind
;
197 inline bool ArrayData::isHackArray() const {
198 return RuntimeOption::EvalHackArrDVArrs
199 ? kind() >= kShapeKind
200 : kind() >= kDictKind
;
203 inline ArrayData::DVArray
ArrayData::dvArray() const {
204 // The darray/varray state is stored in the lower 2-bits of m_aux16. The
205 // array is free to store whatever it wants in the upper 14-bits.
206 return static_cast<DVArray
>(m_aux16
& kDVArrayMask
);
209 inline void ArrayData::setDVArray(DVArray d
) {
210 assertx(!RuntimeOption::EvalHackArrDVArrs
|| d
== kNotDVArray
);
211 assertx(!(d
& ~kDVArrayMask
));
212 m_aux16
= (m_aux16
& ~kDVArrayMask
) | d
;
215 inline bool ArrayData::isVArray() const { return dvArray() & kVArray
; }
216 inline bool ArrayData::isDArray() const { return dvArray() & kDArray
; }
218 inline bool ArrayData::isNotDVArray() const { return dvArray() == kNotDVArray
; }
219 inline bool ArrayData::isVecOrVArray() const {
220 return RuntimeOption::EvalHackArrDVArrs
? isVecArray() : isVArray();
222 inline bool ArrayData::isDictOrDArray() const {
223 return RuntimeOption::EvalHackArrDVArrs
? isDict() : isDArray();
226 inline bool ArrayData::isDictOrDArrayOrShape() const {
227 return isShape() || isDictOrDArray();
230 // gcc doesn't optimize (a & 3) == (b & 3) very well; help it a little.
231 inline bool ArrayData::dvArrayEqual(const ArrayData
* a
, const ArrayData
* b
) {
232 return ((a
->m_aux16
^ b
->m_aux16
) & kDVArrayMask
) == 0;
235 inline bool ArrayData::dvArraySanityCheck() const {
236 auto const dv
= dvArray();
237 if (!RuntimeOption::EvalHackArrDVArrs
) {
238 if (isPacked()) return !(dv
& kDArray
);
239 if (isMixed()) return !(dv
& kVArray
);
240 if (isShape()) return dv
== kDArray
;
242 return dv
== kNotDVArray
;
245 inline bool ArrayData::hasApcTv() const { return m_aux16
& kHasApcTv
; }
247 inline bool ArrayData::isLegacyArray() const { return m_aux16
& kLegacyArray
; }
249 inline void ArrayData::setLegacyArray(bool legacy
) {
250 assertx(!legacy
|| kind() == kDictKind
|| kind() == kVecKind
);
251 m_aux16
= (m_aux16
& ~kLegacyArray
) | (legacy
? kLegacyArray
: 0);
254 inline uint8_t ArrayData::auxBits() const {
255 return dvArray() | (isLegacyArray() ? kLegacyArray
: 0);
258 inline bool ArrayData::useWeakKeys() const { return isPHPArray(); }
260 inline DataType
ArrayData::toDataType() const {
261 auto const k
= kind();
262 if (k
< kShapeKind
) return KindOfArray
;
263 if (k
== kVecKind
) return KindOfVec
;
264 if (k
== kDictKind
) return KindOfDict
;
265 if (k
== kShapeKind
) return KindOfShape
;
266 assertx(k
== kKeysetKind
);
270 inline DataType
ArrayData::toPersistentDataType() const {
271 auto const k
= kind();
272 if (k
< kShapeKind
) return KindOfPersistentArray
;
273 if (k
== kVecKind
) return KindOfPersistentVec
;
274 if (k
== kDictKind
) return KindOfPersistentDict
;
275 if (k
== kShapeKind
) return KindOfPersistentShape
;
276 assertx(k
== kKeysetKind
);
277 return KindOfPersistentKeyset
;
280 ///////////////////////////////////////////////////////////////////////////////
283 inline int32_t ArrayData::getPosition() const {
287 inline void ArrayData::setPosition(int32_t p
) {
288 assertx(m_pos
== p
|| !isStatic());
292 inline bool ArrayData::isHead() const {
293 return m_pos
== iter_begin();
296 inline bool ArrayData::isTail() const {
297 return m_pos
== iter_last();
300 inline bool ArrayData::isInvalid() const {
301 return m_pos
== iter_end();
304 ///////////////////////////////////////////////////////////////////////////////
306 inline bool ArrayData::IsValidKey(const StringData
* k
) {
310 ///////////////////////////////////////////////////////////////////////////////
313 bool ArrayData::hasProvenanceData() const {
314 return m_aux16
& kHasProvenanceData
;
318 void ArrayData::markHasProvenanceData() {
319 m_aux16
|= kHasProvenanceData
;
322 ///////////////////////////////////////////////////////////////////////////////
324 ALWAYS_INLINE
void decRefArr(ArrayData
* arr
) {
325 arr
->decRefAndRelease();
328 ///////////////////////////////////////////////////////////////////////////////
330 ALWAYS_INLINE
bool checkHACRefBind() {
331 return RuntimeOption::EvalHackArrCompatNotices
&&
332 RuntimeOption::EvalHackArrCompatCheckRefBind
;
334 ALWAYS_INLINE
bool checkHACFalseyPromote() {
335 return RuntimeOption::EvalHackArrCompatNotices
&&
336 RuntimeOption::EvalHackArrCompatCheckFalseyPromote
;
338 ALWAYS_INLINE
bool checkHACEmptyStringPromote() {
339 return RuntimeOption::EvalHackArrCompatNotices
&&
340 RuntimeOption::EvalHackArrCompatCheckEmptyStringPromote
;
342 ALWAYS_INLINE
bool checkHACCompare() {
343 return RuntimeOption::EvalHackArrCompatNotices
&&
344 RuntimeOption::EvalHackArrCompatCheckCompare
;
346 ALWAYS_INLINE
bool checkHACArrayPlus() {
347 return RuntimeOption::EvalHackArrCompatNotices
&&
348 RuntimeOption::EvalHackArrCompatCheckArrayPlus
;
350 ALWAYS_INLINE
bool checkHACArrayKeyCast() {
351 return RuntimeOption::EvalHackArrCompatNotices
&&
352 RuntimeOption::EvalHackArrCompatCheckArrayKeyCast
;
355 ///////////////////////////////////////////////////////////////////////////////