Add support for HHBC ops with 5 immediates
[hiphop-php.git] / hphp / runtime / base / apc-array.h
blobb0f4f604dc76c1dfd920501f5328f63de4ed27bd
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 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_APC_ARRAY_H_
18 #define incl_HPHP_APC_ARRAY_H_
20 #include "hphp/runtime/base/apc-handle-defs.h"
21 #include "hphp/runtime/base/mixed-array.h"
22 #include "hphp/runtime/base/packed-array.h"
23 #include "hphp/runtime/base/set-array.h"
24 #include "hphp/util/atomic.h"
25 #include "hphp/util/lock.h"
26 #include "hphp/util/hash.h"
28 namespace HPHP {
30 //////////////////////////////////////////////////////////////////////
32 struct APCLocalArray;
34 //////////////////////////////////////////////////////////////////////
36 struct APCArray {
37 static APCHandle::Pair MakeSharedArray(ArrayData* data,
38 APCHandleLevel level,
39 bool unserializeObj);
40 static APCHandle::Pair MakeSharedVec(ArrayData* data,
41 APCHandleLevel level,
42 bool unserializeObj);
43 static APCHandle::Pair MakeSharedDict(ArrayData* data,
44 APCHandleLevel level,
45 bool unserializeObj);
46 static APCHandle::Pair MakeSharedKeyset(ArrayData* data,
47 APCHandleLevel level,
48 bool unserializeObj);
50 static APCHandle* MakeUncountedArray(ArrayData* array,
51 PointerMap* m = nullptr);
52 static APCHandle* MakeUncountedVec(ArrayData* vec,
53 PointerMap* m = nullptr);
54 static APCHandle* MakeUncountedDict(ArrayData* dict,
55 PointerMap* m = nullptr);
56 static APCHandle* MakeUncountedKeyset(ArrayData* dict);
58 static APCHandle::Pair MakeSharedEmptyArray();
59 static void Delete(APCHandle* handle);
61 static APCArray* fromHandle(APCHandle* handle) {
62 assertx(handle->checkInvariants());
63 assertx(handle->kind() == APCKind::SharedArray ||
64 handle->kind() == APCKind::SharedPackedArray ||
65 handle->kind() == APCKind::SharedVArray ||
66 handle->kind() == APCKind::SharedDArray ||
67 handle->kind() == APCKind::SharedVec ||
68 handle->kind() == APCKind::SharedDict ||
69 handle->kind() == APCKind::SharedKeyset);
70 static_assert(offsetof(APCArray, m_handle) == 0, "");
71 return reinterpret_cast<APCArray*>(handle);
74 static const APCArray* fromHandle(const APCHandle* handle) {
75 assertx(handle->checkInvariants());
76 assertx(handle->kind() == APCKind::SharedArray ||
77 handle->kind() == APCKind::SharedPackedArray ||
78 handle->kind() == APCKind::SharedVArray ||
79 handle->kind() == APCKind::SharedDArray ||
80 handle->kind() == APCKind::SharedVec ||
81 handle->kind() == APCKind::SharedDict ||
82 handle->kind() == APCKind::SharedKeyset);
83 static_assert(offsetof(APCArray, m_handle) == 0, "");
84 return reinterpret_cast<const APCArray*>(handle);
87 // Used when creating/destroying a local wrapper (see APCLocalArray).
88 void reference() const { m_handle.referenceNonRoot(); }
89 void unreference() const { m_handle.unreferenceNonRoot(); }
91 ArrayData* toLocalVArray() const {
92 assertx(!RuntimeOption::EvalHackArrDVArrs);
93 return PackedArray::MakeVArrayFromAPC(this);
95 ArrayData* toLocalDArray() const {
96 assertx(!RuntimeOption::EvalHackArrDVArrs);
97 return MixedArray::MakeDArrayFromAPC(this);
99 ArrayData* toLocalVec() const { return PackedArray::MakeVecFromAPC(this); }
100 ArrayData* toLocalDict() const { return MixedArray::MakeDictFromAPC(this); }
101 ArrayData* toLocalKeyset() const { return SetArray::MakeSetFromAPC(this); }
104 // Array API
107 size_t size() const {
108 return isPacked() ? m_size : m.m_num;
111 Variant getKey(ssize_t pos) const {
112 if (isPacked()) {
113 assertx(static_cast<size_t>(pos) < m_size);
114 return pos;
116 assertx(static_cast<size_t>(pos) < m.m_num);
117 return buckets()[pos].key->toLocal();
120 APCHandle* getValue(ssize_t pos) const {
121 if (isPacked()) {
122 assertx(static_cast<size_t>(pos) < m_size);
123 return vals()[pos];
125 assertx(static_cast<size_t>(pos) < m.m_num);
126 return buckets()[pos].val;
129 ssize_t getIndex(const StringData* key) const {
130 return isPacked() ? -1 : indexOf(key);
133 ssize_t getIndex(int64_t key) const {
134 if (isPacked()) {
135 return (static_cast<uint64_t>(key) >= m_size) ? -1 : key;
137 return indexOf(key);
140 bool isPacked() const {
141 auto const k = m_handle.kind();
142 return
143 k == APCKind::SharedPackedArray ||
144 k == APCKind::SharedVArray ||
145 k == APCKind::SharedVec ||
146 k == APCKind::SharedKeyset;
149 bool isHashed() const {
150 auto const k = m_handle.kind();
151 return
152 k == APCKind::SharedArray ||
153 k == APCKind::SharedDArray ||
154 k == APCKind::SharedDict;
157 bool isPHPArray() const {
158 auto const k = m_handle.kind();
159 return
160 k == APCKind::SharedArray ||
161 k == APCKind::SharedPackedArray ||
162 k == APCKind::SharedVArray ||
163 k == APCKind::SharedDArray;
166 bool isVArray() const {
167 return m_handle.kind() == APCKind::SharedVArray;
170 bool isDArray() const {
171 return m_handle.kind() == APCKind::SharedDArray;
174 bool isVec() const {
175 return m_handle.kind() == APCKind::SharedVec;
178 bool isDict() const {
179 return m_handle.kind() == APCKind::SharedDict;
182 bool isKeyset() const {
183 return m_handle.kind() == APCKind::SharedKeyset;
186 private:
187 struct Bucket {
188 /** index of the next bucket, or -1 if the end of a chain */
189 int next;
190 /** the value of this bucket */
191 APCHandle *key;
192 APCHandle *val;
195 private:
196 enum class PackedCtor {};
197 APCArray(PackedCtor, APCKind kind, size_t size)
198 : m_handle(kind, kInvalidDataType), m_size(size) {
199 assertx(isPacked());
202 enum class HashedCtor {};
203 APCArray(HashedCtor, APCKind kind, unsigned int cap) : m_handle(kind) {
204 assertx(isHashed());
205 m.m_capacity_mask = cap - 1;
206 m.m_num = 0;
208 ~APCArray();
210 APCArray(const APCArray&) = delete;
211 APCArray& operator=(const APCArray&) = delete;
213 private:
214 template <typename A, typename B, typename C>
215 static APCHandle::Pair MakeSharedImpl(ArrayData*, APCHandleLevel, A, B, C);
217 static APCHandle::Pair MakeHash(ArrayData* data, APCKind kind,
218 bool unserializeObj);
219 static APCHandle::Pair MakePacked(ArrayData* data, APCKind kind,
220 bool unserializeObj);
222 private:
223 friend size_t getMemSize(const APCArray*);
225 void add(APCHandle* key, APCHandle* val);
226 ssize_t indexOf(const StringData* key) const;
227 ssize_t indexOf(int64_t key) const;
229 /* index of the beginning of each hash chain */
230 int* hash() const { return (int*)(this + 1); }
231 /* buckets, stored in index order */
232 Bucket* buckets() const { return (Bucket*)(hash() + m.m_capacity_mask + 1); }
233 /* start of the data for packed array */
234 APCHandle** vals() const { return (APCHandle**)(this + 1); }
236 APCHandle* getHandle() {
237 return &m_handle;
239 const APCHandle* getHandle() const {
240 return &m_handle;
243 private:
244 APCHandle m_handle;
245 union {
246 // for map style arrays
247 struct {
248 unsigned int m_capacity_mask;
249 unsigned int m_num;
250 } m;
251 // for packed arrays
252 size_t m_size;
256 //////////////////////////////////////////////////////////////////////
260 #endif