void emitCall(Asm& a, CppCall call) { if (call.isDirect()) { return emitCall(a, (TCA)call.getAddress()); } else if (call.isVirtual()) { // Virtual call. // Load method's address from proper offset off of object in rdi, // using rax as scratch. a. loadq (*rdi, rax); a. call (rax[call.getOffset()]); } else { assert(call.isIndirect()); a. call (call.getReg()); } }
TCA emitCall(vixl::MacroAssembler& a, CppCall call) { if (call.isDirect()) { a. Mov (rHostCallReg, reinterpret_cast<intptr_t>(call.getAddress())); } else if (call.isVirtual()) { a. Ldr (rHostCallReg, argReg(0)[0]); a. Ldr (rHostCallReg, rHostCallReg[call.getOffset()]); } else { // call indirect currently not implemented. It'll be somthing like // a.Br(x2a(call.getReg())) not_implemented(); } 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; }