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 +----------------------------------------------------------------------+
16 #include "hphp/runtime/base/apc-typed-value.h"
18 #include "hphp/runtime/base/apc-bespoke.h"
19 #include "hphp/runtime/base/tv-uncounted.h"
20 #include "hphp/runtime/ext/apc/ext_apc.h"
24 //////////////////////////////////////////////////////////////////////
26 struct HazardPointer
{
31 RDS_LOCAL(std::vector
<HazardPointer
>, s_hazard_pointers
);
33 void APCTypedValue::FreeHazardPointers() {
34 if (!UseHazardPointers()) return;
35 for (auto const hp
: *s_hazard_pointers
) {
36 DecRefUncountedString(hp
.raw
);
38 s_hazard_pointers
->clear();
41 bool APCTypedValue::UseHazardPointers() {
42 return !use_lowptr
&& !apcExtension::UseUncounted
;
45 //////////////////////////////////////////////////////////////////////
47 APCTypedValue
* APCTypedValue::ForArray(ArrayData
* ad
) {
48 assertx(!ad
->isRefCounted());
49 auto const dt
= ad
->toPersistentDataType();
50 auto const result
= initAPCBespoke(ad
);
53 // If we made an APCBespoke, it'll always be part of a joint allocation.
55 auto const kind
= ad
->isStatic() ? APCKind::StaticBespoke
56 : APCKind::UncountedBespoke
;
57 return new (result
.tv
) APCTypedValue(ad
, kind
, dt
);
60 // We didn't make an APCBespoke. Just use a regular persistent array.
61 auto const kind
= ad
->isStatic() ? APCKind::StaticArray
62 : APCKind::UncountedArray
;
64 // Check if the "co-allocate array and APCTypedValue" optimization hit.
65 // It hit if we a) made a new uncounted array and b) its flag is set.
66 if (ad
->uncountedCowCheck() || !ad
->hasApcTv()) {
67 return new APCTypedValue(ad
, kind
, dt
);
70 auto const mem
= reinterpret_cast<APCTypedValue
*>(ad
) - 1;
71 return new (mem
) APCTypedValue(ad
, kind
, dt
);
74 APCTypedValue::APCTypedValue(ArrayData
* ad
, APCKind kind
, DataType dt
)
75 : m_handle(kind
, dt
) {
76 assertx(!ad
->isRefCounted());
77 m_data
.arr
.store(ad
, std::memory_order_release
);
78 assertx(checkInvariants());
81 APCTypedValue
* APCTypedValue::tvUninit() {
82 static APCTypedValue
* value
= new APCTypedValue(KindOfUninit
);
86 APCTypedValue
* APCTypedValue::tvNull() {
87 static APCTypedValue
* value
= new APCTypedValue(KindOfNull
);
91 APCTypedValue
* APCTypedValue::tvTrue() {
92 static auto value
= new APCTypedValue(APCTypedValue::Bool
{}, true);
96 APCTypedValue
* APCTypedValue::tvFalse() {
97 static auto value
= new APCTypedValue(APCTypedValue::Bool
{}, false);
101 bool APCTypedValue::checkInvariants() const {
102 assertx(m_handle
.checkInvariants());
103 switch (m_handle
.kind()) {
104 case APCKind::Uninit
:
105 case APCKind::Null
: assertx(m_data
.num
== 0); break;
108 case APCKind::Double
: break;
109 case APCKind::PersistentFunc
: assertx(m_data
.func
->isPersistent()); break;
110 case APCKind::PersistentClass
: assertx(m_data
.cls
->isPersistent()); break;
111 case APCKind::PersistentClsMeth
:
112 assertx(m_data
.pclsmeth
->getCls()->isPersistent()); break;
113 case APCKind::StaticString
: assertx(m_data
.str
->isStatic()); break;
114 case APCKind::UncountedString
: assertx(m_data
.str
->isUncounted()); break;
115 case APCKind::LazyClass
: assertx(m_data
.str
->isStatic()); break;
117 case APCKind::StaticArray
:
118 case APCKind::StaticBespoke
: {
119 DEBUG_ONLY
auto const ad
= m_data
.arr
.load(std::memory_order_acquire
);
120 assertx(ad
->isStatic());
121 assertx(ad
->toPersistentDataType() == m_handle
.type());
125 case APCKind::UncountedArray
:
126 case APCKind::UncountedBespoke
: {
127 DEBUG_ONLY
auto const ad
= m_data
.arr
.load(std::memory_order_acquire
);
128 assertx(ad
->isUncounted());
129 assertx(ad
->toPersistentDataType() == m_handle
.type());
133 case APCKind::FuncEntity
:
134 case APCKind::ClassEntity
:
135 case APCKind::ClsMeth
:
137 case APCKind::RClsMeth
:
138 case APCKind::SharedObject
:
139 case APCKind::SharedCollection
:
140 case APCKind::SharedVec
:
141 case APCKind::SharedLegacyVec
:
142 case APCKind::SharedDict
:
143 case APCKind::SharedLegacyDict
:
144 case APCKind::SharedKeyset
:
145 case APCKind::SerializedObject
:
146 case APCKind::SerializedVec
:
147 case APCKind::SerializedDict
:
148 case APCKind::SerializedKeyset
:
155 //////////////////////////////////////////////////////////////////////
157 void APCTypedValue::deleteUncounted() {
158 assertx(m_handle
.isUncounted());
159 static_assert(std::is_trivially_destructible
<APCTypedValue
>::value
,
160 "APCTypedValue must be trivially destructible - "
161 "*Array::ReleaseUncounted() frees the memory without "
164 switch (m_handle
.kind()) {
165 case APCKind::UncountedArray
: {
166 auto const ad
= m_data
.arr
.load(std::memory_order_acquire
);
167 DecRefUncountedArray(ad
);
168 if (ad
!= static_cast<void*>(this + 1)) {
174 case APCKind::UncountedBespoke
:
175 freeAPCBespoke(this);
178 case APCKind::UncountedString
:
179 DecRefUncountedString(m_data
.str
);
184 always_assert(false);
188 ArrayData
* APCTypedValue::getArrayData() const {
189 assertx(checkInvariants());
190 return m_data
.arr
.load(std::memory_order_acquire
);
193 void APCTypedValue::setArrayData(ArrayData
* ad
) {
194 m_data
.arr
.store(ad
, std::memory_order_release
);
195 assertx(checkInvariants());
198 TypedValue
APCTypedValue::toTypedValue() const {
199 assertx(m_handle
.isTypedValue());
201 tv
.m_type
= m_handle
.type();
202 auto const kind
= m_handle
.kind();
203 if (UseHazardPointers() && kind
== APCKind::UncountedString
) {
204 s_hazard_pointers
->push_back({m_data
.str
});
205 m_data
.str
->uncountedIncRef();
206 tv
.m_data
.pstr
= m_data
.str
;
207 } else if (kind
== APCKind::UncountedBespoke
) {
208 tv
.m_data
.parr
= readAPCBespoke(this);
210 tv
.m_data
.num
= m_data
.num
;
215 //////////////////////////////////////////////////////////////////////