Fixing tail calls in the jit.
This commit is contained in:
parent
0d88e83daa
commit
5309356908
|
@ -245,17 +245,30 @@ void IssueCall(X64Emitter& e, FunctionInfo* symbol_info, uint32_t flags) {
|
||||||
|
|
||||||
// Actually jump/call to rax.
|
// Actually jump/call to rax.
|
||||||
if (flags & CALL_TAIL) {
|
if (flags & CALL_TAIL) {
|
||||||
|
// Pass the callers return address over.
|
||||||
|
e.mov(e.rdx, e.qword[e.rsp + StackLayout::GUEST_RET_ADDR]);
|
||||||
|
|
||||||
e.add(e.rsp, (uint32_t)e.stack_size());
|
e.add(e.rsp, (uint32_t)e.stack_size());
|
||||||
e.jmp(e.rax);
|
e.jmp(e.rax);
|
||||||
} else {
|
} else {
|
||||||
|
// Return address is from the previous SET_RETURN_ADDRESS.
|
||||||
|
e.mov(e.rdx, e.qword[e.rsp + StackLayout::GUEST_CALL_RET_ADDR]);
|
||||||
|
|
||||||
e.call(e.rax);
|
e.call(e.rax);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void IssueCallIndirect(X64Emitter& e, Value* target, uint32_t flags) {
|
void IssueCallIndirect(X64Emitter& e, Value* target, uint32_t flags) {
|
||||||
// Resolve address to the function to call and store in rax.
|
|
||||||
// TODO(benvanik): caching/etc. For now this makes debugging easier.
|
|
||||||
Reg64 r;
|
Reg64 r;
|
||||||
e.BeginOp(target, r, 0);
|
e.BeginOp(target, r, 0);
|
||||||
|
|
||||||
|
// Check if return.
|
||||||
|
if (flags & CALL_POSSIBLE_RETURN) {
|
||||||
|
e.cmp(r.cvt32(), e.dword[e.rsp + StackLayout::GUEST_RET_ADDR]);
|
||||||
|
e.je("epilog", CodeGenerator::T_NEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve address to the function to call and store in rax.
|
||||||
|
// TODO(benvanik): caching/etc. For now this makes debugging easier.
|
||||||
if (r != e.rdx) {
|
if (r != e.rdx) {
|
||||||
e.mov(e.rdx, r);
|
e.mov(e.rdx, r);
|
||||||
}
|
}
|
||||||
|
@ -264,9 +277,15 @@ void IssueCallIndirect(X64Emitter& e, Value* target, uint32_t flags) {
|
||||||
|
|
||||||
// Actually jump/call to rax.
|
// Actually jump/call to rax.
|
||||||
if (flags & CALL_TAIL) {
|
if (flags & CALL_TAIL) {
|
||||||
|
// Pass the callers return address over.
|
||||||
|
e.mov(e.rdx, e.qword[e.rsp + StackLayout::GUEST_RET_ADDR]);
|
||||||
|
|
||||||
e.add(e.rsp, (uint32_t)e.stack_size());
|
e.add(e.rsp, (uint32_t)e.stack_size());
|
||||||
e.jmp(e.rax);
|
e.jmp(e.rax);
|
||||||
} else {
|
} else {
|
||||||
|
// Return address is from the previous SET_RETURN_ADDRESS.
|
||||||
|
e.mov(e.rdx, e.qword[e.rsp + StackLayout::GUEST_CALL_RET_ADDR]);
|
||||||
|
|
||||||
e.call(e.rax);
|
e.call(e.rax);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -434,6 +453,14 @@ table->AddSequence(OPCODE_RETURN_TRUE, [](X64Emitter& e, Instr*& i) {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
table->AddSequence(OPCODE_SET_RETURN_ADDRESS, [](X64Emitter& e, Instr*& i) {
|
||||||
|
XEASSERT(i->src1.value->IsConstant());
|
||||||
|
e.mov(e.qword[e.rsp + StackLayout::GUEST_CALL_RET_ADDR],
|
||||||
|
i->src1.value->AsUint64());
|
||||||
|
i = e.Advance(i);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// Branches
|
// Branches
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
|
@ -29,10 +29,12 @@ namespace lowering {
|
||||||
#define DFLUSH()
|
#define DFLUSH()
|
||||||
#define DPRINT
|
#define DPRINT
|
||||||
|
|
||||||
|
#define TARGET_THREAD 1
|
||||||
|
|
||||||
#define IFLUSH() fflush(stdout)
|
#define IFLUSH() fflush(stdout)
|
||||||
#define IPRINT if (thread_state->thread_id() == 1) printf
|
#define IPRINT if (thread_state->thread_id() == TARGET_THREAD) printf
|
||||||
#define DFLUSH() fflush(stdout)
|
#define DFLUSH() fflush(stdout)
|
||||||
#define DPRINT DFLUSH(); if (thread_state->thread_id() == 1) printf
|
#define DPRINT DFLUSH(); if (thread_state->thread_id() == TARGET_THREAD) printf
|
||||||
|
|
||||||
|
|
||||||
void TraceString(void* raw_context, const char* str) {
|
void TraceString(void* raw_context, const char* str) {
|
||||||
|
|
|
@ -158,6 +158,10 @@ int X64Emitter::Emit(HIRBuilder* builder, size_t& out_stack_size) {
|
||||||
if (emit_prolog) {
|
if (emit_prolog) {
|
||||||
sub(rsp, (uint32_t)stack_size);
|
sub(rsp, (uint32_t)stack_size);
|
||||||
mov(qword[rsp + StackLayout::GUEST_RCX_HOME], rcx);
|
mov(qword[rsp + StackLayout::GUEST_RCX_HOME], rcx);
|
||||||
|
mov(qword[rsp + StackLayout::GUEST_RET_ADDR], rdx);
|
||||||
|
mov(qword[rsp + StackLayout::GUEST_CALL_RET_ADDR], 0);
|
||||||
|
// ReloadRDX:
|
||||||
|
mov(rdx, qword[rcx + 8]); // membase
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lowering_table = backend_->lowering_table();
|
auto lowering_table = backend_->lowering_table();
|
||||||
|
|
|
@ -48,6 +48,6 @@ int X64Function::CallImpl(ThreadState* thread_state, uint64_t return_address) {
|
||||||
thunk(
|
thunk(
|
||||||
machine_code_,
|
machine_code_,
|
||||||
thread_state->raw_context(),
|
thread_state->raw_context(),
|
||||||
thread_state->memory()->membase());
|
(void*)return_address);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() {
|
||||||
|
|
||||||
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||||
// rsp + 0 = return address
|
// rsp + 0 = return address
|
||||||
|
mov(qword[rsp + 8 * 3], r8);
|
||||||
mov(qword[rsp + 8 * 2], rdx);
|
mov(qword[rsp + 8 * 2], rdx);
|
||||||
mov(qword[rsp + 8 * 1], rcx);
|
mov(qword[rsp + 8 * 1], rcx);
|
||||||
sub(rsp, stack_size);
|
sub(rsp, stack_size);
|
||||||
|
@ -88,6 +89,7 @@ HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() {
|
||||||
add(rsp, stack_size);
|
add(rsp, stack_size);
|
||||||
mov(rcx, qword[rsp + 8 * 1]);
|
mov(rcx, qword[rsp + 8 * 1]);
|
||||||
mov(rdx, qword[rsp + 8 * 2]);
|
mov(rdx, qword[rsp + 8 * 2]);
|
||||||
|
mov(r8, qword[rsp + 8 * 3]);
|
||||||
ret();
|
ret();
|
||||||
|
|
||||||
void* fn = Emplace(stack_size);
|
void* fn = Emplace(stack_size);
|
||||||
|
|
|
@ -104,6 +104,10 @@ namespace x64 {
|
||||||
* +------------------+
|
* +------------------+
|
||||||
* | rcx / context | rsp + 64
|
* | rcx / context | rsp + 64
|
||||||
* +------------------+
|
* +------------------+
|
||||||
|
* | guest ret addr | rsp + 72
|
||||||
|
* +------------------+
|
||||||
|
* | call ret addr | rsp + 80
|
||||||
|
* +------------------+
|
||||||
* ... locals ...
|
* ... locals ...
|
||||||
* +------------------+
|
* +------------------+
|
||||||
* | (return address) |
|
* | (return address) |
|
||||||
|
@ -115,8 +119,10 @@ class StackLayout {
|
||||||
public:
|
public:
|
||||||
const static size_t THUNK_STACK_SIZE = 120;
|
const static size_t THUNK_STACK_SIZE = 120;
|
||||||
|
|
||||||
const static size_t GUEST_STACK_SIZE = 72;
|
const static size_t GUEST_STACK_SIZE = 88;
|
||||||
const static size_t GUEST_RCX_HOME = 64;
|
const static size_t GUEST_RCX_HOME = 64;
|
||||||
|
const static size_t GUEST_RET_ADDR = 72;
|
||||||
|
const static size_t GUEST_CALL_RET_ADDR = 80;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue