ALWAYS_INLINE APCObject::~APCObject() { auto const numProps = m_propCount; if (m_persistent) { auto props = persistentProps(); for (unsigned i = 0; i < numProps; ++i) { if (props[i]) props[i]->unreferenceRoot(); } return; } for (auto i = uint32_t{0}; i < numProps; ++i) { if (props()[i].val) props()[i].val->unreferenceRoot(); assert(props()[i].name->isStatic()); } }
Object APCObject::createObject() const { auto cls = m_cls.left(); assert(cls != nullptr); auto obj = Object::attach( m_fast_init ? ObjectData::newInstanceNoPropInit(const_cast<Class*>(cls)) : ObjectData::newInstance(const_cast<Class*>(cls)) ); auto const numProps = cls->numDeclProperties(); auto const objProp = obj->propVec(); auto const apcProp = persistentProps(); if (m_fast_init) { // re-entry is possible while we're executing toLocal() on each // property, so heap inspectors may see partially initid objects // not yet exposed to PHP. unsigned i = 0; try { for (; i < numProps; ++i) { new (objProp + i) Variant(apcProp[i]->toLocal()); } } catch (...) { for (; i < numProps; ++i) { new (objProp + i) Variant(); } throw; } } else { for (unsigned i = 0; i < numProps; ++i) { tvAsVariant(&objProp[i]) = apcProp[i]->toLocal(); } } if (UNLIKELY(numProps < m_propCount)) { auto dynProps = apcProp[numProps]; assert(dynProps->kind() == APCKind::StaticArray || dynProps->kind() == APCKind::UncountedArray || dynProps->kind() == APCKind::SharedArray); obj->setDynPropArray(dynProps->toLocal().asCArrRef()); } if (!m_no_wakeup) obj->invokeWakeup(); return obj; }
Object APCObject::createObject() const { auto cls = m_cls.left(); assert(cls != nullptr); auto obj = Object::attach( m_fast_init ? ObjectData::newInstanceNoPropInit(const_cast<Class*>(cls)) : ObjectData::newInstance(const_cast<Class*>(cls)) ); auto const numProps = cls->numDeclProperties(); auto const objProp = obj->propVec(); auto const apcProp = persistentProps(); if (m_fast_init) { unsigned i = 0; try { while (i < numProps) { new (objProp + i) Variant(apcProp[i]->toLocal()); ++i; } } catch (...) { while (i < numProps) { new (objProp + i) Variant(); ++i; } throw; } } else { for (unsigned i = 0; i < numProps; ++i) { tvAsVariant(&objProp[i]) = apcProp[i]->toLocal(); } } if (UNLIKELY(numProps < m_propCount)) { auto dynProps = apcProp[numProps]; assert(dynProps->kind() == APCKind::StaticArray || dynProps->kind() == APCKind::UncountedArray || dynProps->kind() == APCKind::SharedArray); obj->setDynPropArray(dynProps->toLocal().asCArrRef()); } if (!m_no_wakeup) obj->invokeWakeup(); return obj; }
APCHandle::Pair APCObject::Construct(ObjectData* objectData) { // This function assumes the object and object/array down the tree have no // internal references and do not implement the serializable interface. assert(!objectData->instanceof(SystemLib::s_SerializableClass)); auto cls = objectData->getVMClass(); auto clsOrName = make_class(cls); if (clsOrName.right()) return ConstructSlow(objectData, clsOrName); // We have a persistent Class. Build an array of APCHandle* to mirror the // declared properties in the object. auto const propInfo = cls->declProperties(); auto const hasDynProps = objectData->hasDynProps(); auto const numRealProps = propInfo.size(); auto const numApcProps = numRealProps + hasDynProps; auto size = sizeof(APCObject) + sizeof(APCHandle*) * numApcProps; auto const apcObj = new (malloc_huge(size)) APCObject(clsOrName, numApcProps); apcObj->m_persistent = 1; // Set a few more flags for faster fetching: whether or not the object has a // wakeup method, and whether or not we can use a fast path that avoids // default-initializing properties before setting them to their APC values. if (!cls->lookupMethod(s___wakeup.get())) apcObj->m_no_wakeup = 1; if (!cls->instanceCtor()) { apcObj->m_fast_init = 1; } auto const apcPropVec = apcObj->persistentProps(); auto const objPropVec = objectData->propVec(); const TypedValueAux* propInit = nullptr; for (unsigned i = 0; i < numRealProps; ++i) { auto const attrs = propInfo[i].attrs; assert((attrs & AttrStatic) == 0); const TypedValue* objProp; if (attrs & AttrBuiltin) { // Special properties like the Memoize cache should be set to their // default value, not the current value. if (propInit == nullptr) { propInit = cls->pinitVec().empty() ? &cls->declPropInit()[0] : &(*cls->getPropData())[0]; } objProp = propInit + i; } else { objProp = objPropVec + i; } auto val = APCHandle::Create(tvAsCVarRef(objProp), false, APCHandleLevel::Inner, true); size += val.size; apcPropVec[i] = val.handle; } if (UNLIKELY(hasDynProps)) { auto val = APCHandle::Create(objectData->dynPropArray(), false, APCHandleLevel::Inner, true); size += val.size; apcPropVec[numRealProps] = val.handle; } return {apcObj->getHandle(), size}; }