Ejemplo n.º 1
0
void IRTranslator::translateAsyncSuspend(const NormalizedInstruction& i) {
  if (m_hhbcTrans.resumed()) {
    HHIR_EMIT(AsyncSuspendR, i.nextSk().offset());
  } else {
    HHIR_EMIT(AsyncSuspendE, i.nextSk().offset(), i.imm[0].u_IVA);
  }
}
Ejemplo n.º 2
0
void
IRTranslator::translateFCallArray(const NormalizedInstruction& i) {
  const Offset pcOffset = i.offset();
  SrcKey next = i.nextSk();
  const Offset after = next.offset();

  HHIR_EMIT(FCallArray, pcOffset, after,
            jit::callDestroysLocals(i, m_hhbcTrans.curFunc()));
}
Ejemplo n.º 3
0
void
IRTranslator::translateFCall(const NormalizedInstruction& i) {
  auto const numArgs = i.imm[0].u_IVA;

  const PC after = m_hhbcTrans.curUnit()->at(i.nextSk().offset());
  const Func* srcFunc = m_hhbcTrans.curFunc();
  Offset returnBcOffset =
    srcFunc->unit()->offsetOf(after - srcFunc->base());

  HHIR_EMIT(FCall, numArgs, returnBcOffset, i.funcd,
            jit::callDestroysLocals(i, m_hhbcTrans.curFunc()));
}
Ejemplo n.º 4
0
void
IRTranslator::translateFCall(const NormalizedInstruction& i) {
  auto const numArgs = i.imm[0].u_IVA;

  const PC after = m_hhbcTrans.curUnit()->at(i.nextSk().offset());
  const Func* srcFunc = m_hhbcTrans.curFunc();
  Offset returnBcOffset =
    srcFunc->unit()->offsetOf(after - srcFunc->base());

  /*
   * If we have a calleeTrace, we're going to see if we should inline
   * the call.
   */
  if (i.calleeTrace) {
    if (!i.calleeTrace->m_inliningFailed) {
      assert(shouldIRInline(m_hhbcTrans.curFunc(), i.funcd, *i.calleeTrace));

      m_hhbcTrans.beginInlining(numArgs, i.funcd, returnBcOffset);
      static const bool shapeStats = Stats::enabledAny() &&
                                     getenv("HHVM_STATS_INLINESHAPE");
      if (shapeStats) {
        m_hhbcTrans.profileInlineFunctionShape(traceletShape(*i.calleeTrace));
      }

      for (auto* ni = i.calleeTrace->m_instrStream.first; ni; ni = ni->next) {
        if (isAlwaysNop(ni->op())) {
          // This might not be necessary---but for now it's preserving
          // side effects of the call to readMetaData that used to
          // exist here.
          ni->noOp = true;
        }
        translateInstr(*ni);
      }
      return;
    }

    static const auto enabled = Stats::enabledAny() &&
                                getenv("HHVM_STATS_FAILEDINL");
    if (enabled) {
      m_hhbcTrans.profileFunctionEntry("FailedCandidate");
      m_hhbcTrans.profileFailedInlShape(traceletShape(*i.calleeTrace));
    }
  }

  HHIR_EMIT(FCall, numArgs, returnBcOffset, i.funcd,
            JIT::callDestroysLocals(i, m_hhbcTrans.curFunc()));
}
Ejemplo n.º 5
0
void
IRTranslator::translateFCall(const NormalizedInstruction& i) {
  auto const numArgs = i.imm[0].u_IVA;

  const PC after = m_hhbcTrans.curUnit()->at(i.nextSk().offset());
  const Func* srcFunc = m_hhbcTrans.curFunc();
  Offset returnBcOffset =
    srcFunc->unit()->offsetOf(after - srcFunc->base());

  /*
   * If we have a calleeTrace, we're going to see if we should inline
   * the call.
   */
  if (i.calleeTrace) {
    if (!i.calleeTrace->m_inliningFailed) {
      assert(shouldIRInline(m_hhbcTrans.curFunc(), i.funcd, *i.calleeTrace));

      m_hhbcTrans.beginInlining(numArgs, i.funcd, returnBcOffset);
      static const bool shapeStats = Stats::enabledAny() &&
                                     getenv("HHVM_STATS_INLINESHAPE");
      if (shapeStats) {
        m_hhbcTrans.profileInlineFunctionShape(traceletShape(*i.calleeTrace));
      }

      Unit::MetaHandle metaHand;
      for (auto* ni = i.calleeTrace->m_instrStream.first;
           ni; ni = ni->next) {
        readMetaData(metaHand, *ni, m_hhbcTrans, false, MetaMode::Legacy);
        translateInstr(*ni);
      }
      return;
    }

    static const auto enabled = Stats::enabledAny() &&
                                getenv("HHVM_STATS_FAILEDINL");
    if (enabled) {
      m_hhbcTrans.profileFunctionEntry("FailedCandidate");
      m_hhbcTrans.profileFailedInlShape(traceletShape(*i.calleeTrace));
    }
  }

  HHIR_EMIT(FCall, numArgs, returnBcOffset, i.funcd,
            JIT::callDestroysLocals(i, m_hhbcTrans.curFunc()));
}
Ejemplo n.º 6
0
bool
IRTranslator::tryTranslateSingletonInline(const NormalizedInstruction& i,
                                          const Func* funcd) {
  using Atom = BCPattern::Atom;
  using Captures = BCPattern::CaptureVec;

  if (!funcd) return false;

  // Make sure we have an acceptable FPush and non-null callee.
  assert(i.op() == Op::FPushFuncD ||
         i.op() == Op::FPushClsMethodD);

  auto fcall = i.nextSk();

  // Check if the next instruction is an acceptable FCall.
  if ((fcall.op() != Op::FCall && fcall.op() != Op::FCallD) ||
      funcd->isResumable() || funcd->isReturnRef()) {
    return false;
  }

  // First, check for the static local singleton pattern...

  // Lambda to check if CGetL and StaticLocInit refer to the same local.
  auto has_same_local = [] (PC pc, const Captures& captures) {
    if (captures.size() == 0) return false;

    auto cgetl = (const Op*)pc;
    auto sli = (const Op*)captures[0];

    assert(*cgetl == Op::CGetL);
    assert(*sli == Op::StaticLocInit);

    return (getImm(sli, 0).u_IVA == getImm(cgetl, 0).u_IVA);
  };

  auto cgetl = Atom(Op::CGetL).onlyif(has_same_local);
  auto retc  = Atom(Op::RetC);

  // Look for a static local singleton pattern.
  auto result = BCPattern {
    Atom(Op::Null),
    Atom(Op::StaticLocInit).capture(),
    Atom(Op::IsTypeL),
    Atom::alt(
      Atom(Op::JmpZ).taken({cgetl, retc}),
      Atom::seq(Atom(Op::JmpNZ), cgetl, retc)
    )
  }.ignore(
    {Op::AssertRATL, Op::AssertRATStk}
  ).matchAnchored(funcd);

  if (result.found()) {
    try {
      hhbcTrans().emitSingletonSLoc(
        funcd,
        (const Op*)result.getCapture(0)
      );
    } catch (const FailedIRGen& e) {
      return false;
    } catch (const FailedCodeGen& e) {
      return false;
    }
    TRACE(1, "[singleton-sloc] %s <- %s\n",
        funcd->fullName()->data(),
        fcall.func()->fullName()->data());
    return true;
  }

  // Not found; check for the static property pattern.

  // Factory for String atoms that are required to match another captured
  // String opcode.
  auto same_string_as = [&] (int i) {
    return Atom(Op::String).onlyif([=] (PC pc, const Captures& captures) {
      auto string1 = (const Op*)pc;
      auto string2 = (const Op*)captures[i];
      assert(*string1 == Op::String);
      assert(*string2 == Op::String);

      auto const unit = funcd->unit();
      auto sd1 = unit->lookupLitstrId(getImmPtr(string1, 0)->u_SA);
      auto sd2 = unit->lookupLitstrId(getImmPtr(string2, 0)->u_SA);

      return (sd1 && sd1 == sd2);
    });
  };

  auto stringProp = same_string_as(0);
  auto stringCls  = same_string_as(1);
  auto agetc = Atom(Op::AGetC);
  auto cgets = Atom(Op::CGetS);

  // Look for a class static singleton pattern.
  result = BCPattern {
    Atom(Op::String).capture(),
    Atom(Op::String).capture(),
    Atom(Op::AGetC),
    Atom(Op::CGetS),
    Atom(Op::IsTypeC),
    Atom::alt(
      Atom(Op::JmpZ).taken({stringProp, stringCls, agetc, cgets, retc}),
      Atom::seq(Atom(Op::JmpNZ), stringProp, stringCls, agetc, cgets, retc)
    )
  }.ignore(
    {Op::AssertRATL, Op::AssertRATStk}
  ).matchAnchored(funcd);

  if (result.found()) {
    try {
      hhbcTrans().emitSingletonSProp(
        funcd,
        (const Op*)result.getCapture(1),
        (const Op*)result.getCapture(0)
      );
    } catch (const FailedIRGen& e) {
      return false;
    } catch (const FailedCodeGen& e) {
      return false;
    }
    TRACE(1, "[singleton-sprop] %s <- %s\n",
        funcd->fullName()->data(),
        fcall.func()->fullName()->data());
    return true;
  }

  return false;
}
Ejemplo n.º 7
0
void IRTranslator::translateAwait(const NormalizedInstruction& i) {
  HHIR_EMIT(Await, i.nextSk().offset(), i.imm[0].u_IVA);
}
Ejemplo n.º 8
0
void IRTranslator::translateYieldK(const NormalizedInstruction& i) {
  HHIR_EMIT(YieldK, i.nextSk().offset());
}
Ejemplo n.º 9
0
void IRTranslator::translateContEnter(const NormalizedInstruction& i) {
  HHIR_EMIT(ContEnter, i.nextSk().offset());
}