/** * sp points to the last use variable on the stack. * returns the closure so that translator-x64 can just return "rax". */ c_Closure* c_Closure::init(int numArgs, ActRec* ar, TypedValue* sp) { static StringData* invokeName = StringData::GetStaticString("__invoke"); Func* invokeFunc = getVMClass()->lookupMethod(invokeName); if (invokeFunc->attrs() & AttrStatic) { // Only set the class for static closures m_thisOrClass = (ObjectData*)(intptr_t(ar->m_func->cls()) | 1LL); } else { // I don't care if it is a $this or a late bound class because we will just // put it back in the same place on an ActRec. m_thisOrClass = ar->m_this; if (ar->hasThis()) { ar->getThis()->incRefCount(); } } // Change my __invoke's m_cls to be the same as my creator's Class* scope = ar->m_func->cls(); m_func = invokeFunc->cloneAndSetClass(scope); // copy the props to instance variables assert(m_cls->numDeclProperties() == numArgs); TypedValue* beforeCurUseVar = sp + numArgs; TypedValue* curProperty = propVec(); for (int i = 0; i < numArgs; i++) { // teleport the references in here so we don't incref *curProperty++ = *--beforeCurUseVar; } return this; }
void c_Closure::init(int numArgs, ActRec* ar, TypedValue* sp) { auto const invokeFunc = getVMClass()->lookupMethod(s_uuinvoke.get()); m_ctx = ar->m_this; if (ar->hasThis()) { if (invokeFunc->isStatic()) { // Only set the class for static closures. setClass(ar->getThis()->getVMClass()); } else { ar->getThis()->incRefCount(); } } /* * Copy the use vars to instance variables, and initialize any * instance properties that are for static locals to KindOfUninit. */ auto const numDeclProperties = getVMClass()->numDeclProperties(); assert(numDeclProperties - numArgs == getInvokeFunc()->numStaticLocals()); TypedValue* beforeCurUseVar = sp + numArgs; TypedValue* curProperty = propVec(); int i = 0; assert(numArgs <= numDeclProperties); for (; i < numArgs; i++) { // teleport the references in here so we don't incref tvCopy(*--beforeCurUseVar, *curProperty++); } for (; i < numDeclProperties; ++i) { tvWriteUninit(curProperty++); } }
void c_Closure::init(int numArgs, ActRec* ar, TypedValue* sp) { auto const invokeFunc = getVMClass()->lookupMethod(s_uuinvoke.get()); m_thisOrClass = ar->m_this; if (ar->hasThis()) { if (invokeFunc->attrs() & AttrStatic) { // Only set the class for static closures. m_thisOrClass = reinterpret_cast<ObjectData*>( reinterpret_cast<intptr_t>(ar->getThis()->getVMClass()) | 1LL ); } else { ar->getThis()->incRefCount(); } } // Change my __invoke's m_cls to be the same as my creator's Class* scope = ar->m_func->cls(); m_func = invokeFunc->cloneAndSetClass(scope); // copy the props to instance variables assert(m_cls->numDeclProperties() == numArgs); TypedValue* beforeCurUseVar = sp + numArgs; TypedValue* curProperty = propVec(); for (int i = 0; i < numArgs; i++) { // teleport the references in here so we don't incref tvCopy(*--beforeCurUseVar, *curProperty++); } }
Array c_Closure::t___debuginfo() { Array ret = Array::Create(); // Serialize 'use' parameters. if (auto propValues = propVec()) { Array use; auto propsInfo = getVMClass()->declProperties(); for (size_t i = 0; i < getVMClass()->numDeclProperties(); ++i) { auto value = &propValues[i]; use.setWithRef(Variant(StrNR(propsInfo[i].name)), tvAsCVarRef(value)); } if (!use.empty()) { ret.set(s_static, use); } } auto const func = getInvokeFunc(); // Serialize function parameters. if (func->numParams()) { Array params; for (int i = 0; i < func->numParams(); ++i) { auto str = String::attach( StringData::Make(s_varprefix.get(), func->localNames()[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 (hasThis()) { ret.set(s_this, Object(getThis())); } return ret; }
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; }