static Array HHVM_METHOD(Closure, __debugInfo) { auto closure = c_Closure::fromObject(this_); Array ret = Array::Create(); // Serialize 'use' parameters. if (auto useVars = closure->getUseVars()) { Array use; auto cls = this_->getVMClass(); auto propsInfo = cls->declProperties(); auto nProps = cls->numDeclProperties(); for (size_t i = 0; i < nProps; ++i) { auto value = &useVars[i]; use.setWithRef(Variant(StrNR(propsInfo[i].name)), tvAsCVarRef(value)); } if (!use.empty()) { ret.set(s_static, use); } } auto const func = closure->getInvokeFunc(); // Serialize function parameters. if (auto nParams = func->numParams()) { Array params; auto lNames = func->localNames(); for (int i = 0; i < nParams; ++i) { auto str = String::attach( StringData::Make(s_varprefix.get(), lNames[i]) ); bool optional = func->params()[i].phpCode; if (auto mi = func->methInfo()) { optional = optional || mi->parameters[i]->valueText; } params.set(str, optional ? s_optional : s_required); } ret.set(s_parameter, params); } // Serialize 'this' object. if (closure->hasThis()) { ret.set(s_this, Object(closure->getThis())); } return ret; }
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}; }