diff --git a/hphp/runtime/vm/translator/hopt/codegen.cpp b/hphp/runtime/vm/translator/hopt/codegen.cpp index 3dfbc82bb..38bcd5250 100644 --- a/hphp/runtime/vm/translator/hopt/codegen.cpp +++ b/hphp/runtime/vm/translator/hopt/codegen.cpp @@ -4255,6 +4255,59 @@ void CodeGenerator::cgLookupClsCns(IRInstruction* inst) { inst->getDst(), kSyncPoint, args, DestType::TV); } +void CodeGenerator::cgLdCns(IRInstruction* inst) { + const StringData* cnsName = inst->getSrc(0)->getValStr(); + + TargetCache::CacheHandle ch = StringData::DefCnsHandle(cnsName, false); + // Has an unlikely branch to a LookupCns + cgLoad(rVmTl, ch, inst); +} + +static TypedValue lookupCnsHelper(const TypedValue* tv, StringData* nm) { + assert(tv->m_type == KindOfUninit); + TypedValue *cns = nullptr; + TypedValue c1; + if (UNLIKELY(tv->m_data.pref != nullptr)) { + ClassInfo::ConstantInfo* ci = + (ClassInfo::ConstantInfo*)(void*)tv->m_data.pref; + cns = const_cast(ci->getDeferredValue()).asTypedValue(); + tvReadCell(cns, &c1); + } else { + if (UNLIKELY(TargetCache::s_constants != nullptr)) { + cns = TargetCache::s_constants->HphpArray::nvGet(nm); + } + if (!cns) { + cns = Unit::loadCns(const_cast(nm)); + } + if (UNLIKELY(!cns)) { + raise_notice(Strings::UNDEFINED_CONSTANT, nm->data(), nm->data()); + c1.m_data.pstr = const_cast(nm); + c1.m_type = KindOfStaticString; + } else { + c1.m_type = cns->m_type; + c1.m_data = cns->m_data; + } + } + return c1; +} + +void CodeGenerator::cgLookupCns(IRInstruction* inst) { + SSATmp* cnsNameTmp = inst->getSrc(0); + + assert(inst->getTypeParam() == Type::Cell); + assert(cnsNameTmp->isConst() && cnsNameTmp->getType() == Type::StaticStr); + + const StringData* cnsName = cnsNameTmp->getValStr(); + TargetCache::CacheHandle ch = StringData::DefCnsHandle(cnsName, false); + + ArgGroup args; + args.addr(rVmTl, ch) + .immPtr(cnsName); + + cgCallHelper(m_as, TCA(lookupCnsHelper), + inst->getDst(), kSyncPoint, args, DestType::TV); +} + HOT_FUNC_VM static inline int64_t ak_exist_string_helper(StringData* key, ArrayData* arr) { int64_t n; diff --git a/hphp/runtime/vm/translator/hopt/hhbctranslator.cpp b/hphp/runtime/vm/translator/hopt/hhbctranslator.cpp index c00aabe50..cd6332c4f 100644 --- a/hphp/runtime/vm/translator/hopt/hhbctranslator.cpp +++ b/hphp/runtime/vm/translator/hopt/hhbctranslator.cpp @@ -341,7 +341,51 @@ void HhbcTranslator::emitColAddNewElemC() { } void HhbcTranslator::emitCns(uint32_t id) { - emitInterpOneOrPunt(Type::Cell, 0); + StringData* name = curUnit()->lookupLitstrId(id); + SSATmp* cnsNameTmp = m_tb->genDefConst(name); + const TypedValue* tv = Unit::lookupPersistentCns(name); + SSATmp* result = nullptr; + Type cnsType = Type::Cell; + if (tv) { + switch (tv->m_type) { + case KindOfUninit: + // a dynamic system constant. always a slow lookup + result = m_tb->gen(LookupCns, cnsType, cnsNameTmp); + break; + case KindOfBoolean: + result = m_tb->genDefConst((bool)tv->m_data.num); + break; + case KindOfInt64: + result = m_tb->genDefConst(tv->m_data.num); + break; + case KindOfDouble: + result = m_tb->genDefConst(tv->m_data.dbl); + break; + case KindOfString: + case KindOfStaticString: + result = m_tb->genDefConst(tv->m_data.pstr); + break; + default: + not_reached(); + } + } else { + spillStack(); // do this on main trace so we update stack tracking once. + SSATmp* c1 = m_tb->gen(LdCns, cnsType, cnsNameTmp); + result = m_tb->cond( + getCurFunc(), + [&] (Block* taken) { // branch + m_tb->gen(CheckInit, taken, c1); + }, + [&] { // Next: LdCns hit in TC + return c1; + }, + [&] { // Taken: miss in TC, do lookup & init + m_tb->hint(Block::Unlikely); + return m_tb->gen(LookupCns, cnsType, cnsNameTmp); + } + ); + } + push(result); } void HhbcTranslator::emitDefCns(uint32_t id) { diff --git a/hphp/runtime/vm/translator/hopt/ir.h b/hphp/runtime/vm/translator/hopt/ir.h index 01bfb0301..0089b80a8 100644 --- a/hphp/runtime/vm/translator/hopt/ir.h +++ b/hphp/runtime/vm/translator/hopt/ir.h @@ -277,6 +277,8 @@ O(LdClsCtx, D(Cls), S(Ctx), C) \ O(LdClsCctx, D(Cls), S(Cctx), C) \ O(LdClsCns, DParam, CStr CStr, C) \ O(LookupClsCns, DParam, CStr CStr, E|Refs|Er|N|Mem) \ +O(LdCns, DParam, CStr, C) \ +O(LookupCns, DParam, CStr, E|Refs|Er|N|Mem) \ O(LdClsMethodCache, D(FuncCls), SUnk, N|C|E|Refs|Er|Mem) \ O(LdClsMethodFCache, D(FuncCtx), C(Cls) CStr S(Obj,Cls,Ctx), N|C|E|Er) \ O(GetCtxFwdCall, D(Ctx), S(Ctx) S(Func), C) \