Remove support for parsing the `elseif` keyword
[hiphop-php.git] / hphp / runtime / base / apc-typed-value.cpp
blob91b1badac902b833b422f55ff5119ba0c20cecb1
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
22 namespace HPHP {
24 //////////////////////////////////////////////////////////////////////
26 struct HazardPointer {
27 StringData* raw;
28 TYPE_SCAN_IGNORE_ALL;
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);
51 ad = result.ad;
53 // If we made an APCBespoke, it'll always be part of a joint allocation.
54 if (result.tv) {
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);
83 return value;
86 APCTypedValue* APCTypedValue::tvNull() {
87 static APCTypedValue* value = new APCTypedValue(KindOfNull);
88 return value;
91 APCTypedValue* APCTypedValue::tvTrue() {
92 static auto value = new APCTypedValue(APCTypedValue::Bool{}, true);
93 return value;
96 APCTypedValue* APCTypedValue::tvFalse() {
97 static auto value = new APCTypedValue(APCTypedValue::Bool{}, false);
98 return value;
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;
106 case APCKind::Bool:
107 case APCKind::Int:
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());
122 break;
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());
130 break;
133 case APCKind::FuncEntity:
134 case APCKind::ClassEntity:
135 case APCKind::ClsMeth:
136 case APCKind::RFunc:
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:
149 assertx(false);
150 break;
152 return true;
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 "
162 "destroying it");
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)) {
169 delete this;
171 return;
174 case APCKind::UncountedBespoke:
175 freeAPCBespoke(this);
176 return;
178 case APCKind::UncountedString:
179 DecRefUncountedString(m_data.str);
180 delete this;
181 return;
183 default:
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());
200 TypedValue tv;
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);
209 } else {
210 tv.m_data.num = m_data.num;
212 return tv;
215 //////////////////////////////////////////////////////////////////////