diff --git a/src/alloy/backend/ivm/ivm_function.cc b/src/alloy/backend/ivm/ivm_function.cc index 702ec20a0..c4c0d97f9 100644 --- a/src/alloy/backend/ivm/ivm_function.cc +++ b/src/alloy/backend/ivm/ivm_function.cc @@ -104,7 +104,7 @@ void IVMFunction::OnBreakpointHit(ThreadState* thread_state, IntCode* i) { #undef TRACE_SOURCE_OFFSET -int IVMFunction::CallImpl(ThreadState* thread_state, uint64_t return_address) { +int IVMFunction::CallImpl(ThreadState* thread_state) { // Setup register file on stack. auto stack = (IVMStack*)thread_state->backend_data(); auto register_file = (Register*)stack->Alloc(register_count_); @@ -120,8 +120,6 @@ int IVMFunction::CallImpl(ThreadState* thread_state, uint64_t return_address) { ics.did_saturate = 0; ics.access_callbacks = thread_state->runtime()->access_callbacks(); ics.thread_state = thread_state; - ics.return_address = return_address; - ics.call_return_address = 0; volatile int* suspend_flag_address = thread_state->suspend_flag_address(); diff --git a/src/alloy/backend/ivm/ivm_function.h b/src/alloy/backend/ivm/ivm_function.h index 13acc5e60..7fee49db0 100644 --- a/src/alloy/backend/ivm/ivm_function.h +++ b/src/alloy/backend/ivm/ivm_function.h @@ -31,8 +31,7 @@ public: protected: virtual int AddBreakpointImpl(runtime::Breakpoint* breakpoint); virtual int RemoveBreakpointImpl(runtime::Breakpoint* breakpoint); - virtual int CallImpl(runtime::ThreadState* thread_state, - uint64_t return_address); + virtual int CallImpl(runtime::ThreadState* thread_state); private: IntCode* GetIntCodeAtSourceOffset(uint64_t offset); diff --git a/src/alloy/backend/ivm/ivm_intcode.cc b/src/alloy/backend/ivm/ivm_intcode.cc index 9c741818e..7100deaa8 100644 --- a/src/alloy/backend/ivm/ivm_intcode.cc +++ b/src/alloy/backend/ivm/ivm_intcode.cc @@ -580,9 +580,7 @@ uint32_t IntCode_CALL_XX(IntCodeState& ics, const IntCode* i, uint32_t reg) { ics.thread_state->runtime()->ResolveFunction(symbol_info->address(), &fn); XEASSERTNOTNULL(fn); // TODO(benvanik): proper tail call support, somehow. - uint64_t return_address = - (i->flags & CALL_TAIL) ? ics.return_address : ics.call_return_address; - fn->Call(ics.thread_state, return_address); + fn->Call(ics.thread_state); if (i->flags & CALL_TAIL) { return IA_RETURN; } @@ -647,19 +645,12 @@ int Translate_CALL_TRUE(TranslationContext& ctx, Instr* i) { uint32_t IntCode_CALL_INDIRECT_XX(IntCodeState& ics, const IntCode* i, uint32_t reg) { uint64_t target = ics.rf[reg].u32; - // Check if return address - if so, return. - if (target == ics.return_address) { - return IA_RETURN; - } - // Real call. Function* fn = NULL; ics.thread_state->runtime()->ResolveFunction(target, &fn); XEASSERTNOTNULL(fn); // TODO(benvanik): proper tail call support, somehow. - uint64_t return_address = - (i->flags & CALL_TAIL) ? ics.return_address : ics.call_return_address; - fn->Call(ics.thread_state, return_address); + fn->Call(ics.thread_state); if (i->flags & CALL_TAIL) { return IA_RETURN; } @@ -777,14 +768,6 @@ int Translate_RETURN_TRUE(TranslationContext& ctx, Instr* i) { return DispatchToC(ctx, i, fns[i->src1.value->type]); } -uint32_t IntCode_SET_RETURN_ADDRESS(IntCodeState& ics, const IntCode* i) { - ics.call_return_address = ics.rf[i->src1_reg].u32; - return IA_NEXT; -} -int Translate_SET_RETURN_ADDRESS(TranslationContext& ctx, Instr* i) { - return DispatchToC(ctx, i, IntCode_SET_RETURN_ADDRESS); -} - uint32_t IntCode_BRANCH_XX(IntCodeState& ics, const IntCode* i, uint32_t reg) { return ics.rf[reg].u32; } @@ -4028,7 +4011,6 @@ static const TranslateFn dispatch_table[] = { Translate_CALL_INDIRECT_TRUE, Translate_RETURN, Translate_RETURN_TRUE, - Translate_SET_RETURN_ADDRESS, Translate_BRANCH, Translate_BRANCH_TRUE, diff --git a/src/alloy/backend/ivm/ivm_intcode.h b/src/alloy/backend/ivm/ivm_intcode.h index 296a180cc..9f361b2f9 100644 --- a/src/alloy/backend/ivm/ivm_intcode.h +++ b/src/alloy/backend/ivm/ivm_intcode.h @@ -48,8 +48,6 @@ typedef struct { int8_t did_saturate; runtime::RegisterAccessCallbacks* access_callbacks; runtime::ThreadState* thread_state; - uint64_t return_address; - uint64_t call_return_address; } IntCodeState; diff --git a/src/alloy/backend/x64/lowering/lowering_sequences.cc b/src/alloy/backend/x64/lowering/lowering_sequences.cc index f7888b635..22e7d1b18 100644 --- a/src/alloy/backend/x64/lowering/lowering_sequences.cc +++ b/src/alloy/backend/x64/lowering/lowering_sequences.cc @@ -11,11 +11,15 @@ #include #include +#include +#include +#include using namespace alloy; using namespace alloy::backend::x64; using namespace alloy::backend::x64::lowering; using namespace alloy::hir; +using namespace alloy::runtime; using namespace Xbyak; @@ -31,6 +35,49 @@ void Dummy() { // } +// TODO(benvanik): fancy stuff. +void CallThunk(void* raw_context, uint8_t* membase, + FunctionInfo* symbol_info) { + // TODO(benvanik): generate this thunk at runtime? or a shim? + auto thread_state = *((ThreadState**)raw_context); + + Function* fn = NULL; + thread_state->runtime()->ResolveFunction(symbol_info->address(), &fn); + XEASSERTNOTNULL(fn); + fn->Call(thread_state); +} +void IssueCall(X64Emitter& e, FunctionInfo* symbol_info, uint32_t flags) { + e.mov(e.r8, (uint64_t)symbol_info); + e.mov(e.rax, (uint64_t)CallThunk); + if (flags & CALL_TAIL) { + e.jmp(e.rax); + } else { + e.call(e.rax); + } +} + +void IndirectCallThunk(void* raw_context, uint8_t* membase, + uint64_t target_address) { + // TODO(benvanik): generate this thunk at runtime? or a shim? + auto thread_state = *((ThreadState**)raw_context); +} +void IssueCallIndirect(X64Emitter& e, Value* target, uint32_t flags) { + Reg64 r; + e.BeginOp(target, r, 0); + if (r != e.r8) { + e.mov(e.r8, r); + } + e.EndOp(r); + e.mov(e.rax, (uint64_t)IndirectCallThunk); + if (flags & CALL_TAIL) { + e.jmp(e.rax); + } else { + e.sub(e.rsp, 0x20); + e.call(e.rax); + e.add(e.rsp, 0x20); + } +} + // Sets EFLAGs with zf for the given value. void CheckBoolean(X64Emitter& e, Value* v) { if (v->IsConstant()) { @@ -259,9 +306,7 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // -------------------------------------------------------------------------- table->AddSequence(OPCODE_CALL, [](X64Emitter& e, Instr*& i) { - e.mov(e.rax, (uint64_t)Dummy); - e.call(e.rax); - UNIMPLEMENTED_SEQ(); + IssueCall(e, i->src1.symbol_info, i->flags); i = e.Advance(i); return true; }); @@ -270,10 +315,7 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { e.inLocalLabel(); CheckBoolean(e, i->src1.value); e.jne(".x", e.T_SHORT); - // TODO(benvanik): call - e.mov(e.rax, (uint64_t)Dummy); - e.call(e.rax); - UNIMPLEMENTED_SEQ(); + IssueCall(e, i->src2.symbol_info, i->flags); e.L(".x"); e.outLocalLabel(); i = e.Advance(i); @@ -281,9 +323,7 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { }); table->AddSequence(OPCODE_CALL_INDIRECT, [](X64Emitter& e, Instr*& i) { - e.mov(e.rax, (uint64_t)Dummy); - e.call(e.rax); - UNIMPLEMENTED_SEQ(); + IssueCallIndirect(e, i->src1.value, i->flags); i = e.Advance(i); return true; }); @@ -292,10 +332,7 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { e.inLocalLabel(); CheckBoolean(e, i->src1.value); e.jne(".x", e.T_SHORT); - // TODO(benvanik): call - e.mov(e.rax, (uint64_t)Dummy); - e.call(e.rax); - UNIMPLEMENTED_SEQ(); + IssueCallIndirect(e, i->src2.value, i->flags); e.L(".x"); e.outLocalLabel(); i = e.Advance(i); @@ -319,12 +356,6 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { return true; }); - table->AddSequence(OPCODE_SET_RETURN_ADDRESS, [](X64Emitter& e, Instr*& i) { - //UNIMPLEMENTED_SEQ(); - i = e.Advance(i); - return true; - }); - // -------------------------------------------------------------------------- // Branches // -------------------------------------------------------------------------- diff --git a/src/alloy/backend/x64/x64_function.cc b/src/alloy/backend/x64/x64_function.cc index 31671732d..c668c14f1 100644 --- a/src/alloy/backend/x64/x64_function.cc +++ b/src/alloy/backend/x64/x64_function.cc @@ -41,10 +41,8 @@ int X64Function::RemoveBreakpointImpl(Breakpoint* breakpoint) { return 0; } -int X64Function::CallImpl(ThreadState* thread_state, uint64_t return_address) { - //typedef void(*call_t)(ThreadState* thread_state, uint64_t return_address); - //((call_t)machine_code_)(thread_state, return_address); - typedef void(*call_t)(ThreadState* thread_state, uint8_t* membase); - ((call_t)machine_code_)(thread_state, thread_state->memory()->membase()); +int X64Function::CallImpl(ThreadState* thread_state) { + typedef void(*call_t)(void* raw_context, uint8_t* membase); + ((call_t)machine_code_)(thread_state->raw_context(), thread_state->memory()->membase()); return 0; } diff --git a/src/alloy/backend/x64/x64_function.h b/src/alloy/backend/x64/x64_function.h index 01a6767c9..cf06bb6c4 100644 --- a/src/alloy/backend/x64/x64_function.h +++ b/src/alloy/backend/x64/x64_function.h @@ -30,8 +30,7 @@ public: protected: virtual int AddBreakpointImpl(runtime::Breakpoint* breakpoint); virtual int RemoveBreakpointImpl(runtime::Breakpoint* breakpoint); - virtual int CallImpl(runtime::ThreadState* thread_state, - uint64_t return_address); + virtual int CallImpl(runtime::ThreadState* thread_state); private: void* machine_code_; diff --git a/src/alloy/frontend/context_info.cc b/src/alloy/frontend/context_info.cc index a90888d17..d93a2f2d6 100644 --- a/src/alloy/frontend/context_info.cc +++ b/src/alloy/frontend/context_info.cc @@ -13,8 +13,9 @@ using namespace alloy; using namespace alloy::frontend; -ContextInfo::ContextInfo(size_t size) : - size_(size) { +ContextInfo::ContextInfo(size_t size, uintptr_t thread_state_offset) : + size_(size), + thread_state_offset_(thread_state_offset) { } ContextInfo::~ContextInfo() { diff --git a/src/alloy/frontend/context_info.h b/src/alloy/frontend/context_info.h index 04b00b012..542d6a40c 100644 --- a/src/alloy/frontend/context_info.h +++ b/src/alloy/frontend/context_info.h @@ -19,13 +19,16 @@ namespace frontend { class ContextInfo { public: - ContextInfo(size_t size); + ContextInfo(size_t size, uintptr_t thread_state_offset); ~ContextInfo(); size_t size() const { return size_; } + uintptr_t thread_state_offset() const { return thread_state_offset_; } + private: size_t size_; + uintptr_t thread_state_offset_; }; diff --git a/src/alloy/frontend/ppc/ppc_context.h b/src/alloy/frontend/ppc/ppc_context.h index 08205e349..92d6d2877 100644 --- a/src/alloy/frontend/ppc/ppc_context.h +++ b/src/alloy/frontend/ppc/ppc_context.h @@ -64,6 +64,10 @@ typedef union { #pragma pack(push, 4) typedef struct XECACHEALIGN64 PPCContext_s { + // Must be stored at 0x0 for now. + // TODO(benvanik): find a nice way to describe this to the JIT. + runtime::ThreadState* thread_state; + // Most frequently used registers first. uint64_t r[32]; // General purpose registers uint64_t lr; // Link register @@ -194,7 +198,6 @@ typedef struct XECACHEALIGN64 PPCContext_s { // current runtime and its data. uint8_t* membase; runtime::Runtime* runtime; - runtime::ThreadState* thread_state; volatile int suspend_flag; void SetRegFromString(const char* name, const char* value); diff --git a/src/alloy/frontend/ppc/ppc_emit_control.cc b/src/alloy/frontend/ppc/ppc_emit_control.cc index 0fcead5e8..83a50a2c4 100644 --- a/src/alloy/frontend/ppc/ppc_emit_control.cc +++ b/src/alloy/frontend/ppc/ppc_emit_control.cc @@ -35,7 +35,6 @@ int InstrEmit_branch( // be correct for returns. if (lk) { Value* return_address = f.LoadConstant(cia + 4); - f.SetReturnAddress(return_address); f.StoreLR(return_address); } diff --git a/src/alloy/frontend/ppc/ppc_frontend.cc b/src/alloy/frontend/ppc/ppc_frontend.cc index 406411e21..29f62ab42 100644 --- a/src/alloy/frontend/ppc/ppc_frontend.cc +++ b/src/alloy/frontend/ppc/ppc_frontend.cc @@ -50,7 +50,9 @@ PPCFrontend::PPCFrontend(Runtime* runtime) : Frontend(runtime) { InitializeIfNeeded(); - ContextInfo* info = new ContextInfo(sizeof(PPCContext)); + ContextInfo* info = new ContextInfo( + sizeof(PPCContext), + offsetof(PPCContext, thread_state)); // Add fields/etc. context_info_ = info; } diff --git a/src/alloy/hir/hir_builder.cc b/src/alloy/hir/hir_builder.cc index 67900036f..99d5649d1 100644 --- a/src/alloy/hir/hir_builder.cc +++ b/src/alloy/hir/hir_builder.cc @@ -578,12 +578,6 @@ void HIRBuilder::ReturnTrue(Value* cond) { EndBlock(); } -void HIRBuilder::SetReturnAddress(Value* value) { - Instr* i = AppendInstr(OPCODE_SET_RETURN_ADDRESS_info, 0); - i->set_src1(value); - i->src2.value = i->src3.value = NULL; -} - void HIRBuilder::Branch(Label* label, uint32_t branch_flags) { Instr* i = AppendInstr(OPCODE_BRANCH_info, branch_flags); i->src1.label = label; diff --git a/src/alloy/hir/hir_builder.h b/src/alloy/hir/hir_builder.h index f18ad2d21..05fa632de 100644 --- a/src/alloy/hir/hir_builder.h +++ b/src/alloy/hir/hir_builder.h @@ -76,7 +76,6 @@ public: void CallIndirectTrue(Value* cond, Value* value, uint32_t call_flags = 0); void Return(); void ReturnTrue(Value* cond); - void SetReturnAddress(Value* value); void Branch(Label* label, uint32_t branch_flags = 0); void Branch(Block* block, uint32_t branch_flags = 0); diff --git a/src/alloy/hir/opcodes.h b/src/alloy/hir/opcodes.h index 646eb659f..9fdcd311e 100644 --- a/src/alloy/hir/opcodes.h +++ b/src/alloy/hir/opcodes.h @@ -96,7 +96,6 @@ enum Opcode { OPCODE_CALL_INDIRECT_TRUE, OPCODE_RETURN, OPCODE_RETURN_TRUE, - OPCODE_SET_RETURN_ADDRESS, OPCODE_BRANCH, OPCODE_BRANCH_TRUE, diff --git a/src/alloy/hir/opcodes.inl b/src/alloy/hir/opcodes.inl index e3cc5953c..abdea12db 100644 --- a/src/alloy/hir/opcodes.inl +++ b/src/alloy/hir/opcodes.inl @@ -86,12 +86,6 @@ DEFINE_OPCODE( OPCODE_SIG_X_V, OPCODE_FLAG_BRANCH); -DEFINE_OPCODE( - OPCODE_SET_RETURN_ADDRESS, - "set_return_address", - OPCODE_SIG_X_V, - 0); - DEFINE_OPCODE( OPCODE_BRANCH, "branch", diff --git a/src/alloy/runtime/function.cc b/src/alloy/runtime/function.cc index 0fbe95ab2..c09d3b929 100644 --- a/src/alloy/runtime/function.cc +++ b/src/alloy/runtime/function.cc @@ -72,12 +72,12 @@ Breakpoint* Function::FindBreakpoint(uint64_t address) { return result; } -int Function::Call(ThreadState* thread_state, uint64_t return_address) { +int Function::Call(ThreadState* thread_state) { ThreadState* original_thread_state = ThreadState::Get(); if (original_thread_state != thread_state) { ThreadState::Bind(thread_state); } - int result = CallImpl(thread_state, return_address); + int result = CallImpl(thread_state); if (original_thread_state != thread_state) { ThreadState::Bind(original_thread_state); } @@ -101,8 +101,7 @@ void ExternFunction::set_name(const char* name) { name_ = xestrdupa(name); } -int ExternFunction::CallImpl(ThreadState* thread_state, - uint64_t return_address) { +int ExternFunction::CallImpl(ThreadState* thread_state) { if (!handler_) { XELOGW("undefined extern call to %.8X %s", address(), name()); return 0; diff --git a/src/alloy/runtime/function.h b/src/alloy/runtime/function.h index 40bad6aa8..d150f91a6 100644 --- a/src/alloy/runtime/function.h +++ b/src/alloy/runtime/function.h @@ -42,13 +42,13 @@ public: int AddBreakpoint(Breakpoint* breakpoint); int RemoveBreakpoint(Breakpoint* breakpoint); - int Call(ThreadState* thread_state, uint64_t return_address); + int Call(ThreadState* thread_state); protected: Breakpoint* FindBreakpoint(uint64_t address); virtual int AddBreakpointImpl(Breakpoint* breakpoint) { return 0; } virtual int RemoveBreakpointImpl(Breakpoint* breakpoint) { return 0; } - virtual int CallImpl(ThreadState* thread_state, uint64_t return_address) = 0; + virtual int CallImpl(ThreadState* thread_state) = 0; protected: Type type_; @@ -76,7 +76,7 @@ public: void* arg1() const { return arg1_; } protected: - virtual int CallImpl(ThreadState* thread_state, uint64_t return_address); + virtual int CallImpl(ThreadState* thread_state); protected: char* name_; diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index 678be2190..e03890a92 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -165,7 +165,7 @@ int Processor::Execute(XenonThreadState* thread_state, uint64_t address) { context->lr = lr; // Execute the function. - fn->Call(thread_state, lr); + fn->Call(thread_state); return 0; } diff --git a/tools/alloy-sandbox/alloy-sandbox.cc b/tools/alloy-sandbox/alloy-sandbox.cc index b392a69e3..da8d1b80e 100644 --- a/tools/alloy-sandbox/alloy-sandbox.cc +++ b/tools/alloy-sandbox/alloy-sandbox.cc @@ -49,7 +49,7 @@ int alloy_sandbox(int argc, xechar_t** argv) { ctx->lr = 0xBEBEBEBE; ctx->r[5] = 10; ctx->r[25] = 25; - fn->Call(thread_state, 0xBEBEBEBE); + fn->Call(thread_state); auto result = ctx->r[11]; delete thread_state;