Return address handling. Not happy with the design, but it (sorta) works.

This commit is contained in:
Ben Vanik 2013-12-08 13:58:57 -08:00
parent dc0848f7ba
commit 2549292a57
13 changed files with 60 additions and 22 deletions

View File

@ -34,7 +34,7 @@ void IVMFunction::Setup(TranslationContext& ctx) {
intcodes_ = (IntCode*)ctx.intcode_arena->CloneContents(); intcodes_ = (IntCode*)ctx.intcode_arena->CloneContents();
} }
int IVMFunction::CallImpl(ThreadState* thread_state) { int IVMFunction::CallImpl(ThreadState* thread_state, uint64_t return_address) {
// Setup register file on stack. // Setup register file on stack.
size_t register_file_size = register_count_ * sizeof(Register); size_t register_file_size = register_count_ * sizeof(Register);
Register* register_file = (Register*)alloca(register_file_size); Register* register_file = (Register*)alloca(register_file_size);
@ -46,7 +46,8 @@ int IVMFunction::CallImpl(ThreadState* thread_state) {
ics.did_carry = 0; ics.did_carry = 0;
ics.access_callbacks = thread_state->runtime()->access_callbacks(); ics.access_callbacks = thread_state->runtime()->access_callbacks();
ics.thread_state = thread_state; ics.thread_state = thread_state;
ics.return_address = 0xBEBEBEBE; ics.return_address = return_address;
ics.call_return_address = 0;
// TODO(benvanik): DID_CARRY -- need HIR to set a OPCODE_FLAG_SET_CARRY // TODO(benvanik): DID_CARRY -- need HIR to set a OPCODE_FLAG_SET_CARRY
// or something so the fns can set an ics flag. // or something so the fns can set an ics flag.

View File

@ -29,7 +29,8 @@ public:
void Setup(TranslationContext& ctx); void Setup(TranslationContext& ctx);
protected: protected:
virtual int CallImpl(runtime::ThreadState* thread_state); virtual int CallImpl(runtime::ThreadState* thread_state,
uint64_t return_address);
private: private:

View File

@ -523,10 +523,13 @@ int Translate_TRAP_TRUE(TranslationContext& ctx, Instr* i) {
uint32_t IntCode_CALL_XX(IntCodeState& ics, const IntCode* i, uint32_t reg) { uint32_t IntCode_CALL_XX(IntCodeState& ics, const IntCode* i, uint32_t reg) {
FunctionInfo* symbol_info = (FunctionInfo*)ics.rf[reg].u64; FunctionInfo* symbol_info = (FunctionInfo*)ics.rf[reg].u64;
Function* fn; Function* fn = NULL;
ics.thread_state->runtime()->ResolveFunction(symbol_info->address(), &fn); ics.thread_state->runtime()->ResolveFunction(symbol_info->address(), &fn);
XEASSERTNOTNULL(fn);
// TODO(benvanik): proper tail call support, somehow. // TODO(benvanik): proper tail call support, somehow.
fn->Call(ics.thread_state); uint64_t return_address =
(i->flags & CALL_TAIL) ? ics.return_address : ics.call_return_address;
fn->Call(ics.thread_state, return_address);
if (i->flags & CALL_TAIL) { if (i->flags & CALL_TAIL) {
return IA_RETURN; return IA_RETURN;
} }
@ -589,16 +592,21 @@ int Translate_CALL_TRUE(TranslationContext& ctx, Instr* i) {
} }
uint32_t IntCode_CALL_INDIRECT_XX(IntCodeState& ics, const IntCode* i, uint32_t reg) { uint32_t IntCode_CALL_INDIRECT_XX(IntCodeState& ics, const IntCode* i, uint32_t reg) {
uint64_t target = ics.rf[reg].u64;
// Check if return address - if so, return. // Check if return address - if so, return.
/*if (ics.rf[reg].u64 == ics.return_address) { if (target == ics.return_address) {
return IA_RETURN; return IA_RETURN;
}*/ }
// Real call. // Real call.
Function* fn; Function* fn = NULL;
ics.thread_state->runtime()->ResolveFunction(ics.rf[reg].u64, &fn); ics.thread_state->runtime()->ResolveFunction(target, &fn);
XEASSERTNOTNULL(fn);
// TODO(benvanik): proper tail call support, somehow. // TODO(benvanik): proper tail call support, somehow.
fn->Call(ics.thread_state); uint64_t return_address =
(i->flags & CALL_TAIL) ? ics.return_address : ics.call_return_address;
fn->Call(ics.thread_state, return_address);
if (i->flags & CALL_TAIL) { if (i->flags & CALL_TAIL) {
return IA_RETURN; return IA_RETURN;
} }
@ -667,6 +675,14 @@ int Translate_RETURN(TranslationContext& ctx, Instr* i) {
return DispatchToC(ctx, i, IntCode_RETURN); return DispatchToC(ctx, i, IntCode_RETURN);
} }
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) { uint32_t IntCode_BRANCH_XX(IntCodeState& ics, const IntCode* i, uint32_t reg) {
return ics.rf[reg].u32; return ics.rf[reg].u32;
} }
@ -1167,6 +1183,7 @@ uint32_t IntCode_LOAD_I32(IntCodeState& ics, const IntCode* i) {
if (DYNAMIC_REGISTER_ACCESS_CHECK(address)) { if (DYNAMIC_REGISTER_ACCESS_CHECK(address)) {
return IntCode_LOAD_REGISTER_I32_DYNAMIC(ics, i); return IntCode_LOAD_REGISTER_I32_DYNAMIC(ics, i);
} }
DFLUSH();
DPRINT("%d (%X) = load.i32 %.8X\n", DPRINT("%d (%X) = load.i32 %.8X\n",
*((int32_t*)(ics.membase + address)), *((int32_t*)(ics.membase + address)),
*((uint32_t*)(ics.membase + address)), *((uint32_t*)(ics.membase + address)),
@ -2827,6 +2844,7 @@ static const TranslateFn dispatch_table[] = {
Translate_CALL_INDIRECT, Translate_CALL_INDIRECT,
Translate_CALL_INDIRECT_TRUE, Translate_CALL_INDIRECT_TRUE,
Translate_RETURN, Translate_RETURN,
Translate_SET_RETURN_ADDRESS,
Translate_BRANCH, Translate_BRANCH,
Translate_BRANCH_IF, Translate_BRANCH_IF,

View File

@ -47,6 +47,7 @@ typedef struct {
runtime::RegisterAccessCallbacks* access_callbacks; runtime::RegisterAccessCallbacks* access_callbacks;
runtime::ThreadState* thread_state; runtime::ThreadState* thread_state;
uint64_t return_address; uint64_t return_address;
uint64_t call_return_address;
} IntCodeState; } IntCodeState;

View File

@ -32,10 +32,12 @@ int InstrEmit_branch(
// The docs say always, though... // The docs say always, though...
// Note that we do the update before we branch/call as we need it to // Note that we do the update before we branch/call as we need it to
// be correct for returns. // be correct for returns.
Value* return_address = f.LoadConstant(cia + 4);
f.SetReturnAddress(return_address);
if (lk) { if (lk) {
f.StoreLR(f.LoadConstant(cia + 4)); f.StoreLR(return_address);
} }
if (!lk) { if (!lk) {
// If LR is not set this call will never return here. // If LR is not set this call will never return here.
call_flags |= CALL_TAIL; call_flags |= CALL_TAIL;
@ -301,8 +303,8 @@ XEEMITTER(bclrx, 0x4C000020, XL )(PPCFunctionBuilder& f, InstrData& i) {
if (!i.XL.LK && !ok) { if (!i.XL.LK && !ok) {
// Return (most likely). // Return (most likely).
// TODO(benvanik): test? ReturnCheck()? // TODO(benvanik): test? ReturnCheck()?
f.Return(); //f.Return();
return 0; //return 0;
} }
return InstrEmit_branch( return InstrEmit_branch(

View File

@ -459,6 +459,12 @@ void FunctionBuilder::Return() {
EndBlock(); EndBlock();
} }
void FunctionBuilder::SetReturnAddress(Value* value) {
Instr* i = AppendInstr(OPCODE_SET_RETURN_ADDRESS_info, 0);
i->set_src1(value);
i->src2.value = i->src3.value = NULL;
}
void FunctionBuilder::Branch(Label* label, uint32_t branch_flags) { void FunctionBuilder::Branch(Label* label, uint32_t branch_flags) {
Instr* i = AppendInstr(OPCODE_BRANCH_info, branch_flags); Instr* i = AppendInstr(OPCODE_BRANCH_info, branch_flags);
i->src1.label = label; i->src1.label = label;

View File

@ -70,6 +70,7 @@ public:
void CallIndirect(Value* value, uint32_t call_flags = 0); void CallIndirect(Value* value, uint32_t call_flags = 0);
void CallIndirectTrue(Value* cond, Value* value, uint32_t call_flags = 0); void CallIndirectTrue(Value* cond, Value* value, uint32_t call_flags = 0);
void Return(); void Return();
void SetReturnAddress(Value* value);
void Branch(Label* label, uint32_t branch_flags = 0); void Branch(Label* label, uint32_t branch_flags = 0);
void BranchIf(Value* cond, Label* true_label, Label* false_label, void BranchIf(Value* cond, Label* true_label, Label* false_label,

View File

@ -75,6 +75,7 @@ enum Opcode {
OPCODE_CALL_INDIRECT, OPCODE_CALL_INDIRECT,
OPCODE_CALL_INDIRECT_TRUE, OPCODE_CALL_INDIRECT_TRUE,
OPCODE_RETURN, OPCODE_RETURN,
OPCODE_SET_RETURN_ADDRESS,
OPCODE_BRANCH, OPCODE_BRANCH,
OPCODE_BRANCH_IF, OPCODE_BRANCH_IF,

View File

@ -74,6 +74,12 @@ DEFINE_OPCODE(
OPCODE_SIG_X, OPCODE_SIG_X,
OPCODE_FLAG_BRANCH); OPCODE_FLAG_BRANCH);
DEFINE_OPCODE(
OPCODE_SET_RETURN_ADDRESS,
"set_return_address",
OPCODE_SIG_X_V,
0);
DEFINE_OPCODE( DEFINE_OPCODE(
OPCODE_BRANCH, OPCODE_BRANCH,
"branch", "branch",

View File

@ -23,12 +23,12 @@ Function::Function(Type type, uint64_t address) :
Function::~Function() { Function::~Function() {
} }
int Function::Call(ThreadState* thread_state) { int Function::Call(ThreadState* thread_state, uint64_t return_address) {
ThreadState* original_thread_state = ThreadState::Get(); ThreadState* original_thread_state = ThreadState::Get();
if (original_thread_state != thread_state) { if (original_thread_state != thread_state) {
ThreadState::Bind(thread_state); ThreadState::Bind(thread_state);
} }
int result = CallImpl(thread_state); int result = CallImpl(thread_state, return_address);
if (original_thread_state != thread_state) { if (original_thread_state != thread_state) {
ThreadState::Bind(original_thread_state); ThreadState::Bind(original_thread_state);
} }
@ -44,7 +44,8 @@ ExternFunction::ExternFunction(
ExternFunction::~ExternFunction() { ExternFunction::~ExternFunction() {
} }
int ExternFunction::CallImpl(ThreadState* thread_state) { int ExternFunction::CallImpl(ThreadState* thread_state,
uint64_t return_address) {
if (!handler_) { if (!handler_) {
XELOGW("undefined extern call to %.8X", address()); XELOGW("undefined extern call to %.8X", address());
return 0; return 0;

View File

@ -34,10 +34,10 @@ public:
Type type() const { return type_; } Type type() const { return type_; }
uint64_t address() const { return address_; } uint64_t address() const { return address_; }
int Call(ThreadState* thread_state); int Call(ThreadState* thread_state, uint64_t return_address);
protected: protected:
virtual int CallImpl(ThreadState* thread_state) = 0; virtual int CallImpl(ThreadState* thread_state, uint64_t return_address) = 0;
protected: protected:
Type type_; Type type_;
@ -57,7 +57,7 @@ public:
void* arg1() const { return arg1_; } void* arg1() const { return arg1_; }
protected: protected:
virtual int CallImpl(ThreadState* thread_state); virtual int CallImpl(ThreadState* thread_state, uint64_t return_address);
protected: protected:
Handler handler_; Handler handler_;

View File

@ -117,7 +117,7 @@ int Processor::Execute(XenonThreadState* thread_state, uint64_t address) {
context->lr = lr; context->lr = lr;
// Execute the function. // Execute the function.
fn->Call(thread_state); fn->Call(thread_state, lr);
return 0; return 0;
} }

View File

@ -47,7 +47,7 @@ int alloy_sandbox(int argc, xechar_t** argv) {
Function* fn; Function* fn;
runtime->ResolveFunction(0x82000000, &fn); runtime->ResolveFunction(0x82000000, &fn);
fn->Call(thread_state); fn->Call(thread_state, 0xBEBEBEBE);
delete thread_state; delete thread_state;