From afa6d733c1712bd2c0ce4fc43b21878704b96f4c Mon Sep 17 00:00:00 2001 From: Jordan DeLong Date: Sat, 25 May 2013 19:20:24 -0700 Subject: [PATCH] Some optimizations for LdClsCns Change LdClsCns to side exit when the type is uninitialized. On the exit path, do a LookupClsCns and ReqBindJmp for the next srckey so forward progress is still made. Add a predictionopts case for the common case of a LdClsCns; CheckInit being followed again by a CheckType---in this case, hoist all the checks into LdClsCns. --- hphp/doc/ir.specification | 27 +++-- hphp/runtime/vm/jit/codegen.cpp | 51 ++++---- hphp/runtime/vm/jit/extradata.h | 19 +++ hphp/runtime/vm/jit/hhbctranslator.cpp | 143 ++++++++++++----------- hphp/runtime/vm/jit/hhbctranslator.h | 48 +++++++- hphp/runtime/vm/jit/ir.cpp | 1 + hphp/runtime/vm/jit/ir.h | 4 +- hphp/runtime/vm/jit/predictionopts.cpp | 78 ++++++++++--- hphp/runtime/vm/jit/vectortranslator.cpp | 4 +- 9 files changed, 251 insertions(+), 124 deletions(-) diff --git a/hphp/doc/ir.specification b/hphp/doc/ir.specification index ce153b850..a34744160 100644 --- a/hphp/doc/ir.specification +++ b/hphp/doc/ir.specification @@ -757,16 +757,25 @@ D:Cls = LdClsCachedSafe S0:ConstStr [ -> L ] Loads the class whose name is S0 out of the target cache. If the class is not defined, returns null and optionally branches to L. -D:T = LdClsCns S0:ConstStr S1:ConstStr [ -> L ] +D:T = LdClsCns [ -> L ] - Loads the class constant named S0 from a class named S1 via the - target cache. This instruction should generally be followed by - CheckInit, unless we know the class is already loaded. If the - optional label L is specified and the loaded value's type does not - match T, this instruction does not load into D and transfers control - to L. The result may be uninitialized if the class is not defined. - Note that no decref of the result is necessary because class - constants will always be static. + Loads the named class constant for a class via the target cache. + This instruction should generally be followed by CheckInit, unless + we know the class is already loaded. + + If the optional label L is specified and the loaded value's type + does not match T, this instruction does not load into D and + transfers control to L. + + The result may be uninitialized if the class is not defined. Note + that no decref of the result is necessary because class constants + will always be static. + +D:T = LookupClsCns + + Load a class constant for a class via the target cache, invoking + autoload if it is not defined. This instruction may raise an + undefined constant error if autoload cannot define the constant. D:FuncCtx = LdClsMethodFCache S0:ConstStr S1:ConstStr S2:{Obj|Cls|Ctx} L:Label diff --git a/hphp/runtime/vm/jit/codegen.cpp b/hphp/runtime/vm/jit/codegen.cpp index e324db68f..d5a050df3 100644 --- a/hphp/runtime/vm/jit/codegen.cpp +++ b/hphp/runtime/vm/jit/codegen.cpp @@ -4643,43 +4643,36 @@ void CodeGenerator::cgLdCls(IRInstruction* inst) { ArgGroup(m_regs).imm(ch).ssa(className)); } -static StringData* fullConstName(SSATmp* cls, SSATmp* cnsName) { +static StringData* fullConstName(const StringData* cls, + const StringData* cnsName) { return StringData::GetStaticString( - Util::toLower(cls->getValStr()->data()) + "::" + - cnsName->getValStr()->data()); + Util::toLower(cls->data()) + "::" + cnsName->data() + ); } void CodeGenerator::cgLdClsCns(IRInstruction* inst) { - SSATmp* cnsName = inst->src(0); - SSATmp* cls = inst->src(1); - - StringData* fullName = fullConstName(cls, cnsName); - TargetCache::CacheHandle ch = TargetCache::allocClassConstant(fullName); - // note that we bail from the trace if the target cache entry is empty - // for this class constant or if the type assertion fails. - // TODO: handle the slow case helper call. + auto const extra = inst->extra(); + auto const fullName = fullConstName(extra->clsName, extra->cnsName); + auto const ch = TargetCache::allocClassConstant(fullName); cgLoad(rVmTl, ch, inst); } void CodeGenerator::cgLookupClsCns(IRInstruction* inst) { - SSATmp* cnsName = inst->src(0); - SSATmp* cls = inst->src(1); - - assert(inst->typeParam() == Type::Cell); - assert(cnsName->isConst() && cnsName->type() == Type::StaticStr); - assert(cls->isConst() && cls->type() == Type::StaticStr); - - StringData* fullName = fullConstName(cls, cnsName); - TargetCache::CacheHandle ch = TargetCache::allocClassConstant(fullName); - - ArgGroup args(m_regs); - args.addr(rVmTl, ch) - .immPtr(Unit::GetNamedEntity(cls->getValStr())) - .immPtr(cls->getValStr()) - .immPtr(cnsName->getValStr()); - - cgCallHelper(m_as, TCA(TargetCache::lookupClassConstantTv), - inst->dst(), kSyncPoint, args, DestType::TV); + auto const extra = inst->extra(); + auto const fullName = fullConstName(extra->clsName, extra->cnsName); + auto const ch = TargetCache::allocClassConstant(fullName); + cgCallHelper( + m_as, + TCA(TargetCache::lookupClassConstantTv), + inst->dst(), + kSyncPoint, + ArgGroup(m_regs) + .addr(rVmTl, ch) + .immPtr(Unit::GetNamedEntity(extra->clsName)) + .immPtr(extra->clsName) + .immPtr(extra->cnsName), + DestType::TV + ); } void CodeGenerator::cgLdCns(IRInstruction* inst) { diff --git a/hphp/runtime/vm/jit/extradata.h b/hphp/runtime/vm/jit/extradata.h index c9b9c73d9..49068086c 100644 --- a/hphp/runtime/vm/jit/extradata.h +++ b/hphp/runtime/vm/jit/extradata.h @@ -288,6 +288,23 @@ struct CallArrayData : IRExtraData { Offset pc, after; }; +/* + * Name of a class constant. + */ +struct ClsCnsName : IRExtraData { + explicit ClsCnsName(const StringData* cls, const StringData* cns) + : clsName(cls) + , cnsName(cns) + {} + + std::string show() const { + return folly::to(clsName->data(), "::", cnsName->data()); + } + + const StringData* clsName; + const StringData* cnsName; +}; + ////////////////////////////////////////////////////////////////////// #define X(op, data) \ @@ -333,6 +350,8 @@ X(ReqBindJmpNoIR, BCOffset); X(ReqRetranslateNoIR, BCOffset); X(InlineCreateCont, CreateContData); X(CallArray, CallArrayData); +X(LdClsCns, ClsCnsName); +X(LookupClsCns, ClsCnsName); X(ReqBindJmpGt, ReqBindJccData); X(ReqBindJmpGte, ReqBindJccData); X(ReqBindJmpLt, ReqBindJccData); diff --git a/hphp/runtime/vm/jit/hhbctranslator.cpp b/hphp/runtime/vm/jit/hhbctranslator.cpp index bd53a1168..cc1684f05 100644 --- a/hphp/runtime/vm/jit/hhbctranslator.cpp +++ b/hphp/runtime/vm/jit/hhbctranslator.cpp @@ -107,12 +107,6 @@ void HhbcTranslator::refineType(SSATmp* tmp, Type type) { // // FIXME: I think most of these shouldn't be possible still // (except LdStack?). - // - // XXX These are possible once we remove the inferred/predicted - // type from emitCGetProp etc in HhbcTranslator. We need to - // delete label on these instructions if this is due to an - // assertType and also handled LdClsCns. - // TODO(#2035446): fix this for LdClsCns assert(opc == LdLoc || opc == LdStack || opc == LdMem || opc == LdProp || opc == LdRef); @@ -272,7 +266,7 @@ IRInstruction* HhbcTranslator::makeMarker(Offset bcOff) { int32_t stackOff = m_tb->spOffset() + m_evalStack.numCells() - m_stackDeficit; - FTRACE(2, "emitMarker: bc {} sp {} fn {}\n", + FTRACE(2, "makeMarker: bc {} sp {} fn {}\n", bcOff, stackOff, curFunc()->fullName()->data()); MarkerData marker; @@ -1521,40 +1515,25 @@ void HhbcTranslator::emitCmp(Opcode opc) { gen(DecRef, src1); } -void HhbcTranslator::emitClsCnsD(int32_t cnsNameStrId, int32_t clsNameStrId) { - // This bytecode re-enters if there is no class with the given name - // and can throw a fatal error. - const StringData* cnsNameStr = lookupStringId(cnsNameStrId); - const StringData* clsNameStr = lookupStringId(clsNameStrId); - SSATmp* cnsNameTmp = cns(cnsNameStr); - SSATmp* clsNameTmp = cns(clsNameStr); - if (0) { - // TODO: 2068502 pick one of these two implementations and remove the other. - Trace* exitTrace = getExitSlowTrace(); - SSATmp* cns = gen(LdClsCns, Type::Cell, cnsNameTmp, clsNameTmp); - gen(CheckInit, exitTrace, cns); - push(cns); - } else { - // if-then-else - // todo: t2068502: refine the type? hhbc spec says null|bool|int|dbl|str - // and, str should always be static-str. - Type cnsType = Type::Cell; - SSATmp* c1 = gen(LdClsCns, cnsType, cnsNameTmp, clsNameTmp); - SSATmp* result = m_tb->cond(curFunc(), - [&] (Block* taken) { // branch - gen(CheckInit, taken, c1); - }, - [&] { // Next: LdClsCns hit in TC - return c1; - }, - [&] { // Taken: miss in TC, do lookup & init - m_tb->hint(Block::Unlikely); - return gen(LookupClsCns, getCatchTrace(), - cnsType, cnsNameTmp, clsNameTmp); - } - ); - push(result); - } +void HhbcTranslator::emitClsCnsD(int32_t cnsNameId, int32_t clsNameId) { + auto const clsCnsName = ClsCnsName { lookupStringId(clsNameId), + lookupStringId(cnsNameId) }; + + // If we have to side exit, do the target cache lookup before + // chaining to another Tracelet so forward progress still happens. + auto const sideExit = makeSideExit( + nextBcOff(), + [&] (Trace* t) { + return genFor(t, LookupClsCns, Type::Cell, clsCnsName); + } + ); + + // TODO: ideally we'd load Uncounted here without guarding, since we + // know this value has to be a non-refcounted type, but the register + // allocator doesn't understand what we mean right now. + auto const cns = gen(LdClsCns, clsCnsName, Type::Cell); + gen(CheckInit, sideExit, cns); + push(cns); } void HhbcTranslator::emitAKExists() { @@ -2822,7 +2801,7 @@ void HhbcTranslator::emitBindMem(SSATmp* ptr, SSATmp* src) { pushIncRef(src); gen(StMem, ptr, cns(0), src); if (isRefCounted(src) && src->type().canRunDtor()) { - Block* exitBlock = getExitTrace(nextSrcKey().offset())->front(); + Block* exitBlock = getExitTrace(nextBcOff())->front(); exitBlock->prepend(m_irFactory.gen(DecRef, prevValue)); gen(DecRefNZOrBranch, exitBlock, prevValue); } else { @@ -3076,7 +3055,7 @@ void HhbcTranslator::emitMod() { // will raise a notice and produce the boolean false. Punch out // here and resume after the Mod instruction; this should be rare. auto const exit = getExitTraceWarn( - nextSrcKey().offset(), + nextBcOff(), exitSpillValues, StringData::GetStaticString(Strings::DIVISION_BY_ZERO) ); @@ -3173,30 +3152,41 @@ Trace* HhbcTranslator::getExitTrace(Offset targetBcOff /* = -1 */) { Trace* HhbcTranslator::getExitTrace(Offset targetBcOff, std::vector& spillValues) { if (targetBcOff == -1) targetBcOff = bcOff(); - return getExitTraceImpl(targetBcOff, ExitFlag::None, spillValues, nullptr); + return getExitTraceImpl(targetBcOff, ExitFlag::None, spillValues, + CustomExit{}); } Trace* HhbcTranslator::getExitTraceWarn(Offset targetBcOff, std::vector& spillValues, const StringData* warning) { assert(targetBcOff != -1); - return getExitTraceImpl(targetBcOff, ExitFlag::None, spillValues, warning); + return getExitTraceImpl(targetBcOff, ExitFlag::None, spillValues, + [&](Trace* t) -> SSATmp* { + genFor(t, RaiseWarning, cns(warning)); + return nullptr; + } + ); +} + +template +Trace* HhbcTranslator::makeSideExit(Offset targetBcOff, ExitLambda exit) { + auto spillValues = peekSpillValues(); + return getExitTraceImpl(targetBcOff, + ExitFlag::DelayedMarker, + spillValues, + exit); } -/* - * Generates an exit trace which will continue execution without HHIR. - * This should be used in situations that HHIR cannot handle -- ideally - * only in slow paths. - */ Trace* HhbcTranslator::getExitSlowTrace() { auto spillValues = peekSpillValues(); - return getExitTraceImpl(bcOff(), ExitFlag::NoIR, spillValues, nullptr); + return getExitTraceImpl(bcOff(), ExitFlag::NoIR, spillValues, + CustomExit{}); } Trace* HhbcTranslator::getExitTraceImpl(Offset targetBcOff, ExitFlag flag, std::vector& stackValues, - const StringData* warning) { + const CustomExit& customFn) { auto const exit = m_tb->makeExitTrace(targetBcOff); MarkerData exitMarker; @@ -3204,25 +3194,46 @@ Trace* HhbcTranslator::getExitTraceImpl(Offset targetBcOff, exitMarker.stackOff = m_tb->spOffset() + stackValues.size() - m_stackDeficit; exitMarker.func = curFunc(); - genFor(exit, Marker, exitMarker); - if (warning) { - genFor(exit, RaiseWarning, cns(warning)); + MarkerData currentMarker; + currentMarker.bcOff = bcOff(); + currentMarker.func = curFunc(); + currentMarker.stackOff = m_tb->spOffset() + + m_evalStack.numCells() - m_stackDeficit; + + genFor(exit, Marker, + flag == ExitFlag::DelayedMarker ? currentMarker : exitMarker); + + // The value we use for stack is going to depend on whether we have + // to spillstack or what. + auto stack = m_tb->sp(); + + // TODO(#2404447) move this conditional to the simplifier? + if (m_stackDeficit != 0 || !stackValues.empty()) { + stackValues.insert( + stackValues.begin(), + { m_tb->sp(), cns(int64_t(m_stackDeficit)) } + ); + stack = genFor(exit, + SpillStack, std::make_pair(stackValues.size(), &stackValues[0]) + ); } - auto const stack = [&]{ - // TODO(#2404447) move this conditional to the simplifier? - if (m_stackDeficit != 0 || !stackValues.empty()) { - stackValues.insert( - stackValues.begin(), - { m_tb->sp(), cns(int64_t(m_stackDeficit)) } - ); - return genFor(exit, - SpillStack, std::make_pair(stackValues.size(), &stackValues[0]) + if (customFn) { + stack = genFor(exit, ExceptionBarrier, stack); + auto const customTmp = customFn(exit); + if (customTmp) { + SSATmp* spill2[] = { stack, cns(0), customTmp }; + stack = genFor(exit, + SpillStack, std::make_pair(sizeof spill2 / sizeof spill2[0], spill2) ); + exitMarker.stackOff += 1; } - return m_tb->sp(); - }(); + } + + if (flag == ExitFlag::DelayedMarker) { + genFor(exit, Marker, exitMarker); + } genFor(exit, SyncABIRegs, m_tb->fp(), stack); diff --git a/hphp/runtime/vm/jit/hhbctranslator.h b/hphp/runtime/vm/jit/hhbctranslator.h index e53fdbcb7..279f4cf3d 100644 --- a/hphp/runtime/vm/jit/hhbctranslator.h +++ b/hphp/runtime/vm/jit/hhbctranslator.h @@ -595,25 +595,63 @@ private: IRInstruction* makeMarker(Offset bcOff); void emitMarker(); - // Exit trace creation routines. +private: // Exit trace creation routines. Trace* getExitTrace(Offset targetBcOff = -1); Trace* getExitTrace(Offset targetBcOff, std::vector& spillValues); Trace* getExitTraceWarn(Offset targetBcOff, std::vector& spillValues, const StringData* warning); + + /* + * Create a custom side exit---that is, an exit that does some + * amount work before leaving the trace. + * + * The exit trace will spill things with a Marker for the current bytecode. + * + * Then it will do an ExceptionBarrier, followed by whatever is done + * by the CustomExit(Trace*) function. The custom exit may add + * instructions to the exit trace, and optionally may return an + * additional SSATmp* to spill on the stack. If there is no + * additional SSATmp*, it should return nullptr. + * + * TODO(#2447661): this should be way better than this, should allow + * using gen/push/spillStack/etc. + */ + template + Trace* makeSideExit(Offset targetBcOff, ExitLambda exit); + + /* + * Generates an exit trace which will continue execution without HHIR. + * This should be used in situations that HHIR cannot handle -- ideally + * only in slow paths. + */ Trace* getExitSlowTrace(); Trace* getCatchTrace(); + /* + * Implementation for the above. Takes spillValues, target offset, + * and a flag for whether to make a no-IR exit. + * + * Also takes a CustomExit(Trace*) function that may perform more + * operations and optionally return a single additional SSATmp* + * (otherwise nullptr) to spill on the stack before exiting. + */ enum class ExitFlag { None, NoIR, + + // DelayedMarker means to use the current instruction marker + // instead of one for targetBcOff. + DelayedMarker, }; + typedef std::function CustomExit; Trace* getExitTraceImpl(Offset targetBcOff, ExitFlag noIRExit, std::vector& spillValues, - const StringData* warning); + const CustomExit&); +private: /* * Accessors for the current function being compiled and its * class and unit. @@ -634,6 +672,12 @@ private: return srcKey; } + /* + * Return the bcOffset of the next instruction (whether it is in + * this tracelet or not). + */ + Offset nextBcOff() const { return nextSrcKey().offset(); } + /* * Helpers for resolving bytecode immediate ids. */ diff --git a/hphp/runtime/vm/jit/ir.cpp b/hphp/runtime/vm/jit/ir.cpp index cec423982..1c75f75f7 100644 --- a/hphp/runtime/vm/jit/ir.cpp +++ b/hphp/runtime/vm/jit/ir.cpp @@ -773,6 +773,7 @@ bool isRefCounted(SSATmp* tmp) { } IRInstruction* inst = tmp->inst(); Opcode opc = inst->op(); + // TODO(#2448005): we shouldn't have to list LdClsCns here. if (opc == DefConst || opc == LdConst || opc == LdClsCns) { return false; } diff --git a/hphp/runtime/vm/jit/ir.h b/hphp/runtime/vm/jit/ir.h index 1d052bb39..4ba017254 100644 --- a/hphp/runtime/vm/jit/ir.h +++ b/hphp/runtime/vm/jit/ir.h @@ -302,8 +302,8 @@ O(LdClsCached, D(Cls), CStr, C|E|N|Refs|Er|Mem) \ O(LdClsCachedSafe, D(Cls), CStr, C) \ O(LdClsCtx, D(Cls), S(Ctx), C) \ O(LdClsCctx, D(Cls), S(Cctx), C) \ -O(LdClsCns, DParam, CStr CStr, NF) \ -O(LookupClsCns, DParam, CStr CStr, E|Refs|Er|N|Mem) \ +O(LdClsCns, DParam, NA, NF) \ +O(LookupClsCns, DParam, NA, E|Refs|Er|N|Mem) \ O(LdCns, DParam, CStr, NF) \ O(LookupCns, DParam, CStr, E|Refs|Er|N|Mem) \ O(LdClsMethodCache, D(FuncCls), C(Str) \ diff --git a/hphp/runtime/vm/jit/predictionopts.cpp b/hphp/runtime/vm/jit/predictionopts.cpp index 913e45ca1..24b95c8d0 100644 --- a/hphp/runtime/vm/jit/predictionopts.cpp +++ b/hphp/runtime/vm/jit/predictionopts.cpp @@ -81,13 +81,14 @@ void optimizePredictions(Trace* const trace, IRFactory* const irFactory) { * generic LdMem/IncRef on the exit block, otherwise we do * type-specialized versions. */ - auto optLdMem = [&] (IRInstruction* checkType, IRInstruction* lastMarker) { + auto optLdMem = [&] (IRInstruction* checkType, + IRInstruction* lastMarker) -> bool { auto const incRef = checkType->src(0)->inst(); - if (incRef->op() != IncRef) return; + if (incRef->op() != IncRef) return false; auto const ldMem = incRef->src(0)->inst(); - if (ldMem->op() != LdMem) return; - if (ldMem->src(1)->getValInt() != 0) return; - if (!ldMem->typeParam().equals(Type::Cell)) return; + if (ldMem->op() != LdMem) return false; + if (ldMem->src(1)->getValInt() != 0) return false; + if (!ldMem->typeParam().equals(Type::Cell)) return false; FTRACE(5, "candidate: {}\n", ldMem->toString()); @@ -95,13 +96,13 @@ void optimizePredictions(Trace* const trace, IRFactory* const irFactory) { auto const exit = checkType->taken(); auto const specialized = checkType->block()->next(); - if (mainBlock != checkType->block()) return; - if (exit->numPreds() != 1) return; - if (exit->isMain()) return; + if (mainBlock != checkType->block()) return false; + if (exit->numPreds() != 1) return false; + if (exit->isMain()) return false; auto const sinkFirst = mainBlock->iteratorTo(ldMem); auto const sinkLast = mainBlock->iteratorTo(checkType); - if (!instructionsAreSinkable(sinkFirst, sinkLast)) return; + if (!instructionsAreSinkable(sinkFirst, sinkLast)) return false; FTRACE(5, "all sinkable\n"); auto const& rpoSort = sortedBlocks(); @@ -127,8 +128,8 @@ void optimizePredictions(Trace* const trace, IRFactory* const irFactory) { /* * Specialize the LdMem left on the main trace after cloning the - * generic version to the exit. We'll reflowTypes in a sec to get - * everything downstream specialized. + * generic version to the exit. We'll reflowTypes after we're + * done with all of this to get everything downstream specialized. */ ldMem->setTypeParam(checkType->typeParam()); @@ -148,7 +149,47 @@ void optimizePredictions(Trace* const trace, IRFactory* const irFactory) { specialized->insert(specialized->skipHeader(), irFactory->cloneInstruction(lastMarker)); - reflowTypes(specialized, rpoSort); + return true; + }; + + /* + * When we have a type prediction for a LdClsCns that is followed + * immediately by CheckInit, we can merge both checks into the + * LdClsCns and change it to exit to the same location the CheckInit + * would've exited to. + */ + auto optLdClsCns = [&] (IRInstruction* checkType, + IRInstruction* lastMarker) -> bool { + auto const ldClsCns = checkType->src(0)->inst(); + if (ldClsCns->op() != LdClsCns) return false; + if (ldClsCns->taken()) return false; + + auto const mainBlock = ldClsCns->block(); + auto const nextIt = boost::next(mainBlock->iteratorTo(ldClsCns)); + if (nextIt == mainBlock->end()) return false; + auto const checkInit = &*nextIt; + if (checkInit->op() != CheckInit) return false; + auto const exit = checkInit->taken(); + if (exit->numPreds() != 1) return false; + + FTRACE(5, "candidate: {}\n", ldClsCns->toString()); + + // Change the LdClsCns to do the check on the more refined type, + // exiting to the trace we would've exited to, and get rid of the + // CheckInit. + checkInit->setTaken(nullptr); + mainBlock->erase(mainBlock->iteratorTo(checkInit)); + ldClsCns->setTaken(exit); + ldClsCns->setTypeParam(checkType->typeParam()); + + // We don't need the checkType anymore. + irFactory->replace( + checkType, + Mov, + ldClsCns->dst() + ); + + return true; }; /* @@ -160,6 +201,7 @@ void optimizePredictions(Trace* const trace, IRFactory* const irFactory) { * visiting. */ if (!trace->isMain()) return; + bool needsReflow = false; for (Block* b : trace->blocks()) { IRInstruction* lastMarker = nullptr; for (auto& inst : *b) { @@ -171,11 +213,19 @@ void optimizePredictions(Trace* const trace, IRFactory* const irFactory) { if (inst.op() == CheckType && inst.src(0)->type().equals(Type::Cell)) { assert(lastMarker); - optLdMem(&inst, lastMarker); - break; + if (optLdMem(&inst, lastMarker) || + optLdClsCns(&inst, lastMarker)) { + needsReflow = true; + break; + } } } } + + if (needsReflow) { + auto& cfg = sortedBlocks(); + reflowTypes(cfg.front(), cfg); + } } ////////////////////////////////////////////////////////////////////// diff --git a/hphp/runtime/vm/jit/vectortranslator.cpp b/hphp/runtime/vm/jit/vectortranslator.cpp index f36157f33..0143d705f 100644 --- a/hphp/runtime/vm/jit/vectortranslator.cpp +++ b/hphp/runtime/vm/jit/vectortranslator.cpp @@ -2119,8 +2119,8 @@ void HhbcTranslator::VectorTranslator::emitMPost() { void HhbcTranslator::VectorTranslator::emitSideExits(SSATmp* catchSp, int nStack) { - const Offset nextOff = m_ht.nextSrcKey().offset(); - auto op = m_ni.mInstrOp(); + auto const nextOff = m_ht.nextBcOff(); + auto const op = m_ni.mInstrOp(); const bool isSetWithRef = op == OpSetWithRefLM || op == OpSetWithRefRM; if (m_failedSetTrace) {