void endRegion(IRGS& env) { auto const curSk = curSrcKey(env); if (!instrAllowsFallThru(curSk.op())) return; // nothing to do here auto const nextSk = curSk.advanced(curUnit(env)); endRegion(env, nextSk); }
void emitCGetL(HTS& env, int32_t id) { auto const ldrefExit = makeExit(env); auto const ldPMExit = makePseudoMainExit(env); // Mimic hhbc guard relaxation for now. auto cat = curSrcKey(env).op() == OpFPassL ? DataTypeSpecific : DataTypeCountnessInit; pushIncRef(env, ldLocInnerWarn(env, id, ldrefExit, ldPMExit, cat)); }
void emitSSwitch(HTS& env, const ImmVector& iv) { const int numCases = iv.size() - 1; /* * We use a fast path translation with a hashtable if none of the * cases are numeric strings and if the input is actually a string. * * Otherwise we do a linear search through the cases calling string * conversion routines. */ const bool fastPath = topC(env)->isA(Type::Str) && std::none_of(iv.strvec(), iv.strvec() + numCases, [&](const StrVecItem& item) { return curUnit(env)->lookupLitstrId(item.str)->isNumeric(); } ); auto const testVal = popC(env); std::vector<LdSSwitchData::Elm> cases(numCases); for (int i = 0; i < numCases; ++i) { auto const& kv = iv.strvec()[i]; cases[i].str = curUnit(env)->lookupLitstrId(kv.str); cases[i].dest = SrcKey{curSrcKey(env), bcOff(env) + kv.dest}; } LdSSwitchData data; data.numCases = numCases; data.cases = &cases[0]; data.defaultSk = SrcKey{curSrcKey(env), bcOff(env) + iv.strvec()[iv.size() - 1].dest}; auto const dest = gen(env, fastPath ? LdSSwitchDestFast : LdSSwitchDestSlow, data, testVal); gen(env, DecRef, testVal); gen(env, AdjustSP, IRSPOffsetData { offsetFromIRSP(env, BCSPOffset{0}) }, sp(env)); gen(env, JmpSSwitchDest, dest, sp(env)); }
Block* makeExitOpt(HTS& env, TransID transId) { assert(!isInlining(env)); auto const targetBcOff = bcOff(env); auto const exit = env.unit.defBlock(Block::Hint::Unlikely); BlockPusher blockPusher(*env.irb, makeMarker(env, targetBcOff), exit); spillStack(env); gen(env, AdjustSP, StackOffset { offsetFromSP(env, 0) }, sp(env)); gen(env, ReqRetranslateOpt, ReqRetransOptData{transId, SrcKey{curSrcKey(env), targetBcOff}}, sp(env)); return exit; }
Block* makeExitOpt(IRGS& env, TransID transId) { assertx(!isInlining(env)); auto const targetBcOff = bcOff(env); auto const exit = defBlock(env, Block::Hint::Unlikely); BlockPusher blockPusher(*env.irb, makeMarker(env, targetBcOff), exit); auto const data = ReqRetranslateOptData { transId, SrcKey { curSrcKey(env), targetBcOff }, bcSPOffset(env) }; gen(env, ReqRetranslateOpt, data, sp(env), fp(env)); return exit; }
void emitSwitch(HTS& env, const ImmVector& iv, int64_t base, int32_t bounded) { int nTargets = bounded ? iv.size() - 2 : iv.size(); SSATmp* const switchVal = popC(env); Type type = switchVal->type(); assertx(IMPLIES(!(type <= (Type::Int | Type::Null)), bounded)); assertx(IMPLIES(bounded, iv.size() > 2)); SSATmp* index; SSATmp* ssabase = cns(env, base); SSATmp* ssatargets = cns(env, nTargets); Offset defaultOff = bcOff(env) + iv.vec32()[iv.size() - 1]; Offset zeroOff = 0; if (base <= 0 && (base + nTargets) > 0) { zeroOff = bcOff(env) + iv.vec32()[0 - base]; } else { zeroOff = defaultOff; } if (type <= Type::Null) { gen(env, Jmp, makeExit(env, zeroOff)); return; } if (type <= Type::Bool) { Offset nonZeroOff = bcOff(env) + iv.vec32()[iv.size() - 2]; gen(env, JmpNZero, makeExit(env, nonZeroOff), switchVal); gen(env, Jmp, makeExit(env, zeroOff)); return; } if (type <= Type::Int) { // No special treatment needed index = switchVal; } else if (type <= Type::Dbl) { // switch(Double|String|Obj)Helper do bounds-checking for us, so // we need to make sure the default case is in the jump table, // and don't emit our own bounds-checking code bounded = false; index = gen(env, LdSwitchDblIndex, switchVal, ssabase, ssatargets); } else if (type <= Type::Str) { bounded = false; index = gen(env, LdSwitchStrIndex, switchVal, ssabase, ssatargets); } else if (type <= Type::Obj) { // switchObjHelper can throw exceptions and reenter the VM so we use the // catch block here. bounded = false; index = gen(env, LdSwitchObjIndex, switchVal, ssabase, ssatargets); } else if (type <= Type::Arr) { gen(env, DecRef, switchVal); gen(env, Jmp, makeExit(env, defaultOff)); return; } else { PUNT(Switch-UnknownType); } std::vector<SrcKey> targets(iv.size()); for (int i = 0; i < iv.size(); i++) { targets[i] = SrcKey{curSrcKey(env), bcOff(env) + iv.vec32()[i]}; } JmpSwitchData data; data.base = base; data.bounded = bounded; data.cases = iv.size(); data.defaultSk = {curSrcKey(env), defaultOff}; data.targets = &targets[0]; spillStack(env); gen(env, AdjustSP, IRSPOffsetData { offsetFromIRSP(env, BCSPOffset{0}) }, sp(env)); gen(env, JmpSwitchDest, data, index, sp(env)); }
void endRegion(HTS& env) { auto const nextSk = curSrcKey(env).advanced(curUnit(env)); endRegion(env, nextSk.offset()); }