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 +----------------------------------------------------------------------+
19 #include "hphp/runtime/base/datatype.h"
20 #include "hphp/runtime/base/typed-value.h"
22 #include "hphp/util/compact-tagged-ptrs.h"
23 #include "hphp/util/compilation-flags.h"
26 #include <type_traits>
30 namespace tv_val_detail
{
32 * These structs are used to add dummy() and is_dummy() functions to tv_rval
40 * The canonical non-null "missing" rval. Only valid for tv_rval (is_const ==
41 * true). These are actually defined in tv_val_detail::with_dummy; see above.
43 * Some users of tv_rval prefer to use a dummy rval-to-Uninit to represent a
44 * missing element, instead of a nullptr rval, so that tv() is always valid.
45 * These functions provide and test for such a value.
47 * static tv_val dummy();
48 * bool is_dummy() const;
50 INLINE_FLATTEN
static T
dummy() { return T
{ &immutable_uninit_base
}; }
51 INLINE_FLATTEN
bool is_dummy() const {
52 return static_cast<const T
&>(*this) == dummy();
57 INLINE_FLATTEN T
* get_ptr(T
* ptr
) {
61 template<typename T
, typename Tag
>
62 INLINE_FLATTEN T
* get_ptr(CompactTaggedPtr
<T
, Tag
> ptr
) {
68 * NOTE: You probably do not want to use tv_val directly. You should instead
69 * use tv_lval or tv_rval, for mutable or constant pointees, respectively.
71 * tv_val is a thin wrapper around the concept of a pointer to a
72 * TypedValue. For now, it contains a normal TypedValue*, but in the future we
73 * will explore different memory layout options that will likely require
74 * passing around separate pointers to the value and type of a TypedValue. The
75 * goal of tv_val is to replace TypedValue* in as much code as possible, so
76 * these alternate layout options can be explored with minimal disruption.
78 * Like all pointers, tv_val is nullable/optional. The presence of a value can
79 * be detected via is_set(), explicit cast to a bool, or comparison with
82 * If tag_t is non-void, CompactTaggedPtr will be used internally to store a
83 * tag. This has no space overhead, but has a slight penalty at runtime.
85 template<bool is_const
, typename tag_t
= void>
86 struct tv_val
: std::conditional
<is_const
,
87 tv_val_detail::with_dummy
<tv_val
<true>>,
88 tv_val_detail::empty
>::type
{
90 template<typename T
> using maybe_const_t
=
91 typename
std::conditional
<is_const
, const T
, T
>::type
;
92 template<typename T
, typename R
= T
> using with_tag_t
=
93 typename
std::enable_if
<!std::is_same
<T
, void>::value
, R
>::type
;
96 using value_t
= maybe_const_t
<Value
>;
97 using type_t
= maybe_const_t
<DataType
>;
98 using tv_t
= maybe_const_t
<TypedValue
>;
101 * These values expose details about the internal representation of a tv_val,
102 * and should only be inspected while generating code that works with
105 * If you do change these, you must also update the return registers used in
106 * runtime/base/hash-table-*.S.
108 static constexpr int type_idx
= wide_tv_val
? 0 : -1;
109 static constexpr int val_idx
= wide_tv_val
? 1 : 0;
111 INLINE_FLATTEN
tv_val();
112 /* implicit */ INLINE_FLATTEN
tv_val(std::nullptr_t
);
113 /* implicit */ INLINE_FLATTEN
tv_val(tv_t
* lval
);
114 INLINE_FLATTEN
tv_val(type_t
* type
, value_t
* val
);
117 * Construct from a tv_val without a tag and a tag.
119 template<typename Tag
= tag_t
>
120 INLINE_FLATTEN
tv_val(tv_val
<is_const
> lval
, with_tag_t
<Tag
> t
);
122 INLINE_FLATTEN
bool operator==(tv_val other
) const;
123 INLINE_FLATTEN
bool operator!=(tv_val other
) const;
126 * Whether this tv_val is set.
128 INLINE_FLATTEN
bool is_set() const;
129 INLINE_FLATTEN
explicit operator bool() const;
130 INLINE_FLATTEN
bool operator==(std::nullptr_t
) const;
131 INLINE_FLATTEN
bool operator!=(std::nullptr_t
) const;
134 * Implicit cast to tv_rval.
136 /* implicit */ INLINE_FLATTEN
operator tv_val
<true>() const;
139 * Explicit cast to tv_lval.
141 * This is the moral equivalent of:
142 * const_cast<TypedValue*>(const TypedValue*)
144 INLINE_FLATTEN tv_val
<false> as_lval() const;
147 * References to the value and type.
149 * @requires: is_set()
151 INLINE_FLATTEN value_t
& val() const;
152 INLINE_FLATTEN type_t
& type() const;
155 * Get a copy of the referenced value and type as a TypedValue.
157 * @requires: is_set()
159 INLINE_FLATTEN TypedValue
tv() const;
160 INLINE_FLATTEN TypedValue
operator*() const;
162 template<typename Tag
= tag_t
>
163 INLINE_FLATTEN with_tag_t
<Tag
> tag() const;
165 template<typename Tag
= tag_t
>
166 INLINE_FLATTEN with_tag_t
<Tag
, tv_val
<is_const
>> drop_tag() const;
169 if (isRefcountedType(type())) scanner
.scan(val().pcnt
);
173 template<bool, typename
> friend struct tv_val
;
176 using maybe_tagged_t
= std::conditional_t
<
177 std::is_same
<tag_t
, void>::value
, T
*, CompactTaggedPtr
<T
, tag_t
>
181 * Default storage type: a single TypedValue*.
184 INLINE_FLATTEN
storage()
187 INLINE_FLATTEN
storage(type_t
* type
, value_t
* val
)
188 : m_tv
{reinterpret_cast<tv_t
*>(val
)}
190 assertx(val
== nullptr || &m_tv
->m_type
== type
);
193 template<typename Tag
= tag_t
>
194 INLINE_FLATTEN
storage(type_t
* type
, value_t
* val
, with_tag_t
<Tag
> tag
)
195 : m_tv
{tag
, reinterpret_cast<tv_t
*>(val
)}
197 assertx(val
== nullptr || &m_tv
->m_type
== type
);
200 INLINE_FLATTEN
bool operator==(const storage
& o
) const {
201 return m_tv
== o
.m_tv
;
204 INLINE_FLATTEN
bool operator!=(const storage
& o
) const {
205 return m_tv
!= o
.m_tv
;
208 INLINE_FLATTEN type_t
* type() const { return &m_tv
->m_type
; }
209 INLINE_FLATTEN value_t
* val() const { return &m_tv
->m_data
; }
210 INLINE_FLATTEN
bool is_set() const { return static_cast<bool>(m_tv
); }
212 template<typename Tag
= tag_t
>
213 INLINE_FLATTEN with_tag_t
<Tag
> tag() const { return m_tv
.tag(); }
216 maybe_tagged_t
<tv_t
> m_tv
;
220 * Wide storage type: separate pointers for the type and the value. m_type is
221 * only meangingful is m_val != nullptr.
223 struct wide_storage
{
224 INLINE_FLATTEN
wide_storage()
225 : m_type
{}, m_val
{} {}
227 INLINE_FLATTEN
wide_storage(type_t
* type
, value_t
* val
)
231 assertx((type
&& val
) || val
== nullptr);
234 template<typename Tag
= tag_t
>
235 INLINE_FLATTEN
wide_storage(type_t
* type
, value_t
* val
, with_tag_t
<Tag
> tag
)
239 assertx((type
&& val
) || val
== nullptr);
242 INLINE_FLATTEN
bool operator==(const wide_storage
& o
) const {
243 return m_val
== o
.m_val
&& (m_type
== o
.m_type
|| m_val
== nullptr);
246 INLINE_FLATTEN
bool operator!=(const wide_storage
& o
) const {
247 return !operator==(o
);
250 INLINE_FLATTEN type_t
* type() const {
251 return tv_val_detail::get_ptr(m_type
);
253 INLINE_FLATTEN value_t
* val() const { return m_val
; }
254 INLINE_FLATTEN
bool is_set() const { return m_val
; }
256 template<typename Tag
= tag_t
>
257 INLINE_FLATTEN with_tag_t
<Tag
> tag() const { return m_type
.tag(); }
260 maybe_tagged_t
<type_t
> m_type
;
264 using storage_t
= std::conditional_t
<wide_tv_val
, wide_storage
, storage
>;
269 * TV-lval API for tv_val.
271 template<bool is_const
>
272 INLINE_FLATTEN
auto& type(const tv_val
<is_const
>& val
) { return val
.type(); }
273 template<bool is_const
>
274 INLINE_FLATTEN
auto& val(const tv_val
<is_const
>& val
) { return val
.val(); }
275 template<bool is_const
>
276 INLINE_FLATTEN TypedValue
as_tv(const tv_val
<is_const
>& val
) {
280 ///////////////////////////////////////////////////////////////////////////////
282 using tv_lval
= tv_val
<false>;
283 using tv_rval
= tv_val
<true>;
285 ///////////////////////////////////////////////////////////////////////////////
289 /* representation of a tv_val_offset when wide mode is on */
290 struct tv_val_offset_wide
{
291 tv_val_offset_wide(ptrdiff_t tv_offset
)
292 : type_offset(tv_offset
+ offsetof(TypedValue
, m_type
))
293 , data_offset(tv_offset
+ offsetof(TypedValue
, m_data
)) {}
294 tv_val_offset_wide(ptrdiff_t type_offset
, ptrdiff_t data_offset
)
295 : type_offset(type_offset
)
296 , data_offset(data_offset
) {}
298 ptrdiff_t typeOffset() const { return type_offset
; }
299 ptrdiff_t dataOffset() const { return data_offset
; }
301 tv_val_offset_wide
shift(ptrdiff_t off
) const {
308 /* extract a tv_val from a given base address */
309 tv_lval
apply(char* base
) const {
311 reinterpret_cast<DataType
*>(base
+ typeOffset()),
312 reinterpret_cast<Value
*>(base
+ dataOffset())
316 tv_rval
apply(const char* base
) const {
318 reinterpret_cast<const DataType
*>(base
+ typeOffset()),
319 reinterpret_cast<const Value
*>(base
+ dataOffset())
323 ptrdiff_t type_offset
;
324 ptrdiff_t data_offset
;
327 /* representation of a tv_val_offset when wide mode is off */
328 struct tv_val_offset_nonwide
{
329 tv_val_offset_nonwide(ptrdiff_t offset
) : offset(offset
) {}
330 tv_val_offset_nonwide(ptrdiff_t type_offset
, ptrdiff_t data_offset
)
331 : offset(data_offset
) {
332 static_assert(offsetof(TypedValue
, m_data
) == 0, "");
333 assertx(type_offset
== data_offset
+ offsetof(TypedValue
, m_type
));
336 ptrdiff_t typeOffset() const { return offset
+ offsetof(TypedValue
, m_type
); }
337 ptrdiff_t dataOffset() const { return offset
+ offsetof(TypedValue
, m_data
); }
339 /* extract a tv_val from a given base address */
340 tv_lval
apply(char* base
) {
341 return reinterpret_cast<TypedValue
*>(base
+ dataOffset());
344 tv_rval
apply(const char* base
) {
345 return reinterpret_cast<const TypedValue
*>(base
+ dataOffset());
348 tv_val_offset_nonwide
shift(ptrdiff_t off
) const {
349 return {offset
+ off
};
355 } // namespace detail
357 using tv_val_offset
= std::conditional
<wide_tv_val
,
358 detail::tv_val_offset_wide
,
359 detail::tv_val_offset_nonwide
>::type
;
363 #include "hphp/runtime/base/tv-val-inl.h"