APCHandle* APCArray::MakeUncountedArray(ArrayData* array) { assert(apcExtension::UseUncounted); APCTypedValue* value; if (array->isPacked()) { value = new APCTypedValue(MixedArray::MakeUncountedPacked(array)); } else if (array->isStruct()) { value = new APCTypedValue(StructArray::MakeUncounted(array)); } else { value = new APCTypedValue(MixedArray::MakeUncounted(array)); } return value->getHandle(); }
APCHandle* APCArray::MakeUncountedArray(ArrayData* array) { assert(apcExtension::UseUncounted); APCTypedValue* value; if (array->isPackedLayout()) { ArrayData* data = PackedArray::MakeUncounted(array, sizeof(APCTypedValue)); auto mem = reinterpret_cast<APCTypedValue*>(data) - 1; value = new(mem) APCTypedValue(APCTypedValue::UncountedArr{}, data); } else { ArrayData* data = MixedArray::MakeUncounted(array, sizeof(APCTypedValue)); auto mem = reinterpret_cast<APCTypedValue*>(data) - 1; value = new(mem) APCTypedValue(APCTypedValue::UncountedArr{}, data); } return value->getHandle(); }
ssize_t APCArray::indexOf(const StringData* key) const { strhash_t h = key->hash(); ssize_t bucket = hash()[h & m.m_capacity_mask]; Bucket* b = buckets(); while (bucket != -1) { if (!IS_REFCOUNTED_TYPE(b[bucket].key->getType())) { APCTypedValue *k = APCTypedValue::fromHandle(b[bucket].key); if (!b[bucket].key->is(KindOfInt64) && key->same(k->getStringData())) { return bucket; } } else { assert(b[bucket].key->is(KindOfString)); APCString *k = APCString::fromHandle(b[bucket].key); if (key->same(k->getStringData())) { return bucket; } } bucket = b[bucket].next; } return -1; }
void APCArray::add(APCHandle *key, APCHandle *val) { int pos = m.m_num; // NOTE: no check on duplication because we assume the original array has no // duplication Bucket* bucket = buckets() + pos; bucket->key = key; bucket->val = val; m.m_num++; int hash_pos; if (!IS_REFCOUNTED_TYPE(key->getType())) { APCTypedValue *k = APCTypedValue::fromHandle(key); hash_pos = (key->is(KindOfInt64) ? k->getInt64() : k->getStringData()->hash()) & m.m_capacity_mask; } else { assert(key->is(KindOfString)); APCString *k = APCString::fromHandle(key); hash_pos = k->getStringData()->hash() & m.m_capacity_mask; } int& hp = hash()[hash_pos]; bucket->next = hp; hp = pos; }
APCHandle* APCHandle::Create(const Variant& source, size_t& size, bool serialized, bool inner /* = false */, bool unserializeObj /* = false */) { auto type = source.getType(); // this gets rid of the ref, if it was one switch (type) { case KindOfBoolean: { auto value = new APCTypedValue(type, static_cast<int64_t>(source.getBoolean())); size = sizeof(APCTypedValue); return value->getHandle(); } case KindOfInt64: { auto value = new APCTypedValue(type, source.getInt64()); size = sizeof(APCTypedValue); return value->getHandle(); } case KindOfDouble: { auto value = new APCTypedValue(type, source.getDouble()); size = sizeof(APCTypedValue); return value->getHandle(); } case KindOfUninit: case KindOfNull: { auto value = new APCTypedValue(type); size = sizeof(APCTypedValue); return value->getHandle(); } case KindOfStaticString: { if (serialized) goto StringCase; auto value = new APCTypedValue(type, source.getStringData()); size = sizeof(APCTypedValue); return value->getHandle(); } StringCase: case KindOfString: { StringData* s = source.getStringData(); if (serialized) { // It is priming, and there might not be the right class definitions // for unserialization. return APCObject::MakeShared(apc_reserialize(s), size); } auto const st = lookupStaticString(s); if (st) { APCTypedValue* value = new APCTypedValue(KindOfStaticString, st); size = sizeof(APCTypedValue); return value->getHandle(); } assert(!s->isStatic()); // would've been handled above if (!inner && apcExtension::UseUncounted) { StringData* st = StringData::MakeUncounted(s->slice()); APCTypedValue* value = new APCTypedValue(st); size = sizeof(APCTypedValue) + st->size(); return value->getHandle(); } return APCString::MakeShared(type, s, size); } case KindOfArray: return APCArray::MakeShared(source.getArrayData(), size, inner, unserializeObj); case KindOfResource: // TODO Task #2661075: Here and elsewhere in the runtime, we convert // Resources to the empty array during various serialization operations, // which does not match Zend behavior. We should fix this. size = sizeof(APCArray); return APCArray::MakeShared(); case KindOfObject: return unserializeObj ? APCObject::Construct(source.getObjectData(), size) : APCObject::MakeShared(apc_serialize(source), size); default: return nullptr; } }