void emitCall(Vout& v, CallSpec target, RegSet args) { switch (target.kind()) { case CallSpec::Kind::Direct: v << call{static_cast<TCA>(target.address()), args}; return; case CallSpec::Kind::Smashable: v << calls{static_cast<TCA>(target.address()), args}; return; case CallSpec::Kind::ArrayVirt: { auto const addr = reinterpret_cast<intptr_t>(target.arrayTable()); auto const arrkind = v.makeReg(); v << loadzbl{rarg(0)[HeaderKindOffset], arrkind}; if (deltaFits(addr, sz::dword)) { v << callm{baseless(arrkind * 8 + addr), args}; } else { auto const base = v.makeReg(); v << ldimmq{addr, base}; v << callm{base[arrkind * 8], args}; } static_assert(sizeof(HeaderKind) == 1, ""); } return; case CallSpec::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; case CallSpec::Kind::Stub: v << callstub{target.stubAddr(), args}; return; } not_reached(); }
void emitCall(Vout& v, CallSpec target, RegSet args) { using K = CallSpec::Kind; switch (target.kind()) { case K::Direct: v << call{static_cast<TCA>(target.address()), args}; return; case K::Smashable: v << calls{static_cast<TCA>(target.address()), args}; return; case K::ArrayVirt: { auto const addr = reinterpret_cast<intptr_t>(target.arrayTable()); auto const arrkind = v.makeReg(); v << loadzbl{rarg(0)[HeaderKindOffset], arrkind}; if (deltaFits(addr, sz::dword)) { v << callm{baseless(arrkind * 8 + addr), args}; } else { auto const base = v.makeReg(); v << ldimmq{addr, base}; v << callm{base[arrkind * 8], args}; } static_assert(sizeof(HeaderKind) == 1, ""); } return; case K::Destructor: { auto dtor = lookupDestructor(v, target.reg()); v << callm{dtor, args}; } return; case K::Stub: v << callstub{target.stubAddr(), args}; return; } not_reached(); }