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 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; }
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; }
bool same(CVarRef v1, const StringData* v2) { bool null1 = v1.isNull(); bool null2 = (v2 == nullptr); if (null1 && null2) return true; if (null1 || null2) return false; if (!v1.isString()) return false; auto const sdata = v1.getStringData(); return sdata == v2 || v2->same(sdata); }
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 f_class_uses(CVarRef obj, bool autoload /* = true */) { Class* cls; if (obj.isString()) { cls = Unit::getClass(obj.getStringData(), autoload); if (!cls) { return false; } } else if (obj.isObject()) { cls = obj.getObjectData()->getVMClass(); } else { return false; } Array ret(Array::Create()); for (auto& elem : cls->usedTraits()) { auto& traitName = elem->nameRef(); ret.set(traitName, traitName); } return ret; }
Variant f_class_parents(CVarRef obj, bool autoload /* = true */) { Class* cls; if (obj.isString()) { cls = Unit::getClass(obj.getStringData(), autoload); if (!cls) { return false; } } else if (obj.isObject()) { cls = obj.getObjectData()->getVMClass(); } else { return false; } Array ret(Array::Create()); for (cls = cls->parent(); cls; cls = cls->parent()) { auto& clsName = cls->nameRef(); ret.set(clsName, clsName); } return ret; }
Variant f_class_implements(CVarRef obj, bool autoload /* = true */) { Class* cls; if (obj.isString()) { cls = Unit::getClass(obj.getStringData(), autoload); if (!cls) { return false; } } else if (obj.isObject()) { cls = obj.getObjectData()->getVMClass(); } else { return false; } Array ret(Array::Create()); const Class::InterfaceMap& ifaces = cls->allInterfaces(); for (int i = 0, size = ifaces.size(); i < size; i++) { ret.set(ifaces[i]->nameRef(), ifaces[i]->nameRef()); } return ret; }
Variant f_class_uses(CVarRef obj, bool autoload /* = true */) { Class* cls; if (obj.isString()) { cls = Unit::getClass(obj.getStringData(), autoload); if (!cls) { return false; } } else if (obj.isObject()) { cls = obj.getObjectData()->getVMClass(); } else { return false; } Array ret(Array::Create()); for (auto const& traitName : cls->preClass()->usedTraits()) { const String& nameRef = *(String*)(&traitName); ret.set(nameRef, nameRef); } return ret; }
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; }
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 ArrayData::IsValidKey(CVarRef k) { return k.isInteger() || (k.isString() && IsValidKey(k.getStringData())); }
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); }