|
15 | 15 | */
|
16 | 16 |
|
17 | 17 | #include "hphp/runtime/base/apc-array.h"
|
18 |
| -#include "hphp/runtime/base/apc-variant.h" |
| 18 | +#include "hphp/runtime/base/apc-handle.h" |
| 19 | +#include "hphp/runtime/base/apc-typed-value.h" |
| 20 | +#include "hphp/runtime/base/apc-string.h" |
| 21 | +#include "hphp/runtime/base/apc-local-array.h" |
19 | 22 | #include "hphp/runtime/base/array-iterator.h"
|
| 23 | +#include "hphp/runtime/ext/ext_apc.h" |
20 | 24 |
|
21 | 25 | namespace HPHP {
|
22 | 26 |
|
23 | 27 | ///////////////////////////////////////////////////////////////////////////////
|
24 | 28 |
|
25 |
| -APCArray* APCArray::Create(ArrayData* arr, |
26 |
| - bool unserializeObj, |
27 |
| - bool &shouldCache) { |
28 |
| - int num = arr->size(); |
29 |
| - int cap = num > 2 ? Util::roundUpToPowerOfTwo(num) : 2; |
| 29 | +APCHandle* APCArray::MakeShared(ArrayData* arr, |
| 30 | + bool inner, |
| 31 | + bool unserializeObj) { |
| 32 | + if (!inner) { |
| 33 | + // only need to call hasInternalReference() on the toplevel array |
| 34 | + PointerSet seen; |
| 35 | + if (arr->hasInternalReference(seen)) { |
| 36 | + String s = apc_serialize(arr); |
| 37 | + APCHandle* handle = APCString::MakeShared(KindOfArray, s.get()); |
| 38 | + handle->setSerializedArray(); |
| 39 | + handle->mustCache(); |
| 40 | + return handle; |
| 41 | + } |
| 42 | + } |
| 43 | + |
| 44 | + if (arr->isVectorData()) { |
| 45 | + return APCArray::MakePackedShared(arr, unserializeObj); |
| 46 | + } |
| 47 | + |
| 48 | + return APCArray::MakeShared(arr, unserializeObj); |
| 49 | +} |
| 50 | + |
| 51 | +APCHandle* APCArray::MakeShared() { |
| 52 | + void* p = malloc(sizeof(APCArray)); |
| 53 | + APCArray* arr = new (p) APCArray(static_cast<size_t>(0)); |
| 54 | + return arr->getHandle(); |
| 55 | +} |
| 56 | + |
| 57 | +APCHandle* APCArray::MakeShared(ArrayData* arr, |
| 58 | + bool unserializeObj) { |
| 59 | + auto num = arr->size(); |
| 60 | + auto cap = num > 2 ? Util::roundUpToPowerOfTwo(num) : 2; |
30 | 61 |
|
31 |
| - APCArray* ret = (APCArray*)malloc(sizeof(APCArray) + |
32 |
| - sizeof(int) * cap + |
33 |
| - sizeof(Bucket) * num); |
| 62 | + void* p = malloc(sizeof(APCArray) + |
| 63 | + sizeof(int) * cap + |
| 64 | + sizeof(Bucket) * num); |
| 65 | + APCArray* ret = new (p) APCArray(static_cast<unsigned int>(cap)); |
34 | 66 |
|
35 |
| - ret->m.m_capacity_mask = cap - 1; |
36 |
| - ret->m.m_num = 0; |
37 | 67 | for (int i = 0; i < cap; i++) ret->hash()[i] = -1;
|
38 | 68 |
|
39 | 69 | try {
|
40 | 70 | for (ArrayIter it(arr); !it.end(); it.next()) {
|
41 |
| - APCVariant* key = APCVariant::Create(it.first(), false, true, |
42 |
| - unserializeObj); |
43 |
| - APCVariant* val = APCVariant::Create(it.secondRef(), false, true, |
44 |
| - unserializeObj); |
45 |
| - if (val->shouldCache()) shouldCache = true; |
46 |
| - ret->add(ret->m.m_num, key, val); |
47 |
| - ++ret->m.m_num; |
| 71 | + auto key = APCHandle::Create(it.first(), false, true, |
| 72 | + unserializeObj); |
| 73 | + auto val = APCHandle::Create(it.secondRef(), false, true, |
| 74 | + unserializeObj); |
| 75 | + if (val->shouldCache()) { |
| 76 | + ret->mustCache(); |
| 77 | + } |
| 78 | + ret->add(key, val); |
48 | 79 | }
|
49 | 80 | } catch (...) {
|
50 |
| - Destroy(ret); |
| 81 | + delete ret; |
51 | 82 | throw;
|
52 | 83 | }
|
53 | 84 |
|
54 |
| - return ret; |
| 85 | + return ret->getHandle(); |
55 | 86 | }
|
56 | 87 |
|
57 |
| -void APCArray::Destroy(APCArray* map) { |
58 |
| - Bucket* buckets = map->buckets(); |
59 |
| - for (int i = 0; i < map->m.m_num; i++) { |
60 |
| - buckets[i].key->decRef(); |
61 |
| - buckets[i].val->decRef(); |
| 88 | +APCHandle* APCArray::MakePackedShared(ArrayData* arr, |
| 89 | + bool unserializeObj) { |
| 90 | + size_t num_elems = arr->size(); |
| 91 | + void* p = malloc(sizeof(APCArray) + sizeof(APCHandle*) * num_elems); |
| 92 | + auto ret = new (p) APCArray(static_cast<size_t>(num_elems)); |
| 93 | + |
| 94 | + try { |
| 95 | + size_t i = 0; |
| 96 | + for (ArrayIter it(arr); !it.end(); it.next()) { |
| 97 | + APCHandle* val = APCHandle::Create(it.secondRef(), |
| 98 | + false, true, |
| 99 | + unserializeObj); |
| 100 | + if (val->shouldCache()) { |
| 101 | + ret->mustCache(); |
| 102 | + } |
| 103 | + ret->vals()[i++] = val; |
| 104 | + } |
| 105 | + assert(i == num_elems); |
| 106 | + } catch (...) { |
| 107 | + delete ret; |
| 108 | + throw; |
62 | 109 | }
|
63 |
| - free(map); |
| 110 | + |
| 111 | + return ret->getHandle(); |
| 112 | +} |
| 113 | + |
| 114 | +Variant APCArray::MakeArray(APCHandle* handle) { |
| 115 | + if (handle->getSerializedArray()) { |
| 116 | + StringData* serArr = APCString::fromHandle(handle)->getStringData(); |
| 117 | + return apc_unserialize(serArr->data(), serArr->size()); |
| 118 | + } |
| 119 | + return APCLocalArray::Make(APCArray::fromHandle(handle)); |
| 120 | +} |
| 121 | + |
| 122 | +void APCArray::Delete(APCHandle* handle) { |
| 123 | + handle->getSerializedArray() ? delete APCString::fromHandle(handle) |
| 124 | + : delete APCArray::fromHandle(handle); |
64 | 125 | }
|
65 | 126 |
|
66 |
| -void APCArray::add(int pos, APCVariant *key, APCVariant *val) { |
| 127 | +APCArray::~APCArray() { |
| 128 | + if (isPacked()) { |
| 129 | + APCHandle** v = vals(); |
| 130 | + for (size_t i = 0, n = m_size; i < n; i++) { |
| 131 | + v[i]->decRef(); |
| 132 | + } |
| 133 | + } else { |
| 134 | + Bucket* bks = buckets(); |
| 135 | + for (int i = 0; i < m.m_num; i++) { |
| 136 | + bks[i].key->decRef(); |
| 137 | + bks[i].val->decRef(); |
| 138 | + } |
| 139 | + } |
| 140 | +} |
| 141 | + |
| 142 | +void APCArray::add(APCHandle *key, APCHandle *val) { |
| 143 | + int pos = m.m_num; |
67 | 144 | // NOTE: no check on duplication because we assume the original array has no
|
68 | 145 | // duplication
|
69 | 146 | Bucket* bucket = buckets() + pos;
|
70 | 147 | bucket->key = key;
|
71 | 148 | bucket->val = val;
|
72 |
| - int hash_pos = |
73 |
| - (key->is(KindOfInt64) ? |
74 |
| - key->intData() : key->getStringData()->hash()) & m.m_capacity_mask; |
| 149 | + m.m_num++; |
| 150 | + int hash_pos; |
| 151 | + if (!IS_REFCOUNTED_TYPE(key->getType())) { |
| 152 | + APCTypedValue *k = APCTypedValue::fromHandle(key); |
| 153 | + hash_pos = (key->is(KindOfInt64) ? |
| 154 | + k->getInt64() : k->getStringData()->hash()) & m.m_capacity_mask; |
| 155 | + } else { |
| 156 | + assert(key->is(KindOfString)); |
| 157 | + APCString *k = APCString::fromHandle(key); |
| 158 | + hash_pos = k->getStringData()->hash() & m.m_capacity_mask; |
| 159 | + } |
75 | 160 |
|
76 | 161 | int& hp = hash()[hash_pos];
|
77 | 162 | bucket->next = hp;
|
78 | 163 | hp = pos;
|
79 | 164 | }
|
80 | 165 |
|
81 |
| -int APCArray::indexOf(const StringData* key) { |
| 166 | +ssize_t APCArray::indexOf(const StringData* key) const { |
82 | 167 | strhash_t h = key->hash();
|
83 |
| - int bucket = hash()[h & m.m_capacity_mask]; |
| 168 | + ssize_t bucket = hash()[h & m.m_capacity_mask]; |
84 | 169 | Bucket* b = buckets();
|
85 | 170 | while (bucket != -1) {
|
86 |
| - if (!b[bucket].key->is(KindOfInt64) && |
87 |
| - key->same(b[bucket].key->getStringData())) { |
88 |
| - return bucket; |
| 171 | + if (!IS_REFCOUNTED_TYPE(b[bucket].key->getType())) { |
| 172 | + APCTypedValue *k = APCTypedValue::fromHandle(b[bucket].key); |
| 173 | + if (!b[bucket].key->is(KindOfInt64) && |
| 174 | + key->same(k->getStringData())) { |
| 175 | + return bucket; |
| 176 | + } |
| 177 | + } else { |
| 178 | + assert(b[bucket].key->is(KindOfString)); |
| 179 | + APCString *k = APCString::fromHandle(b[bucket].key); |
| 180 | + if (key->same(k->getStringData())) { |
| 181 | + return bucket; |
| 182 | + } |
89 | 183 | }
|
90 | 184 | bucket = b[bucket].next;
|
91 | 185 | }
|
92 | 186 | return -1;
|
93 | 187 | }
|
94 | 188 |
|
95 |
| -int APCArray::indexOf(int64_t key) { |
96 |
| - int bucket = hash()[key & m.m_capacity_mask]; |
| 189 | +ssize_t APCArray::indexOf(int64_t key) const { |
| 190 | + ssize_t bucket = hash()[key & m.m_capacity_mask]; |
97 | 191 | Bucket* b = buckets();
|
98 | 192 | while (bucket != -1) {
|
99 | 193 | if (b[bucket].key->is(KindOfInt64) &&
|
100 |
| - key == b[bucket].key->intData()) { |
| 194 | + key == APCTypedValue::fromHandle(b[bucket].key)->getInt64()) { |
101 | 195 | return bucket;
|
102 | 196 | }
|
103 | 197 | bucket = b[bucket].next;
|
|
0 commit comments