2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_HPHPVALUE_H_
17 #define incl_HPHP_HPHPVALUE_H_
19 #include <type_traits>
24 #include "hphp/runtime/base/datatype.h"
28 //////////////////////////////////////////////////////////////////////
38 //////////////////////////////////////////////////////////////////////
41 * This is the payload of a PHP value. This union may only be used in
42 * contexts that have a discriminator, e.g. in TypedValue (below), or
43 * when the type is known beforehand.
46 int64_t num
; // KindOfInt64, KindOfBool (must be zero-extended)
47 double dbl
; // KindOfDouble
48 StringData
* pstr
; // KindOfString, KindOfStaticString
49 ArrayData
* parr
; // KindOfArray
50 ObjectData
* pobj
; // KindOfObject
51 ResourceData
* pres
; // KindOfResource
52 Class
* pcls
; // only in vm stack, no type tag.
53 RefData
* pref
; // KindOfRef
56 enum VarNrFlag
{ NR_FLAG
= 1<<29 };
59 int32_t u_hash
; // key type and hash for MixedArray and [Stable]Map
60 VarNrFlag u_varNrFlag
; // magic number for asserts in VarNR
61 bool u_deepInit
; // used by Class::initPropsImpl for deep init
62 int32_t u_rdsHandle
; // used by unit.cpp to squirrel away rds handles TODO type
63 bool u_isAbstractConst
; // used by Class::Const
68 * experimental "Packed" format for TypedValues. By grouping 7 tags
69 * and 7 values separately, we can fit 7 TypedValues in 63 bytes (64 with
70 * a throw-away alignment byte (t0):
73 * [t0][t1][t2]..[t7][value1][value2]..[value7]
75 * With this layout, a single TypedValue requires 16 bytes, and still has
76 * room for a 32-bit padding field, which we still use in a few places:
79 * [t0][m_type][t2][t3][m_pad][m_data]
83 * A TypedValue is a descriminated PHP Value. m_tag describes the contents
84 * of m_data. m_aux is described above, and must only be read or written
85 * in specialized contexts.
88 // This TypedValue layout is a subset of the full 7pack format. Client
89 // code should not mess with the _t0 or _tags padding fields.
101 std::string
pretty() const;
109 std::string
pretty() const; // debug formatting. see trace.h
113 // Check that TypedValue's size is a power of 2 (16bytes currently)
114 static_assert((sizeof(TypedValue
) & (sizeof(TypedValue
)-1)) == 0,
115 "TypedValue's size is expected to be a power of 2");
116 constexpr size_t kTypedValueAlignMask
= sizeof(TypedValue
) - 1;
117 constexpr size_t alignTypedValue(size_t sz
) {
118 return (sz
+ kTypedValueAlignMask
) & ~kTypedValueAlignMask
;
122 * This TypedValue subclass exposes a 32-bit "aux" field somewhere inside it.
123 * For now, access the m_aux field declared in TypedValue, but once we
124 * rearrange TypedValue, the aux field can move down to this struct.
125 * TODO: t1100154 phase this out completely.
127 struct TypedValueAux
: TypedValue
{
128 static constexpr size_t auxOffset
= offsetof(TypedValue
, m_aux
);
129 static const size_t auxSize
= sizeof(m_aux
);
130 int32_t& hash() { return m_aux
.u_hash
; }
131 const int32_t& hash() const { return m_aux
.u_hash
; }
132 int32_t& rdsHandle() { return m_aux
.u_rdsHandle
; }
133 const int32_t& rdsHandle() const { return m_aux
.u_rdsHandle
; }
134 bool& deepInit() { return m_aux
.u_deepInit
; }
135 const bool& deepInit() const { return m_aux
.u_deepInit
; }
136 bool& isAbstractConst() { return m_aux
.u_isAbstractConst
; }
137 const bool& isAbstractConst() const { return m_aux
.u_isAbstractConst
; }
138 VarNrFlag
& varNrFlag() { return m_aux
.u_varNrFlag
; }
139 const VarNrFlag
& varNrFlag() const { return m_aux
.u_varNrFlag
; }
142 static void assertions() {
143 static_assert(sizeof(TypedValueAux
) <= 16,
144 "don't add big things to AuxUnion");
149 * Sometimes TypedValues need to be allocated with alignment that
150 * allows use of 128-bit SIMD stores/loads. This constant just helps
151 * self-document that case.
153 constexpr size_t kTVSimdAlign
= 0x10;
156 * These may be used to provide a little more self-documentation about
157 * whether typed values must be cells (not KindOfRef) or ref (must be
160 * See bytecode.specification for details. Note that in
161 * bytecode.specification, refs are abbreviated as "V".
164 typedef TypedValue Cell
;
165 typedef TypedValue Ref
;
168 * A TypedNum is a TypedValue that is either KindOfDouble or
171 typedef TypedValue TypedNum
;
173 //////////////////////////////////////////////////////////////////////
175 template<DataType
> struct DataTypeCPPType
;
177 template<> struct DataTypeCPPType<dt> { typedef cpp type; }
179 X(KindOfUninit
, void);
181 X(KindOfBoolean
, bool);
182 X(KindOfInt64
, int64_t);
183 X(KindOfDouble
, double);
184 X(KindOfArray
, ArrayData
*);
185 X(KindOfObject
, ObjectData
*);
186 X(KindOfResource
, ResourceData
*);
187 X(KindOfRef
, RefData
*);
188 X(KindOfString
, StringData
*);
189 X(KindOfStaticString
, const StringData
*);
194 * make_value and make_tv are helpers for creating TypedValues and
195 * Values as temporaries, without messing up the conversions.
199 typename
std::enable_if
<
200 std::is_integral
<T
>::value
,
202 >::type
make_value(T t
) { Value v
; v
.num
= t
; return v
; }
205 typename
std::enable_if
<
206 std::is_pointer
<T
>::value
,
208 >::type
make_value(T t
) {
210 v
.num
= reinterpret_cast<int64_t>(t
);
214 inline Value
make_value(double d
) { Value v
; v
.dbl
= d
; return v
; }
217 * Pack a base data element into a TypedValue for use
218 * elsewhere in the runtime.
220 * TypedValue tv = make_tv<KindOfInt64>(123);
222 template<DataType DType
>
223 typename
std::enable_if
<
224 !std::is_same
<typename DataTypeCPPType
<DType
>::type
,void>::value
,
226 >::type
make_tv(typename DataTypeCPPType
<DType
>::type val
) {
228 ret
.m_data
= make_value(val
);
233 template<DataType DType
>
234 typename
std::enable_if
<
235 std::is_same
<typename DataTypeCPPType
<DType
>::type
,void>::value
,
244 * Extract the underlying data element for the TypedValue
246 * int64_t val = unpack_tv<KindOfInt64>(tv);
248 template <DataType DType
>
249 typename
std::enable_if
<
250 std::is_same
<typename DataTypeCPPType
<DType
>::type
,double>::value
,
252 >::type
unpack_tv(TypedValue
*tv
) {
253 assert(DType
== tv
->m_type
);
254 return tv
->m_data
.dbl
;
257 template <DataType DType
>
258 typename
std::enable_if
<
259 std::is_integral
<typename DataTypeCPPType
<DType
>::type
>::value
,
260 typename DataTypeCPPType
<DType
>::type
261 >::type
unpack_tv(TypedValue
*tv
) {
262 assert(DType
== tv
->m_type
);
263 return tv
->m_data
.num
;
266 template <DataType DType
>
267 typename
std::enable_if
<
268 std::is_pointer
<typename DataTypeCPPType
<DType
>::type
>::value
,
269 typename DataTypeCPPType
<DType
>::type
270 >::type
unpack_tv(TypedValue
*tv
) {
271 assert((DType
== tv
->m_type
) ||
272 (IS_STRING_TYPE(DType
) && IS_STRING_TYPE(tv
->m_type
)));
273 return reinterpret_cast<typename DataTypeCPPType
<DType
>::type
>
277 //////////////////////////////////////////////////////////////////////