Refactoring of function types. Also fixes some library import bugs.

This commit is contained in:
Ben Vanik
2014-01-30 00:22:55 -08:00
parent bdee924494
commit f85b83709e
21 changed files with 198 additions and 160 deletions

View File

@@ -23,7 +23,7 @@ using namespace alloy::runtime;
IVMFunction::IVMFunction(FunctionInfo* symbol_info) :
register_count_(0), intcode_count_(0), intcodes_(0),
source_map_count_(0), source_map_(0),
GuestFunction(symbol_info) {
Function(symbol_info) {
}
IVMFunction::~IVMFunction() {

View File

@@ -21,7 +21,7 @@ namespace backend {
namespace ivm {
class IVMFunction : public runtime::GuestFunction {
class IVMFunction : public runtime::Function {
public:
IVMFunction(runtime::FunctionInfo* symbol_info);
virtual ~IVMFunction();

View File

@@ -712,6 +712,13 @@ int Translate_CALL_INDIRECT_TRUE(TranslationContext& ctx, Instr* i) {
return DispatchToC(ctx, i, fns[i->src1.value->type]);
}
uint32_t IntCode_CALL_EXTERN(IntCodeState& ics, const IntCode* i) {
return IntCode_CALL_XX(ics, i, i->src1_reg);
}
int Translate_CALL_EXTERN(TranslationContext& ctx, Instr* i) {
return DispatchToC(ctx, i, IntCode_CALL_EXTERN);
}
uint32_t IntCode_RETURN(IntCodeState& ics, const IntCode* i) {
return IA_RETURN;
}
@@ -4009,6 +4016,7 @@ static const TranslateFn dispatch_table[] = {
Translate_CALL_TRUE,
Translate_CALL_INDIRECT,
Translate_CALL_INDIRECT_TRUE,
Translate_CALL_EXTERN,
Translate_RETURN,
Translate_RETURN_TRUE,

View File

@@ -96,12 +96,6 @@ void Dummy() {
//
}
void UnimplementedExtern(void* raw_context, ExternFunction* extern_fn) {
// TODO(benvanik): generate this thunk at runtime? or a shim?
auto thread_state = *((ThreadState**)raw_context);
extern_fn->Call(thread_state);
}
uint64_t DynamicRegisterLoad(void* raw_context, uint32_t address) {
auto thread_state = *((ThreadState**)raw_context);
auto cbs = thread_state->runtime()->access_callbacks();
@@ -149,44 +143,30 @@ void* ResolveFunctionSymbol(void* raw_context, FunctionInfo* symbol_info) {
Function* fn = NULL;
thread_state->runtime()->ResolveFunction(symbol_info->address(), &fn);
XEASSERTNOTNULL(fn);
XEASSERT(fn->type() == Function::USER_FUNCTION);
auto x64_fn = (X64Function*)fn;
return x64_fn->machine_code();
}
void* ResolveFunctionAddress(void* raw_context, uint64_t target_address) {
void* ResolveFunctionAddress(void* raw_context, uint32_t target_address) {
// TODO(benvanik): generate this thunk at runtime? or a shim?
auto thread_state = *((ThreadState**)raw_context);
Function* fn = NULL;
thread_state->runtime()->ResolveFunction(target_address, &fn);
XEASSERTNOTNULL(fn);
XEASSERT(fn->type() == Function::USER_FUNCTION);
auto x64_fn = (X64Function*)fn;
return x64_fn->machine_code();
}
void IssueCall(X64Emitter& e, FunctionInfo* symbol_info, uint32_t flags) {
// If we are an extern function, we can directly insert a call.
auto fn = symbol_info->function();
if (fn && fn->type() == Function::EXTERN_FUNCTION) {
auto extern_fn = (ExternFunction*)fn;
if (extern_fn->handler()) {
e.mov(e.rdx, (uint64_t)extern_fn->arg0());
e.mov(e.r8, (uint64_t)extern_fn->arg1());
e.mov(e.rax, (uint64_t)extern_fn->handler());
} else {
// Unimplemented - call dummy.
e.mov(e.rdx, (uint64_t)extern_fn);
e.mov(e.rax, (uint64_t)UnimplementedExtern);
}
} else {
// Generic call, resolve address.
// TODO(benvanik): caching/etc. For now this makes debugging easier.
e.mov(e.rdx, (uint64_t)symbol_info);
e.mov(e.rax, (uint64_t)ResolveFunctionSymbol);
e.call(e.rax);
e.mov(e.rcx, e.qword[e.rsp + 0]);
e.mov(e.rdx, e.qword[e.rcx + 8]); // membase
}
// Resolve address to the function to call and store in rax.
// TODO(benvanik): caching/etc. For now this makes debugging easier.
e.mov(e.rdx, (uint64_t)symbol_info);
e.mov(e.rax, (uint64_t)ResolveFunctionSymbol);
e.call(e.rax);
e.mov(e.rcx, e.qword[e.rsp + 0]);
e.mov(e.rdx, e.qword[e.rcx + 8]); // membase
// Actually jump/call to rax.
if (flags & CALL_TAIL) {
// TODO(benvanik): adjust stack?
e.add(e.rsp, 72);
@@ -198,6 +178,8 @@ void IssueCall(X64Emitter& e, FunctionInfo* symbol_info, 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;
e.BeginOp(target, r, 0);
if (r != e.rdx) {
@@ -208,6 +190,8 @@ void IssueCallIndirect(X64Emitter& e, Value* target, uint32_t flags) {
e.call(e.rax);
e.mov(e.rcx, e.qword[e.rsp + 0]);
e.mov(e.rdx, e.qword[e.rcx + 8]); // membase
// Actually jump/call to rax.
if (flags & CALL_TAIL) {
// TODO(benvanik): adjust stack?
e.add(e.rsp, 72);
@@ -349,6 +333,17 @@ table->AddSequence(OPCODE_CALL_INDIRECT_TRUE, [](X64Emitter& e, Instr*& i) {
return true;
});
table->AddSequence(OPCODE_CALL_EXTERN, [](X64Emitter& e, Instr*& i) {
auto symbol_info = i->src1.symbol_info;
XEASSERT(symbol_info->behavior() == FunctionInfo::BEHAVIOR_EXTERN);
XEASSERTNOTNULL(symbol_info->extern_handler());
e.mov(e.rdx, (uint64_t)symbol_info->extern_arg0());
e.mov(e.r8, (uint64_t)symbol_info->extern_arg1());
CallNative(e, symbol_info->extern_handler());
i = e.Advance(i);
return true;
});
table->AddSequence(OPCODE_RETURN, [](X64Emitter& e, Instr*& i) {
// If this is the last instruction in the last block, just let us
// fall through.

View File

@@ -21,7 +21,7 @@ using namespace alloy::runtime;
X64Function::X64Function(FunctionInfo* symbol_info) :
machine_code_(NULL), code_size_(0),
GuestFunction(symbol_info) {
Function(symbol_info) {
}
X64Function::~X64Function() {

View File

@@ -20,7 +20,7 @@ namespace backend {
namespace x64 {
class X64Function : public runtime::GuestFunction {
class X64Function : public runtime::Function {
public:
X64Function(runtime::FunctionInfo* symbol_info);
virtual ~X64Function();

View File

@@ -380,8 +380,8 @@ XEEMITTER(mcrf, 0x4C000000, XL )(PPCHIRBuilder& f, InstrData& i) {
// System linkage (A-24)
XEEMITTER(sc, 0x44000002, SC )(PPCHIRBuilder& f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
f.CallExtern(f.symbol_info());
return 0;
}

View File

@@ -557,6 +557,13 @@ void HIRBuilder::CallIndirectTrue(
EndBlock();
}
void HIRBuilder::CallExtern(FunctionInfo* symbol_info) {
Instr* i = AppendInstr(OPCODE_CALL_EXTERN_info, 0);
i->src1.symbol_info = symbol_info;
i->src2.value = i->src3.value = NULL;
EndBlock();
}
void HIRBuilder::Return() {
Instr* i = AppendInstr(OPCODE_RETURN_info, 0);
i->src1.value = i->src2.value = i->src3.value = NULL;

View File

@@ -74,6 +74,7 @@ public:
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 CallExtern(runtime::FunctionInfo* symbol_info);
void Return();
void ReturnTrue(Value* cond);

View File

@@ -94,6 +94,7 @@ enum Opcode {
OPCODE_CALL_TRUE,
OPCODE_CALL_INDIRECT,
OPCODE_CALL_INDIRECT_TRUE,
OPCODE_CALL_EXTERN,
OPCODE_RETURN,
OPCODE_RETURN_TRUE,

View File

@@ -74,6 +74,12 @@ DEFINE_OPCODE(
OPCODE_SIG_X_V_V,
OPCODE_FLAG_BRANCH);
DEFINE_OPCODE(
OPCODE_CALL_EXTERN,
"call_extern",
OPCODE_SIG_X_S,
OPCODE_FLAG_BRANCH);
DEFINE_OPCODE(
OPCODE_RETURN,
"return",

View File

@@ -17,8 +17,9 @@ using namespace alloy;
using namespace alloy::runtime;
Function::Function(Type type, uint64_t address) :
type_(type), address_(address), debug_info_(0) {
Function::Function(FunctionInfo* symbol_info) :
address_(symbol_info->address()),
symbol_info_(symbol_info), debug_info_(0) {
// TODO(benvanik): create on demand?
lock_ = AllocMutex();
}
@@ -77,43 +78,27 @@ int Function::Call(ThreadState* thread_state) {
if (original_thread_state != thread_state) {
ThreadState::Bind(thread_state);
}
int result = CallImpl(thread_state);
int result = 0;
if (symbol_info_->behavior() == FunctionInfo::BEHAVIOR_EXTERN) {
auto handler = symbol_info_->extern_handler();
if (handler) {
handler(thread_state->raw_context(),
symbol_info_->extern_arg0(),
symbol_info_->extern_arg1());
} else {
XELOGW("undefined extern call to %.8X %s",
symbol_info_->address(),
symbol_info_->name());
result = 1;
}
} else {
CallImpl(thread_state);
}
if (original_thread_state != thread_state) {
ThreadState::Bind(original_thread_state);
}
return result;
}
ExternFunction::ExternFunction(
uint64_t address, Handler handler, void* arg0, void* arg1) :
name_(0),
handler_(handler), arg0_(arg0), arg1_(arg1),
Function(Function::EXTERN_FUNCTION, address) {
}
ExternFunction::~ExternFunction() {
if (name_) {
xe_free(name_);
}
}
void ExternFunction::set_name(const char* name) {
name_ = xestrdupa(name);
}
int ExternFunction::CallImpl(ThreadState* thread_state) {
if (!handler_) {
XELOGW("undefined extern call to %.8X %s", address(), name());
return 0;
}
handler_(thread_state->raw_context(), arg0_, arg1_);
return 0;
}
GuestFunction::GuestFunction(FunctionInfo* symbol_info) :
symbol_info_(symbol_info),
Function(Function::USER_FUNCTION, symbol_info->address()) {
}
GuestFunction::~GuestFunction() {
}

View File

@@ -24,17 +24,11 @@ class ThreadState;
class Function {
public:
enum Type {
UNKNOWN_FUNCTION = 0,
EXTERN_FUNCTION,
USER_FUNCTION,
};
public:
Function(Type type, uint64_t address);
Function(FunctionInfo* symbol_info);
virtual ~Function();
Type type() const { return type_; }
uint64_t address() const { return address_; }
FunctionInfo* symbol_info() const { return symbol_info_; }
DebugInfo* debug_info() const { return debug_info_; }
void set_debug_info(DebugInfo* debug_info) { debug_info_ = debug_info; }
@@ -51,8 +45,8 @@ protected:
virtual int CallImpl(ThreadState* thread_state) = 0;
protected:
Type type_;
uint64_t address_;
FunctionInfo* symbol_info_;
DebugInfo* debug_info_;
// TODO(benvanik): move elsewhere? DebugData?
@@ -61,43 +55,6 @@ protected:
};
class ExternFunction : public Function {
public:
typedef void(*Handler)(void* context, void* arg0, void* arg1);
public:
ExternFunction(uint64_t address, Handler handler, void* arg0, void* arg1);
virtual ~ExternFunction();
const char* name() const { return name_; }
void set_name(const char* name);
Handler handler() const { return handler_; }
void* arg0() const { return arg0_; }
void* arg1() const { return arg1_; }
protected:
virtual int CallImpl(ThreadState* thread_state);
protected:
char* name_;
Handler handler_;
void* arg0_;
void* arg1_;
};
class GuestFunction : public Function {
public:
GuestFunction(FunctionInfo* symbol_info);
virtual ~GuestFunction();
FunctionInfo* symbol_info() const { return symbol_info_; }
protected:
FunctionInfo* symbol_info_;
};
} // namespace runtime
} // namespace alloy

View File

@@ -34,11 +34,19 @@ void SymbolInfo::set_name(const char* name) {
FunctionInfo::FunctionInfo(Module* module, uint64_t address) :
end_address_(0), behavior_(BEHAVIOR_DEFAULT), function_(0),
SymbolInfo(SymbolInfo::TYPE_FUNCTION, module, address) {
xe_zero_struct(&extern_info_, sizeof(extern_info_));
}
FunctionInfo::~FunctionInfo() {
}
void FunctionInfo::SetupExtern(ExternHandler handler, void* arg0, void* arg1) {
behavior_ = BEHAVIOR_EXTERN;
extern_info_.handler = handler;
extern_info_.arg0 = arg0;
extern_info_.arg1 = arg1;
}
VariableInfo::VariableInfo(Module* module, uint64_t address) :
SymbolInfo(SymbolInfo::TYPE_VARIABLE, module, address) {
}

View File

@@ -63,6 +63,7 @@ public:
BEHAVIOR_PROLOG,
BEHAVIOR_EPILOG,
BEHAVIOR_EPILOG_RETURN,
BEHAVIOR_EXTERN,
};
public:
@@ -79,10 +80,21 @@ public:
Function* function() const { return function_; }
void set_function(Function* value) { function_ = value; }
typedef void(*ExternHandler)(void* context, void* arg0, void* arg1);
void SetupExtern(ExternHandler handler, void* arg0, void* arg1);
ExternHandler extern_handler() const { return extern_info_.handler; }
void* extern_arg0() const { return extern_info_.arg0; }
void* extern_arg1() const { return extern_info_.arg1; }
private:
uint64_t end_address_;
Behavior behavior_;
Function* function_;
struct {
ExternHandler handler;
void* arg0;
void* arg1;
} extern_info_;
};
class VariableInfo : public SymbolInfo {