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-collection.h"
18 #include "hphp/runtime/base/apc-object.h"
19 #include "hphp/runtime/base/apc-array.h"
20 #include "hphp/runtime/base/apc-stats.h"
21 #include "hphp/runtime/base/object-data.h"
22 #include "hphp/runtime/base/type-object.h"
23 #include "hphp/runtime/ext/apc/ext_apc.h"
24 #include "hphp/runtime/base/collections.h"
25 #include "hphp/runtime/ext/collections/ext_collections-map.h"
26 #include "hphp/runtime/ext/collections/ext_collections-set.h"
27 #include "hphp/runtime/ext/collections/ext_collections-vector.h"
28 #include "hphp/runtime/base/data-walker.h"
34 //////////////////////////////////////////////////////////////////////
36 void fillMap(BaseMap
* map
, const APCArray
* ar
) {
37 for (auto i
= uint32_t{0}; i
< ar
->size(); ++i
) {
38 map
->set(*ar
->getKey(i
).asTypedValue(),
39 *ar
->getValue(i
)->toLocal().asTypedValue());
44 void fillCollection(T
* coll
, const APCArray
* ar
) {
45 for (auto i
= uint32_t{0}; i
< ar
->size(); ++i
) {
46 coll
->add(*ar
->getValue(i
)->toLocal().asTypedValue());
50 // Deserializing an array could give back a different ArrayKind than we need,
51 // so we have to go with the slow case of calling a collection constructor.
53 Object
createFromSerialized(CollectionType colType
, APCHandle
* handle
) {
54 auto const col
= Object::attach(collections::alloc(colType
));
55 auto const arr
= handle
->toLocal();
57 case CollectionType::ImmVector
:
58 case CollectionType::Vector
:
59 static_cast<BaseVector
*>(col
.get())->init(arr
);
61 case CollectionType::ImmSet
:
62 case CollectionType::Set
:
63 static_cast<BaseSet
*>(col
.get())->init(arr
);
65 case CollectionType::ImmMap
:
66 case CollectionType::Map
:
67 static_cast<BaseMap
*>(col
.get())->init(arr
);
69 case CollectionType::Pair
:
76 //////////////////////////////////////////////////////////////////////
80 APCHandle::Pair
APCCollection::Make(const ObjectData
* obj
,
82 bool unserializeObj
) {
84 return APCString::MakeSerializedObject(
85 apc_serialize(Variant(const_cast<ObjectData
*>(obj
)))
89 auto const array
= collections::asArray(obj
);
90 if (!array
) return bail();
93 * Create an uncounted array if we can.
95 * If this collection is an OuterHandle, then we need to do a full check on
96 * this array for things like circularity. If we're an InnerHandle, someone
97 * already checked that, but we want to check for whether it's uncounted to
98 * use a better representation. For the OuterHandle case, we just delegate
99 * to APCArray below (which will do the full DataWalker pass).
101 if (level
== APCHandleLevel::Inner
&& apcExtension::UseUncounted
&&
103 DataWalker
walker(DataWalker::LookupFeature::HasObjectOrResource
);
104 auto const features
= walker
.traverseData(const_cast<ArrayData
*>(array
));
105 assert(!features
.isCircular
);
106 if (!features
.hasObjectOrResource
) {
107 auto const makeUncounted
= [&] () {
108 if (isVectorCollection(obj
->collectionType())) {
109 return APCArray::MakeUncountedVec(const_cast<ArrayData
*>(array
));
111 return APCArray::MakeUncountedDict(const_cast<ArrayData
*>(array
));
114 { makeUncounted(), getMemSize(array
) + sizeof(APCTypedValue
) },
115 obj
->collectionType()
120 auto const makeShared
= [&] () {
121 if (isVectorCollection(obj
->collectionType())) {
122 return APCArray::MakeSharedVec(const_cast<ArrayData
*>(array
),
126 return APCArray::MakeSharedDict(const_cast<ArrayData
*>(array
),
130 return WrapArray(makeShared(), obj
->collectionType());
133 void APCCollection::Delete(APCHandle
* h
) {
134 assert(offsetof(APCCollection
, m_handle
) == 0);
135 delete reinterpret_cast<APCCollection
*>(h
);
138 APCCollection::APCCollection()
139 : m_handle(APCKind::SharedCollection
)
142 APCCollection::~APCCollection() {
143 // Zero for size is correct, because when this APCCollection was unreferenced
144 // it already included the size of the inner handle.
145 m_arrayHandle
->unreferenceRoot(0);
148 APCHandle::Pair
APCCollection::WrapArray(APCHandle::Pair inner
,
149 CollectionType colType
) {
150 auto const col
= new APCCollection
;
151 col
->m_arrayHandle
= inner
.handle
;
152 col
->m_colType
= colType
;
153 return { &col
->m_handle
, inner
.size
+ sizeof(APCCollection
) };
156 Object
APCCollection::createObject() const {
157 if (m_arrayHandle
->isTypedValue()) {
158 Variant
local(m_arrayHandle
->toLocal());
159 assert(local
.isArray());
160 return Object::attach(
161 collections::alloc(m_colType
, local
.getArrayData())
165 if (UNLIKELY(m_arrayHandle
->kind() == APCKind::SerializedVec
||
166 m_arrayHandle
->kind() == APCKind::SerializedDict
)) {
167 return createFromSerialized(m_colType
, m_arrayHandle
);
170 // We had a counted inner array---we need to do an O(N) copy to get the
171 // collection into the request local heap.
172 auto const apcArr
= APCArray::fromHandle(m_arrayHandle
);
173 auto const col
= Object::attach(collections::alloc(m_colType
));
175 case CollectionType::ImmVector
:
176 case CollectionType::Vector
:
177 fillCollection(static_cast<BaseVector
*>(col
.get()), apcArr
);
179 case CollectionType::ImmSet
:
180 case CollectionType::Set
:
181 fillCollection(static_cast<BaseSet
*>(col
.get()), apcArr
);
183 case CollectionType::ImmMap
:
184 case CollectionType::Map
:
185 fillMap(static_cast<BaseMap
*>(col
.get()), apcArr
);
187 case CollectionType::Pair
:
194 //////////////////////////////////////////////////////////////////////