abstract constants: preclass/class emission [2/2]
[hiphop-php.git] / hphp / runtime / base / typed-value.h
blob6b39e5483ee87e0c6cbfc292ce7b257bc71ed052
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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>
20 #include <string>
21 #include <cstdint>
22 #include <cstdlib>
24 #include "hphp/runtime/base/datatype.h"
26 namespace HPHP {
28 //////////////////////////////////////////////////////////////////////
30 struct Class;
31 struct ArrayData;
32 struct StringData;
33 struct ObjectData;
34 struct RefData;
35 struct ResourceData;
36 struct TypedValue;
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.
45 union Value {
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 };
58 union AuxUnion {
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
67 * 7pack format:
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):
72 * 0 1 2 7 8 16 56
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:
78 * 0 1 2 3 4 8
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.
87 #ifdef PACKED_TV
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.
90 struct TypedValue {
91 union {
92 uint8_t _tags[8];
93 struct {
94 uint8_t _t0;
95 DataType m_type;
96 AuxUnion m_aux;
99 Value m_data;
101 std::string pretty() const;
103 #else
104 struct TypedValue {
105 Value m_data;
106 DataType m_type;
107 AuxUnion m_aux;
109 std::string pretty() const; // debug formatting. see trace.h
111 #endif
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; }
141 private:
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
158 * KindOfRef).
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
169 * KindOfInt64.
171 typedef TypedValue TypedNum;
173 //////////////////////////////////////////////////////////////////////
175 template<DataType> struct DataTypeCPPType;
176 #define X(dt, cpp) \
177 template<> struct DataTypeCPPType<dt> { typedef cpp type; }
179 X(KindOfUninit, void);
180 X(KindOfNull, 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*);
191 #undef X
194 * make_value and make_tv are helpers for creating TypedValues and
195 * Values as temporaries, without messing up the conversions.
198 template<class T>
199 typename std::enable_if<
200 std::is_integral<T>::value,
201 Value
202 >::type make_value(T t) { Value v; v.num = t; return v; }
204 template<class T>
205 typename std::enable_if<
206 std::is_pointer<T>::value,
207 Value
208 >::type make_value(T t) {
209 Value v;
210 v.num = reinterpret_cast<int64_t>(t);
211 return v;
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,
225 TypedValue
226 >::type make_tv(typename DataTypeCPPType<DType>::type val) {
227 TypedValue ret;
228 ret.m_data = make_value(val);
229 ret.m_type = DType;
230 return ret;
233 template<DataType DType>
234 typename std::enable_if<
235 std::is_same<typename DataTypeCPPType<DType>::type,void>::value,
236 TypedValue
237 >::type make_tv() {
238 TypedValue ret;
239 ret.m_type = DType;
240 return ret;
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,
251 double
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>
274 (tv->m_data.pstr);
277 //////////////////////////////////////////////////////////////////////
281 #endif