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 #ifndef incl_HPHP_REQ_ROOT_H_
18 #define incl_HPHP_REQ_ROOT_H_
20 #include "hphp/runtime/base/typed-value.h"
21 #include "hphp/runtime/base/runtime-option.h"
24 namespace HPHP
{ namespace req
{
27 * An explicitly-tracked root, registered on construction and de-registered
28 * on destruction. Subclasses of this implement tyindex() and detach() methods
29 * so instances can be scanned as needed.
30 * Warning: this extra tracking is expensive, and only necessary when
31 * creating and destroying heap pointers in areas not already known
32 * as roots (thread locals, stack, rds, ExecutionContext, etc).
35 static constexpr uint32_t INVALID
= ~0;
37 root_handle(uint16_t size
, type_scan::Index tyindex
)
38 : m_id(addRootHandle()), m_size(size
), m_tyindex(tyindex
)
41 // move construction takes over the old handle's id.
42 root_handle(root_handle
&& h
) noexcept
43 : m_id(h
.m_id
!= INVALID
? stealRootHandle(&h
) : INVALID
)
45 , m_tyindex(h
.m_tyindex
)
48 // move-assignment poaches the old handle's id if necessary.
49 root_handle
& operator=(root_handle
&& h
) {
50 if (m_id
== INVALID
) m_id
= stealRootHandle(&h
);
54 // root_handles must all be unique; remove copy-construct and copy-assign
55 root_handle(const root_handle
&) = delete;
56 root_handle
& operator=(const root_handle
&) = delete;
58 virtual ~root_handle() {
59 if (m_id
!= INVALID
) delRootHandle();
66 virtual void scan(type_scan::Scanner
&) const = 0;
67 virtual void detach() = 0;
69 template<class Fn
> void iterate(Fn fn
) const {
70 fn(this, m_size
, m_tyindex
);
73 uint32_t addRootHandle();
74 uint32_t stealRootHandle(root_handle
*);
79 const uint16_t m_size
;
80 const type_scan::Index m_tyindex
;
83 // e.g. req::root<Array>, req::root<Variant>
85 struct root
: T
, root_handle
{
87 root_handle(sizeof(root
<T
>), type_scan::getIndexForScan
<root
<T
>>())
89 static_assert(sizeof(root
<T
>) <= 0xffff, "");
93 root(const root
<T
>& r
)
94 : T(static_cast<const T
&>(r
)),
95 root_handle(sizeof(root
<T
>), type_scan::getIndexForScan
<root
<T
>>())
97 static_assert(sizeof(root
<T
>) <= 0xffff, "");
100 // conversion constructor
101 template<class S
> /* implicit */ root(const S
& s
)
103 root_handle(sizeof(root
<T
>), type_scan::getIndexForScan
<root
<T
>>())
105 static_assert(sizeof(root
<T
>) <= 0xffff, "");
109 root
<T
>& operator=(const root
<T
>& r
) {
110 T::operator=(static_cast<const T
&>(r
));
114 // converting assign from any type only deals with T
115 template<class S
> root
<T
>& operator=(const S
& s
) {
121 root(root
<T
>&& r
) noexcept
122 : T(std::move(r
)), root_handle(std::move(r
))
124 /* implicit */ root(T
&& t
) noexcept
126 root_handle(sizeof(root
<T
>), type_scan::getIndexForScan
<root
<T
>>())
130 root
<T
>& operator=(root
<T
>&& r
) {
131 T::operator=(std::move(static_cast<T
&&>(r
)));
132 root_handle::operator=(std::move(r
));
135 root
<T
>& operator=(T
&& t
) {
136 T::operator=(std::move(t
));
140 // implement root_handle
141 void scan(type_scan::Scanner
&) const override
;
142 void detach() override
;
145 template<> void root
<TypedValue
>::scan(type_scan::Scanner
&) const;
146 template<> void root
<TypedValue
>::detach();