Ejemplo n.º 1
0
void CodeGenerator::cgCallHelper(Vout& v,
                                 CppCall call,
                                 const CallDest& dstInfo,
                                 SyncOptions sync,
                                 ArgGroup& args) {
  auto dstReg0 = dstInfo.reg0;
  DEBUG_ONLY auto dstReg1 = dstInfo.reg1;

  RegSet argRegs;
  for (size_t i = 0; i < args.numGpArgs(); i++) {
    auto const r = rarg(i);
    args.gpArg(i).setDstReg(r);
    argRegs.add(r);
  }
  always_assert_flog(
    args.numStackArgs() == 0,
    "Stack arguments not yet supported on ARM: `{}'",
    *m_curInst
  );
  shuffleArgs(v, args, call);

  auto syncPoint = emitCall(v, call, argRegs);
  if (RuntimeOption::HHProfServerEnabled || sync != SyncOptions::kNoSyncPoint) {
    recordHostCallSyncPoint(v, syncPoint);
  }

  auto* taken = m_curInst->taken();
  if (taken && taken->isCatch()) {
    assert_not_implemented(args.numStackArgs() == 0);
    auto next = v.makeBlock();
    v << hcunwind{syncPoint, {next, m_state.labels[taken]}};
    v = next;
  } else if (!m_curInst->is(Call, CallArray, ContEnter)) {
    v << hcnocatch{syncPoint};
  }

  switch (dstInfo.type) {
    case DestType::TV: CG_PUNT(cgCall-ReturnTV);
    case DestType::SIMD: CG_PUNT(cgCall-ReturnSIMD);
    case DestType::SSA:
    case DestType::Byte:
      assertx(dstReg1 == InvalidReg);
      v << copy{PhysReg(vixl::x0), dstReg0};
      break;
    case DestType::None:
      assertx(dstReg0 == InvalidReg && dstReg1 == InvalidReg);
      break;
    case DestType::Dbl:
      assertx(dstReg1 == InvalidReg);
      v << copy{PhysReg(vixl::d0), dstReg0};
      break;
  }
}
Ejemplo n.º 2
0
void cgCallHelper(Vout& v, IRLS& env, CallSpec call, const CallDest& dstInfo,
                  SyncOptions sync, const ArgGroup& args) {
    auto const inst = args.inst();
    jit::vector<Vreg> vIndRetArgs, vargs, vSimdArgs, vStkArgs;

    for (size_t i = 0; i < args.numIndRetArgs(); ++i) {
        prepareArg(args.indRetArg(i), v, vIndRetArgs);
    }
    for (size_t i = 0; i < args.numGpArgs(); ++i) {
        prepareArg(args.gpArg(i), v, vargs);
    }
    for (size_t i = 0; i < args.numSimdArgs(); ++i) {
        prepareArg(args.simdArg(i), v, vSimdArgs);
    }
    for (size_t i = 0; i < args.numStackArgs(); ++i) {
        prepareArg(args.stkArg(i), v, vStkArgs);
    }

    auto const syncFixup = [&] {
        if (RuntimeOption::HHProfEnabled || sync != SyncOptions::None) {
            // If we are profiling the heap, we always need to sync because regs need
            // to be correct during allocations no matter what.
            return makeFixup(inst->marker(), sync);
        }
        return Fixup{};
    }();

    Vlabel targets[2];
    bool nothrow = false;
    auto const taken = inst->taken();
    auto const do_catch = taken && taken->isCatch();

    if (do_catch) {
        always_assert_flog(
            inst->is(InterpOne) || sync != SyncOptions::None,
            "cgCallHelper called with None but inst has a catch block: {}\n",
            *inst
        );
        always_assert_flog(
            taken->catchMarker() == inst->marker(),
            "Catch trace doesn't match fixup:\n"
            "Instruction: {}\n"
            "Catch trace: {}\n"
            "Fixup      : {}\n",
            inst->toString(),
            taken->catchMarker().show(),
            inst->marker().show()
        );

        targets[0] = v.makeBlock();
        targets[1] = env.labels[taken];
    } else {
        // The current instruction doesn't have a catch block so it'd better not
        // throw.  Register a null catch trace to indicate this to the unwinder.
        nothrow = true;
    }

    VregList dstRegs;
    if (dstInfo.reg0.isValid()) {
        dstRegs.push_back(dstInfo.reg0);
        if (dstInfo.reg1.isValid()) {
            dstRegs.push_back(dstInfo.reg1);
        }
    }

    auto const argsId = v.makeVcallArgs({
        std::move(vargs),
        std::move(vSimdArgs),
        std::move(vStkArgs),
        std::move(vIndRetArgs)
    });
    auto const dstId = v.makeTuple(std::move(dstRegs));

    if (do_catch) {
        v << vinvoke{call, argsId, dstId, {targets[0], targets[1]},
                     syncFixup, dstInfo.type};
        v = targets[0];
    } else {
        v << vcall{call, argsId, dstId, syncFixup, dstInfo.type, nothrow};
    }
}