Return address handling. Not happy with the design, but it (sorta) works.
This commit is contained in:
parent
dc0848f7ba
commit
2549292a57
|
@ -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.
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,10 @@ 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) {
|
||||||
|
@ -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(
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue