/** * 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; }
PGORegionMode pgoRegionMode(const Func& func) { auto& s = RuntimeOption::EvalJitPGORegionSelector; if ((s == "wholecfg" || s == "hotcfg") && RuntimeOption::EvalJitPGOCFGHotFuncOnly && !(func.attrs() & AttrHot)) { return PGORegionMode::Hottrace; } if (s == "hottrace") return PGORegionMode::Hottrace; if (s == "hotblock") return PGORegionMode::Hotblock; if (s == "hotcfg") return PGORegionMode::HotCFG; if (s == "wholecfg") return PGORegionMode::WholeCFG; FTRACE(1, "unknown pgo region mode {}: using hottrace\n", s); assertx(false); return PGORegionMode::Hottrace; }
bool RenamedFuncDict::rename(const StringData* old, const StringData* n3w) { assert(isFunctionRenameable(old) || isFunctionRenameable(n3w)); NamedEntity *oldNe = const_cast<NamedEntity *>(Unit::GetNamedEntity(old)); NamedEntity *newNe = const_cast<NamedEntity *>(Unit::GetNamedEntity(n3w)); Func* func = Unit::lookupFunc(oldNe); if (!func) { // It's the caller's responsibility to ensure that the old function // exists. not_reached(); } if (!(func->attrs() & AttrDynamicInvoke)) { // When EvalJitEnableRenameFunction is false, the translator may wire // non-DynamicInvoke Func*'s into the TC. Don't rename functions. if (RuntimeOption::EvalJit && !RuntimeOption::EvalJitEnableRenameFunction) { raise_error("You must explicitly enable fb_rename_function in the JIT " "(-v Eval.JitEnableRenameFunction=true)"); } } Func *fnew = Unit::lookupFunc(newNe); if (fnew && fnew != func) { // To match hphpc, we silently ignore functions defined in user code that // have the same name as a function defined in a separable extension if (!fnew->isIgnoreRedefinition()) { raise_error("Function already defined: %s", n3w->data()); } else { return false; } } oldNe->setCachedFunc(nullptr); if (UNLIKELY(newNe->m_cachedFuncOffset == 0)) { Transl::TargetCache::allocFixedFunction(newNe, false); } newNe->setCachedFunc(func); if (RuntimeOption::EvalJit) { Transl::TargetCache::invalidateForRename(old); } return true; }
void rename_function(const String& old_name, const String& new_name) { auto const old = old_name.get(); auto const n3w = new_name.get(); auto const oldNe = const_cast<NamedEntity*>(Unit::GetNamedEntity(old)); auto const newNe = const_cast<NamedEntity*>(Unit::GetNamedEntity(n3w)); Func* func = Unit::lookupFunc(oldNe); if (!func) { // It's the caller's responsibility to ensure that the old function // exists. not_reached(); } // Interceptable functions can be renamed even when // JitEnableRenameFunction is false. if (!(func->attrs() & AttrInterceptable)) { if (!RuntimeOption::EvalJitEnableRenameFunction) { // When EvalJitEnableRenameFunction is false, the translator may // wire non-AttrInterceptable Func*'s into the TC. Don't rename // functions. raise_error("fb_rename_function must be explicitly enabled" "(-v Eval.JitEnableRenameFunction=true)"); } } auto const fnew = Unit::lookupFunc(newNe); if (fnew && fnew != func) { // To match hphpc, we silently ignore functions defined in user code that // have the same name as a function defined in a separable extension if (!fnew->isAllowOverride()) { raise_error("Function already defined: %s", n3w->data()); } return; } always_assert(!RDS::isPersistentHandle(oldNe->getFuncHandle())); oldNe->setCachedFunc(nullptr); newNe->m_cachedFunc.bind(); newNe->setCachedFunc(func); if (RuntimeOption::EvalJit) { JIT::invalidateForRenameFunction(old); } }
void rename_function(const String& old_name, const String& new_name) { auto const old = old_name.get(); auto const n3w = new_name.get(); auto const oldNe = const_cast<NamedEntity*>(Unit::GetNamedEntity(old)); auto const newNe = const_cast<NamedEntity*>(Unit::GetNamedEntity(n3w)); Func* func = Unit::lookupFunc(oldNe); if (!func) { // It's the caller's responsibility to ensure that the old function // exists. not_reached(); } if (!(func->attrs() & AttrDynamicInvoke)) { // When EvalJitEnableRenameFunction is false, the translator may wire // non-DynamicInvoke Func*'s into the TC. Don't rename functions. if (RuntimeOption::EvalJit && !RuntimeOption::EvalJitEnableRenameFunction) { raise_error("You must explicitly enable fb_rename_function in the JIT " "(-v Eval.JitEnableRenameFunction=true)"); } } Func *fnew = Unit::lookupFunc(newNe); if (fnew && fnew != func) { // To match hphpc, we silently ignore functions defined in user code that // have the same name as a function defined in a separable extension if (!fnew->isAllowOverride()) { raise_error("Function already defined: %s", n3w->data()); } return; } oldNe->setCachedFunc(nullptr); newNe->m_cachedFunc.bind(); newNe->setCachedFunc(func); if (RuntimeOption::EvalJit) { JIT::invalidateForRenameFunction(old); } }
bool dumpTCAnnotation(const Func& func, TransKind transKind) { return RuntimeOption::EvalDumpTCAnnotationsForAllTrans || (transKind == TransKind::Optimize && (func.attrs() & AttrHot)); }