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++); } }
/* * The CreateCl opcode is specified as not being allowed before the * class it creates exists, and closure classes are always unique. * * This means even if we're not in RepoAuthoritative mode, as long as * this code is reachable it will always use the same closure Class*, * so we can just burn it into the TC without using RDS. */ void emitCreateCl(HTS& env, int32_t numParams, const StringData* clsName) { auto const cls = Unit::lookupClassOrUniqueClass(clsName); auto const invokeFunc = cls->lookupMethod(s_uuinvoke.get()); auto const clonedFunc = invokeFunc->cloneAndSetClass( const_cast<Class*>(curClass(env)) ); assert(cls && (cls->attrs() & AttrUnique)); auto const closure = allocObjFast(env, cls); gen(env, IncRef, closure); auto const ctx = [&]{ if (!curClass(env)) return cns(env, nullptr); auto const ldctx = gen(env, LdCtx, fp(env)); if (invokeFunc->attrs() & AttrStatic) { return gen(env, ConvClsToCctx, gen(env, LdClsCtx, ldctx)); } gen(env, IncRefCtx, ldctx); return ldctx; }(); gen(env, StClosureCtx, closure, ctx); gen(env, StClosureFunc, FuncData(clonedFunc), closure); SSATmp* args[numParams]; for (int32_t i = 0; i < numParams; ++i) { args[numParams - i - 1] = popF(env); } int32_t propId = 0; for (; propId < numParams; ++propId) { gen( env, StClosureArg, PropByteOffset(cls->declPropOffset(propId)), closure, args[propId] ); } // Closure static variables are per instance, and need to start // uninitialized. After numParams use vars, the remaining instance // properties hold any static locals. assert(cls->numDeclProperties() == clonedFunc->numStaticLocals() + numParams); for (int32_t numDeclProperties = cls->numDeclProperties(); propId < numDeclProperties; ++propId) { gen( env, StClosureArg, PropByteOffset(cls->declPropOffset(propId)), closure, cns(env, Type::Uninit) ); } push(env, closure); }