Example #1
0
TCA emitCall(vixl::MacroAssembler& a, CppCall call) {
  switch (call.kind()) {
  case CppCall::Kind::Direct:
    a. Mov  (rHostCallReg, reinterpret_cast<intptr_t>(call.address()));
    break;
  case CppCall::Kind::Virtual:
    a. Ldr  (rHostCallReg, argReg(0)[0]);
    a. Ldr  (rHostCallReg, rHostCallReg[call.vtableOffset()]);
    break;
  case CppCall::Kind::IndirectReg:
  case CppCall::Kind::IndirectVreg:
    // call indirect currently not implemented. It'll be something like
    // a.Br(x2a(call.getReg()))
    not_implemented();
    always_assert(0);
    break;
  case CppCall::Kind::ArrayVirt:
  case CppCall::Kind::Destructor:
    not_implemented();
    always_assert(0);
    break;
  }

  using namespace vixl;
  auto fixupAddr = a.frontier();
  a.   HostCall(6);

  // Note that the fixup address for a HostCall is directly *before* the
  // HostCall, not after as in the native case. This is because, in simulation
  // mode we look at the simulator's PC at the time the fixup is invoked, and it
  // will still be pointing to the HostCall; it's not advanced past it until the
  // host call returns. In the native case, by contrast, we'll be looking at
  // return addresses, which point after the call.
  return fixupAddr;
}
Example #2
0
Vpoint emitCall(Vout& v, CppCall call, RegSet args) {
  PhysReg arg0(argReg(0));
  PhysReg rHostCall(rHostCallReg);
  switch (call.kind()) {
  case CppCall::Kind::Direct:
    v << ldimm{reinterpret_cast<intptr_t>(call.address()), rHostCall};
    break;
  case CppCall::Kind::Virtual:
    v << loadq{arg0[0], rHostCall};
    v << loadq{rHostCall[call.vtableOffset()], rHostCall};
    break;
  case CppCall::Kind::IndirectReg:
  case CppCall::Kind::IndirectVreg:
    // call indirect currently not implemented. It'll be something like
    // a.Br(x2a(call.getReg()))
    not_implemented();
    always_assert(0);
    break;
  case CppCall::Kind::ArrayVirt:
  case CppCall::Kind::Destructor:
    not_implemented();
    always_assert(0);
    break;
  }
  uint8_t argc = args.size();
  args.add(rHostCall);
  auto fixupAddr = v.makePoint();
  v << hostcall{args, argc, fixupAddr};
  return fixupAddr;
}
Example #3
0
void emitCall(Vout& v, CppCall target, RegSet args) {
  switch (target.kind()) {
    case CppCall::Kind::Direct:
      v << call{static_cast<TCA>(target.address()), args};
      return;
    case CppCall::Kind::Virtual:
      // Virtual call.  Load method's address from proper offset off of object in
      // rdi, using rax as scratch.
      v << load{*reg::rdi, reg::rax};
      v << callm{reg::rax[target.vtableOffset()], args};
      return;
    case CppCall::Kind::ArrayVirt: {
      auto const addr = reinterpret_cast<intptr_t>(target.arrayTable());
      v << loadzbl{reg::rdi[HeaderKindOffset], reg::eax};
      if (deltaFits(addr, sz::dword)) {
        v << callm{baseless(reg::rax * 8 + addr), args};
      } else {
        auto const base = v.makeReg();
        v << ldimmq{addr, base};
        v << callm{base[reg::rax * 8], args};
      }
      static_assert(sizeof(HeaderKind) == 1, "");
      return;
    }
    case CppCall::Kind::Destructor:
      // this movzbq is only needed because callers aren't required to
      // zero-extend the type.
      auto zextType = v.makeReg();
      v << movzbq{target.reg(), zextType};
      auto dtor_ptr = lookupDestructor(v, zextType);
      v << callm{dtor_ptr, args};
      return;
  }
  not_reached();
}