void Variant::setEvalScalar() { switch (m_type) { case KindOfString: { StringData *pstr = m_data.pstr; if (!pstr->isStatic()) { StringData *sd = makeStaticString(pstr); decRefStr(pstr); m_data.pstr = sd; assert(m_data.pstr->isStatic()); m_type = KindOfStaticString; } break; } case KindOfArray: { ArrayData *parr = m_data.parr; if (!parr->isStatic()) { ArrayData *ad = ArrayData::GetScalarArray(parr); decRefArr(parr); m_data.parr = ad; assert(m_data.parr->isStatic()); } break; } case KindOfRef: not_reached(); break; case KindOfObject: case KindOfResource: not_reached(); // object shouldn't be in a scalar array break; default: break; } }
void ZendArray::onSetEvalScalar() { for (Bucket *p = m_pListHead; p; p = p->pListNext) { StringData *key = p->skey; if (p->hasStrKey() && !key->isStatic()) { StringData *skey= StringData::GetStaticString(key); if (key && key->decRefCount() == 0) { DELETE(StringData)(key); } p->skey = skey; } p->data.setEvalScalar(); } }
Variant::Variant(const String& v) { m_type = KindOfString; StringData *s = v.get(); if (s) { m_data.pstr = s; if (s->isStatic()) { m_type = KindOfStaticString; } else { s->incRefCount(); } } else { m_type = KindOfNull; } }
bool register_intercept(const String& name, const Variant& callback, const Variant& data) { StringIMap<Variant> &handlers = s_intercept_data->m_intercept_handlers; if (!callback.toBoolean()) { if (name.empty()) { s_intercept_data->m_global_handler.unset(); StringIMap<Variant> empty; handlers.swap(empty); } else { auto tmp = handlers[name]; auto it = handlers.find(name); if (it != handlers.end()) { auto tmp = it->second; handlers.erase(it); } } return true; } EventHook::EnableIntercept(); Array handler = make_packed_array(callback, data); if (name.empty()) { s_intercept_data->m_global_handler = handler; StringIMap<Variant> empty; handlers.swap(empty); } else { handlers[name] = handler; } Lock lock(s_mutex); if (name.empty()) { for (auto& entry : s_registered_flags) { flag_maybe_intercepted(entry.second.second); } } else { StringData* sd = name.get(); if (!sd->isStatic()) { sd = makeStaticString(sd); } auto &entry = s_registered_flags[StrNR(sd)]; entry.first = true; flag_maybe_intercepted(entry.second); } return true; }
int32_t ImmutableObj::getSpaceUsage() { int32_t size = sizeof(ImmutableObj) + sizeof(Prop) * m_propCount; if (!m_cls->isStatic()) { size += sizeof(StringData) + m_cls->size(); } for (int i = 0; i < m_propCount; i++) { StringData *sd = m_props[i].name; if (!sd->isStatic()) { size += sizeof(StringData) + sd->size(); } if (m_props[i].val) { size += m_props[i].val->getSpaceUsage(); } } return size; }
void Variant::setEvalScalar() { switch (m_type) { case KindOfUninit: case KindOfNull: case KindOfBoolean: case KindOfInt64: case KindOfDouble: case KindOfStaticString: return; case KindOfString: { StringData *pstr = m_data.pstr; if (!pstr->isStatic()) { StringData *sd = makeStaticString(pstr); decRefStr(pstr); m_data.pstr = sd; assert(m_data.pstr->isStatic()); m_type = KindOfStaticString; } return; } case KindOfPersistentArray: case KindOfArray: { auto parr = m_data.parr; if (!parr->isStatic()) { auto ad = ArrayData::GetScalarArray(parr); assert(ad->isStatic()); m_data.parr = ad; m_type = KindOfPersistentArray; decRefArr(parr); } return; } case KindOfObject: case KindOfResource: case KindOfRef: case KindOfClass: break; } not_reached(); }
bool register_intercept(const String& name, CVarRef callback, CVarRef data) { StringIMap<Variant> &handlers = s_intercept_data->m_intercept_handlers; if (!callback.toBoolean()) { if (name.empty()) { s_intercept_data->m_global_handler.reset(); handlers.clear(); } else { handlers.erase(name); } return true; } EventHook::EnableIntercept(); Array handler = make_packed_array(callback, data); if (name.empty()) { s_intercept_data->m_global_handler = handler; handlers.clear(); } else { handlers[name] = handler; } Lock lock(s_mutex); if (name.empty()) { for (auto& entry : s_registered_flags) { flag_maybe_intercepted(entry.second.second); } } else { StringData* sd = name.get(); if (!sd->isStatic()) { sd = makeStaticString(sd); } auto &entry = s_registered_flags[StrNR(sd)]; entry.first = true; flag_maybe_intercepted(entry.second); } return true; }
Variant *get_intercept_handler(CStrRef name, char* flag) { TRACE(1, "get_intercept_handler %s flag is %d\n", name.get()->data(), (int)*flag); if (*flag == -1) { Lock lock(s_mutex); if (*flag == -1) { StringData *sd = name.get(); if (!sd->isStatic()) { sd = StringData::GetStaticString(sd); } s_registered_flags[StrNR(sd)].push_back(flag); *flag = 0; } } Variant *handler = get_enabled_intercept_handler(name); if (handler == nullptr) { return nullptr; } *flag = 1; return handler; }
void ImmutableObj::getSizeStats(SharedVariantStats *stats) { stats->initStats(); if (m_cls->isStatic()) { stats->dataTotalSize += sizeof(ImmutableObj) + sizeof(Prop) * m_propCount; } else { stats->dataSize += m_cls->size(); stats->dataTotalSize += sizeof(ImmutableObj) + sizeof(Prop) * m_propCount + sizeof(StringData) + m_cls->size(); } for (int i = 0; i < m_propCount; i++) { StringData *sd = m_props[i].name; if (!sd->isStatic()) { stats->dataSize += sd->size(); stats->dataTotalSize += sizeof(StringData) + sd->size(); } if (m_props[i].val) { SharedVariantStats childStats; m_props[i].val->getStats(&childStats); stats->addChildStats(&childStats); } } }
Variant *get_intercept_handler(const String& name, char* flag) { TRACE(1, "get_intercept_handler %s flag is %d\n", name.get()->data(), (int)*flag); if (*flag == -1) { Lock lock(s_mutex); if (*flag == -1) { StringData *sd = name.get(); if (!sd->isStatic()) { sd = makeStaticString(sd); } auto &entry = s_registered_flags[StrNR(sd)]; entry.second.push_back(flag); *flag = entry.first; } if (!*flag) return nullptr; } Variant *handler = get_enabled_intercept_handler(name); if (handler == nullptr) { return nullptr; } assert(*flag); return handler; }
void Variant::setEvalScalar() { switch (m_type) { DT_UNCOUNTED_CASE: return; case KindOfString: { StringData *pstr = m_data.pstr; if (!pstr->isStatic()) { StringData *sd = makeStaticString(pstr); decRefStr(pstr); m_data.pstr = sd; assert(m_data.pstr->isStatic()); m_type = KindOfStaticString; } return; } case KindOfArray: { ArrayData *parr = m_data.parr; if (!parr->isStatic()) { ArrayData *ad = ArrayData::GetScalarArray(parr); decRefArr(parr); m_data.parr = ad; assert(m_data.parr->isStatic()); } return; } case KindOfObject: case KindOfResource: case KindOfRef: case KindOfClass: break; } not_reached(); }
APCHandle::Pair APCHandle::Create(const Variant& source, bool serialized, APCHandleLevel level, bool unserializeObj) { auto type = source.getType(); // this gets rid of the ref, if it was one switch (type) { case KindOfUninit: { auto value = APCTypedValue::tvUninit(); return {value->getHandle(), sizeof(APCTypedValue)}; } case KindOfNull: { auto value = APCTypedValue::tvNull(); return {value->getHandle(), sizeof(APCTypedValue)}; } case KindOfBoolean: { auto value = source.getBoolean() ? APCTypedValue::tvTrue() : APCTypedValue::tvFalse(); return {value->getHandle(), sizeof(APCTypedValue)}; } case KindOfInt64: { auto value = new APCTypedValue(source.getInt64()); return {value->getHandle(), sizeof(APCTypedValue)}; } case KindOfDouble: { auto value = new APCTypedValue(source.getDouble()); return {value->getHandle(), sizeof(APCTypedValue)}; } case KindOfPersistentString: case KindOfString: { StringData* s = source.getStringData(); if (serialized) { // It is priming, and there might not be the right class definitions // for unserialization. return APCString::MakeSerializedObject(apc_reserialize(String{s})); } if (s->isStatic()) { auto value = new APCTypedValue(APCTypedValue::StaticStr{}, s); return APCHandle::Pair{value->getHandle(), sizeof(APCTypedValue)}; } auto const st = lookupStaticString(s); if (st) { auto value = new APCTypedValue(APCTypedValue::StaticStr{}, st); return {value->getHandle(), sizeof(APCTypedValue)}; } if (apcExtension::UseUncounted) { auto st = StringData::MakeUncounted(s->slice()); auto value = new APCTypedValue(APCTypedValue::UncountedStr{}, st); return {value->getHandle(), st->size() + sizeof(APCTypedValue)}; } return APCString::MakeSharedString(s); } case KindOfPersistentVec: case KindOfVec: { auto ad = source.getArrayData(); assert(ad->isVecArray()); if (ad->isStatic()) { auto value = new APCTypedValue(APCTypedValue::StaticVec{}, ad); return {value->getHandle(), sizeof(APCTypedValue)}; } return APCArray::MakeSharedVec(ad, level, unserializeObj); } case KindOfPersistentDict: case KindOfDict: { auto ad = source.getArrayData(); assert(ad->isDict()); if (ad->isStatic()) { auto value = new APCTypedValue(APCTypedValue::StaticDict{}, ad); return {value->getHandle(), sizeof(APCTypedValue)}; } return APCArray::MakeSharedDict(ad, level, unserializeObj); } case KindOfPersistentKeyset: case KindOfKeyset: { auto ad = source.getArrayData(); assert(ad->isKeyset()); if (ad->isStatic()) { auto value = new APCTypedValue(APCTypedValue::StaticKeyset{}, ad); return {value->getHandle(), sizeof(APCTypedValue)}; } return APCArray::MakeSharedKeyset(ad, level, unserializeObj); } case KindOfPersistentArray: case KindOfArray: { auto ad = source.getArrayData(); assert(ad->isPHPArray()); if (ad->isStatic()) { auto value = new APCTypedValue(APCTypedValue::StaticArr{}, ad); return {value->getHandle(), sizeof(APCTypedValue)}; } return APCArray::MakeSharedArray(ad, level, unserializeObj); } case KindOfObject: if (source.getObjectData()->isCollection()) { return APCCollection::Make(source.getObjectData(), level, unserializeObj); } return unserializeObj ? APCObject::Construct(source.getObjectData()) : APCString::MakeSerializedObject(apc_serialize(source)); 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. return APCArray::MakeSharedEmptyArray(); case KindOfRef: case KindOfClass: return {nullptr, 0}; } not_reached(); }
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; } }