int SharedVariant::getIndex(CVarRef key) { ASSERT(is(KindOfArray)); switch (key.getType()) { case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: { int64 num = key.getNumData(); if (getIsVector()) { if (num < 0 || (size_t) num >= m_data.vec->size) return -1; return num; } return m_data.map->indexOf(num); } case KindOfStaticString: case KindOfString: { if (getIsVector()) return -1; StringData *sd = key.getStringData(); return m_data.map->indexOf(sd); } default: // No other types are legitimate keys break; } return -1; }
int64 HphpMap::hash(CVarRef s) { int64 hash; switch (s.getType()) { case KindOfInt16: case KindOfInt32: case KindOfInt64: hash = hash_int64(s.toInt64()); break; case LiteralString: { const char* d = s.getLiteralString(); hash = hash_string(d, strlen(d)); } break; case KindOfString: { StringData *st = s.getStringData(); hash = hash_string(st->data(), st->size()); } break; default: ASSERT(false); return 0; } return hash; }
HOT_FUNC void ImmutableMap::add(int pos, CVarRef key, CVarRef val, bool unserializeObj) { int64_t ikey; StringData* skey; int32_t hash; Bucket* b = buckets() + pos; switch (key.getType()) { case KindOfInt64: { hash = ikey = key.toInt64(); b->setIntKey(ikey); break; } case KindOfString: { skey = StringData::GetStaticString(key.getStringData()); goto static_case; } case KindOfStaticString: { skey = key.getStringData(); static_case: hash = skey->hash(); b->setStrKey(skey, hash); break; } default: not_reached(); } addVal(pos, hash & m.m_capacity_mask, val, unserializeObj); }
int64_t f_count(CVarRef var, bool recursive /* = false */) { switch (var.getType()) { case KindOfUninit: case KindOfNull: return 0; case KindOfObject: { Object obj = var.toObject(); if (obj->isCollection()) { return obj->getCollectionSize(); } if (obj.instanceof(SystemLib::s_CountableClass)) { return obj->o_invoke_few_args(s_count, 0).toInt64(); } } break; case KindOfArray: if (recursive) { CArrRef arr_var = var.toCArrRef(); return php_count_recursive(arr_var); } return var.getArrayData()->size(); default: break; } return 1; }
bool Array::less(CVarRef v2) const { if (m_px == nullptr || v2.isNull()) { return HPHP::less(toBoolean(), v2.toBoolean()); } if (v2.getType() == KindOfArray) { return m_px->compare(v2.toArray().get()) < 0; } return v2.more(*this); }
bool Array::more(CVarRef v2) const { if (m_px == NULL || v2.isNull()) { return HPHP::more(toBoolean(), v2.toBoolean()); } if (v2.getType() == KindOfArray) { return v2.toArray().get()->compare(m_px) < 0; } return v2.less(*this); }
void Array::remove(CVarRef key) { switch(key.getType()) { case KindOfBoolean: case KindOfInt64: removeImpl(key.toInt64()); return; default: break; } VarNR k(key.toKey()); if (!k.isNull()) { removeImpl(k); } }
void Parameter::bind(VariableEnvironment &env, CVarRef val, bool ref /* = false */) const { if (m_kind != KindOfNull) { DataType otype = val.getType(); if (!(m_nullDefault && otype == KindOfNull || otype == m_kind && (m_kind != KindOfObject || m_kind == KindOfObject && val.toObject().instanceof(m_type.c_str())))) { throw_unexpected_argument_type(m_argNum, m_fnName, m_type.c_str(), val); } } if (ref) val.setContagious(); env.getIdx(m_idx) = val; }
bool Array::exists(CVarRef key, bool isKey /* = false */) const { switch(key.getType()) { case KindOfBoolean: case KindOfInt64: return existsImpl(key.toInt64()); default: break; } if (isKey) return existsImpl(key); VarNR k(key.toKey()); if (!k.isNull()) { return existsImpl(k); } return false; }
bool ConcurrentTableSharedStore::constructPrime(CVarRef v, KeyValuePair& item) { if (s_apc_file_storage.getState() != SharedStoreFileStorage::StateInvalid && (IS_REFCOUNTED_TYPE(v.getType()))) { // Only do the storage for ref-counted type String s = apc_serialize(v); char *sAddr = s_apc_file_storage.put(s.data(), s.size()); if (sAddr) { item.sAddr = sAddr; item.sSize = s.size(); return false; } } item.value = SharedVariant::Create(v, false); return true; }
CVarRef Array::set(CVarRef key, CVarRef v, int64 prehash /* = -1 */) { switch(key.getType()) { case KindOfBoolean: case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: return setImpl(key.toInt64(), v, prehash); default: break; } Variant k = key.toKey(); if (!k.isNull()) { return setImpl(k, v, prehash); } return null_variant; }
bool Array::exists(CVarRef key, int64 prehash /* = -1 */) const { switch(key.getType()) { case KindOfBoolean: case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: return existsImpl(key.toInt64(), prehash); default: break; } Variant k = key.toKey(); if (!k.isNull()) { return existsImpl(k, prehash); } return false; }
void Array::remove(CVarRef key, int64 prehash /* = -1 */) { switch(key.getType()) { case KindOfBoolean: case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: removeImpl(key.toInt64(), prehash); return; default: break; } Variant k = key.toKey(); if (!k.isNull()) { removeImpl(k, prehash); } }
String f_gettype(CVarRef v) { switch (v.getType()) { case KindOfUninit: case KindOfNull: return "NULL"; case KindOfBoolean: return "boolean"; case KindOfInt64: return "integer"; case KindOfDouble: return "double"; case KindOfStaticString: case KindOfString: return "string"; case KindOfArray: return "array"; case KindOfObject: return "object"; default: assert(false); break; } return ""; }
int hphp_ffi_exportVariant(CVarRef v, void** result) { switch (v.getType()) { case KindOfNull: return 0; case KindOfBoolean: *result = (void*)v.toBoolean(); return 1; case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: { *result = (void*)v.toInt64(); return 2; } case KindOfDouble: { union { double d; void* p; } u; u.d = v.toDouble(); *result = u.p; return 3; } case LiteralString: *result = (void*)v.getLiteralString(); return 4; case KindOfString: { StringData *sd = v.getStringData(); sd->incRefCount(); *result = (void*)sd; return 5; } case KindOfArray: { ArrayData *ad = v.getArrayData(); ad->incRefCount(); *result = (void*)ad; return 6; } case KindOfObject: { ObjectData *od = v.getObjectData(); od->incRefCount(); *result = (void*)od; return 7; } default: ASSERT(false); return 0; } }
Variant Array::rvalAt(CVarRef key, int64 prehash /* = -1 */) const { if (!m_px) return null; switch(key.getType()) { case KindOfBoolean: case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: return m_px->get(key.toInt64(), prehash); default: break; } Variant k = key.toKey(); if (!k.isNull()) { return m_px->get(k, prehash); } return null; }
String f_serialize(CVarRef value) { switch (value.getType()) { case KindOfUninit: case KindOfNull: return "N;"; case KindOfBoolean: return value.getBoolean() ? "b:1;" : "b:0;"; case KindOfInt64: { StringBuffer sb; sb.append("i:"); sb.append(value.getInt64()); sb.append(';'); return sb.detach(); } case KindOfStaticString: case KindOfString: { StringData *str = value.getStringData(); StringBuffer sb; sb.append("s:"); sb.append(str->size()); sb.append(":\""); sb.append(str->data(), str->size()); sb.append("\";"); return sb.detach(); } case KindOfArray: { ArrayData *arr = value.getArrayData(); if (arr->empty()) return "a:0:{}"; // fall-through } case KindOfObject: case KindOfResource: case KindOfDouble: { VariableSerializer vs(VariableSerializer::Type::Serialize); return vs.serialize(value, true); } default: assert(false); break; } return ""; }
int ThreadSharedVariant::getIndex(CVarRef key) { ASSERT(is(KindOfArray)); switch (key.getType()) { case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: { int64 num = key.getNumData(); if (getIsVector()) { if (num < 0 || (size_t) num >= m_data.vec->size) return -1; return num; } if (RuntimeOption::ApcUseGnuMap) { Int64ToIntMap::const_iterator it = m_data.gnuMap->intMap->find(num); if (it == m_data.gnuMap->intMap->end()) return -1; return it->second; } return m_data.map->indexOf(num); } case KindOfStaticString: case KindOfString: { if (getIsVector()) return -1; StringData *sd = key.getStringData(); if (RuntimeOption::ApcUseGnuMap) { StringDataToIntMap::const_iterator it = m_data.gnuMap->strMap->find(sd); if (it == m_data.gnuMap->strMap->end()) return -1; return it->second; } return m_data.map->indexOf(sd); } default: // No other types are legitimate keys break; } return -1; }
Array Array::operator+(CVarRef var) const { if (var.getType() != KindOfArray) { throw BadArrayMergeException(); } return operator+(var.getArrayData()); }
ThreadSharedVariant::ThreadSharedVariant(CVarRef source, bool serialized, bool inner /* = false */) { ASSERT(!serialized || source.isString()); setOwner(); m_ref = 1; switch (source.getType()) { case KindOfBoolean: { m_type = KindOfBoolean; m_data.num = source.toBoolean(); break; } case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: { m_type = KindOfInt64; m_data.num = source.toInt64(); break; } case KindOfDouble: { m_type = KindOfDouble; m_data.dbl = source.toDouble(); break; } case KindOfStaticString: case KindOfString: { String s = source.toString(); m_type = serialized ? KindOfObject : KindOfString; if (serialized) { // It is priming, and there might not be the right class definitions // for unserialization. s = apc_reserialize(s); } m_data.str = s->copy(true); break; } case KindOfArray: { m_type = KindOfArray; ArrayData *arr = source.getArrayData(); if (!inner) { // only need to call hasInternalReference() on the toplevel array PointerSet seen; if (arr->hasInternalReference(seen)) { setSerializedArray(); setShouldCache(); String s = apc_serialize(source); m_data.str = new StringData(s.data(), s.size(), CopyString); break; } } size_t size = arr->size(); if (arr->isVectorData()) { setIsVector(); m_data.vec = new VectorData(size); uint i = 0; for (ArrayIter it(arr); !it.end(); it.next(), i++) { ThreadSharedVariant* val = createAnother(it.second(), false, true); if (val->shouldCache()) setShouldCache(); m_data.vec->vals[i] = val; } } else { m_data.map = new ImmutableMap(size); uint i = 0; for (ArrayIter it(arr); !it.end(); it.next(), i++) { ThreadSharedVariant* key = createAnother(it.first(), false); ThreadSharedVariant* val = createAnother(it.second(), false, true); if (val->shouldCache()) setShouldCache(); m_data.map->add(key, val); } } break; } default: { m_type = KindOfObject; setShouldCache(); String s = apc_serialize(source); m_data.str = new StringData(s.data(), s.size(), CopyString); break; } } }
String f_gettype(CVarRef v) { return getDataTypeString(v.getType()); }
ProcessSharedVariant::ProcessSharedVariant(CVarRef source, ProcessSharedVariantLock* lock) : m_lock(putPtr(lock)) { switch (source.getType()) { case KindOfBoolean: { m_type = KindOfBoolean; m_data.num = source.toBoolean(); break; } case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: { m_type = KindOfInt64; m_data.num = source.toInt64(); break; } case KindOfDouble: { m_type = KindOfDouble; m_data.dbl = source.toDouble(); break; } case LiteralString: case KindOfStaticString: case KindOfString: { String s = source.toString(); m_type = KindOfString; if (lock) { m_data.str = putPtr(SharedMemoryManager::GetSegment() ->construct<SharedMemoryString> (boost::interprocess::anonymous_instance) (s.data(), s.size())); } else { // Just need this string to live long enough for the key lookup so // don't store in shared memory. m_data.str = putPtr(new SharedMemoryString(s.data(), s.size())); } break; } case KindOfArray: { ASSERT(lock); m_type = KindOfArray; uint i = 0; ProcessSharedVariantMapData* mapData = SharedMemoryManager::GetSegment() ->construct<ProcessSharedVariantMapData> (boost::interprocess::anonymous_instance)(); m_data.map = putPtr(mapData); ProcessSharedVariantToIntMap* map = SharedMemoryManager::GetSegment() ->construct<ProcessSharedVariantToIntMap> (boost::interprocess::anonymous_instance)(); mapData->map = putPtr(map); SharedMemoryVector<SharedVariant*>* keys = SharedMemoryManager::GetSegment() ->construct<SharedMemoryVector<SharedVariant*> > (boost::interprocess::anonymous_instance)(); mapData->keys = putPtr(keys); SharedMemoryVector<SharedVariant*>* vals = SharedMemoryManager::GetSegment() ->construct<SharedMemoryVector<SharedVariant*> > (boost::interprocess::anonymous_instance)(); mapData->vals = putPtr(vals); for (ArrayIterPtr it = source.begin(); !it->end(); it->next()) { ProcessSharedVariant* key = SharedMemoryManager::GetSegment() ->construct<ProcessSharedVariant> (boost::interprocess::anonymous_instance) (it->first(), getLock()); ProcessSharedVariant* val = SharedMemoryManager::GetSegment() ->construct<ProcessSharedVariant> (boost::interprocess::anonymous_instance) (it->second(), getLock()); (*map)[key] = i++; keys->push_back(putPtr(key)); vals->push_back(putPtr(val)); } break; } default: { m_type = KindOfObject; String s = f_serialize(source); m_data.str = putPtr(SharedMemoryManager::GetSegment() ->construct<SharedMemoryString> (boost::interprocess::anonymous_instance) (s.data(), s.size())); break; } } }
bool HphpMap::same(CVarRef s1, CVarRef s2) { DataType t1 = s1.getType(); DataType t2 = s2.getType(); switch (t1) { case KindOfInt16: case KindOfInt32: case KindOfInt64: switch (t2) { case KindOfInt16: case KindOfInt32: case KindOfInt64: break; default: return false; } break; case LiteralString: case KindOfString: switch (t2) { case LiteralString: case KindOfString: break; default: return false; } break; default: ASSERT(false); if (t1 != t2) return false; break; } switch (t1) { case KindOfInt16: case KindOfInt32: case KindOfInt64: return s1.toInt64() == s2.toInt64(); default: const char* s1d; uint64 s1l; const char* s2d; uint64 s2l; if (t1 == LiteralString) { s1d = s1.getLiteralString(); s1l = strlen(s1d); } else { StringData *s1data = s1.getStringData(); s1d = s1data->data(); s1l = s1data->size(); } if (t2 == LiteralString) { s2d = s2.getLiteralString(); s2l = strlen(s2d); } else { StringData *s2data = s2.getStringData(); s2d = s2data->data(); s2l = s2data->size(); } return string_strcmp(s1d, s1l, s2d, s2l) == 0; } }
bool f_is_resource(CVarRef v) { return (v.getType() == KindOfResource && !v.getResourceData()->isInvalid()); }
String f_gettype(CVarRef v) { if (v.getType() == KindOfResource && v.getResourceData()->isInvalid()) { return s_unknown_type; } return getDataTypeString(v.getType()); }
SharedVariant::SharedVariant(CVarRef source, bool serialized, bool inner /* = false */, bool unserializeObj /* = false */) : m_shouldCache(false), m_flags(0) { assert(!serialized || source.isString()); m_count = 1; m_type = source.getType(); switch (m_type) { case KindOfBoolean: { m_data.num = source.toBoolean(); break; } case KindOfInt64: { m_type = KindOfInt64; m_data.num = source.toInt64(); break; } case KindOfDouble: { m_data.dbl = source.toDouble(); break; } case KindOfStaticString: { if (serialized) goto StringCase; m_data.str = source.getStringData(); break; } StringCase: case KindOfString: { String s = source.toString(); if (serialized) { m_type = KindOfObject; // It is priming, and there might not be the right class definitions // for unserialization. s = apc_reserialize(s); } StringData* st = StringData::LookupStaticString(s.get()); if (st) { m_data.str = st; m_type = KindOfStaticString; break; } m_data.str = s->copy(true); break; } case KindOfArray: { ArrayData *arr = source.getArrayData(); if (!inner) { // only need to call hasInternalReference() on the toplevel array PointerSet seen; if (arr->hasInternalReference(seen)) { setSerializedArray(); m_shouldCache = true; String s = apc_serialize(source); m_data.str = StringData::MakeMalloced(s.data(), s.size()); break; } } if (arr->isVectorData()) { setIsVector(); m_data.vec = new (arr->size()) VectorData(); for (ArrayIter it(arr); !it.end(); it.next()) { SharedVariant* val = Create(it.secondRef(), false, true, unserializeObj); if (val->m_shouldCache) m_shouldCache = true; m_data.vec->vals()[m_data.vec->m_size++] = val; } } else { m_data.map = ImmutableMap::Create(arr, unserializeObj, m_shouldCache); } break; } case KindOfUninit: case KindOfNull: { break; } 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. m_type = KindOfArray; setIsVector(); m_data.vec = new (0) VectorData(); break; } default: { assert(source.isObject()); m_shouldCache = true; if (unserializeObj) { // This assumes hasInternalReference(seen, true) is false ImmutableObj* obj = new ImmutableObj(source.getObjectData()); m_data.obj = obj; setIsObj(); } else { String s = apc_serialize(source); m_data.str = StringData::MakeMalloced(s.data(), s.size()); } break; } } assert(m_type != KindOfResource); }
SharedVariant::SharedVariant(CVarRef source, bool serialized, bool inner /* = false */, bool unserializeObj /* = false */) : m_count (1), m_shouldCache(false), m_flags(0){ ASSERT(!serialized || source.isString()); m_type = source.getType(); switch (m_type) { case KindOfBoolean: { m_data.num = source.toBoolean(); break; } case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: { m_type = KindOfInt64; m_data.num = source.toInt64(); break; } case KindOfDouble: { m_data.dbl = source.toDouble(); break; } case KindOfStaticString: case KindOfString: { String s = source.toString(); if (serialized) { m_type = KindOfObject; // It is priming, and there might not be the right class definitions // for unserialization. s = apc_reserialize(s); } m_data.str = s->copy(true); break; } case KindOfArray: { ArrayData *arr = source.getArrayData(); if (!inner) { // only need to call hasInternalReference() on the toplevel array PointerSet seen; if (arr->hasInternalReference(seen)) { setSerializedArray(); m_shouldCache = true; String s = apc_serialize(source); m_data.str = new StringData(s.data(), s.size(), CopyString); break; } } size_t size = arr->size(); if (arr->isVectorData()) { setIsVector(); m_data.vec = new VectorData(size); uint i = 0; for (ArrayIter it(arr); !it.end(); it.next(), i++) { SharedVariant* val = Create(it.secondRef(), false, true, unserializeObj); if (val->m_shouldCache) m_shouldCache = true; m_data.vec->vals[i] = val; } } else { m_data.map = new ImmutableMap(size); for (ArrayIter it(arr); !it.end(); it.next()) { SharedVariant* key = Create(it.first(), false, true, unserializeObj); SharedVariant* val = Create(it.secondRef(), false, true, unserializeObj); if (val->m_shouldCache) m_shouldCache = true; m_data.map->add(key, val); } } break; } case KindOfNull: { m_data.num = 0; break; } default: { ASSERT(source.isObject()); m_shouldCache = true; if (unserializeObj) { // This assumes hasInternalReference(seen, true) is false ImmutableObj* obj = new ImmutableObj(source.getObjectData()); m_data.obj = obj; setIsObj(); } else { String s = apc_serialize(source); m_data.str = new StringData(s.data(), s.size(), CopyString); } break; } } }