Exemplo n.º 1
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();
}