- remove the need to do any VARF_Native runtime checks by making native functions use the same calling convention as the script version

This commit is contained in:
Magnus Norddahl 2018-10-10 23:47:56 +02:00
commit 0120ea190c
8 changed files with 68 additions and 157 deletions

View file

@ -106,7 +106,6 @@ void JitCompiler::EmitPARAM()
I_FatalError("Unknown REGT value passed to EmitPARAM\n");
break;
}
}
void JitCompiler::EmitPARAMI()
@ -126,33 +125,29 @@ void JitCompiler::EmitRESULT()
void JitCompiler::EmitCALL()
{
EmitDoCall(regA[A], CallType::Unknown);
EmitDoCall(regA[A]);
}
void JitCompiler::EmitCALL_K()
{
VMFunction *func = (VMFunction*)konsta[A].o;
auto ptr = newTempIntPtr();
cc.mov(ptr, asmjit::imm_ptr(func));
EmitDoCall(ptr, (func->VarFlags & VARF_Native) ? CallType::Native : CallType::Script);
cc.mov(ptr, asmjit::imm_ptr(konsta[A].o));
EmitDoCall(ptr);
}
void JitCompiler::EmitTAIL()
{
EmitDoTail(regA[A], CallType::Unknown);
EmitDoTail(regA[A]);
}
void JitCompiler::EmitTAIL_K()
{
VMFunction *func = (VMFunction*)konsta[A].o;
auto ptr = newTempIntPtr();
cc.mov(ptr, asmjit::imm_ptr(func));
EmitDoTail(ptr, (func->VarFlags & VARF_Native) ? CallType::Native : CallType::Script);
cc.mov(ptr, asmjit::imm_ptr(konsta[A].o));
EmitDoTail(ptr);
}
void JitCompiler::EmitDoCall(asmjit::X86Gp vmfunc, CallType calltype)
void JitCompiler::EmitDoCall(asmjit::X86Gp vmfunc)
{
using namespace asmjit;
@ -173,28 +168,7 @@ void JitCompiler::EmitDoCall(asmjit::X86Gp vmfunc, CallType calltype)
paramsptr = params;
}
if (calltype == CallType::Script)
{
EmitScriptCall(vmfunc, paramsptr);
}
else if (calltype == CallType::Native)
{
EmitNativeCall(vmfunc, paramsptr);
}
else
{
auto nativecall = cc.newLabel();
auto endcall = cc.newLabel();
auto varflags = newTempInt32();
cc.mov(varflags, x86::dword_ptr(vmfunc, offsetof(VMFunction, VarFlags)));
cc.test(varflags, (int)VARF_Native);
cc.jnz(nativecall);
EmitScriptCall(vmfunc, paramsptr);
cc.jmp(endcall);
cc.bind(nativecall);
EmitNativeCall(vmfunc, paramsptr);
cc.bind(endcall);
}
EmitScriptCall(vmfunc, paramsptr);
LoadInOuts(B);
LoadReturns(pc + 1, C);
@ -207,14 +181,6 @@ void JitCompiler::EmitScriptCall(asmjit::X86Gp vmfunc, asmjit::X86Gp paramsptr)
{
using namespace asmjit;
// VMCalls[0]++
auto vmcallsptr = newTempIntPtr();
auto vmcalls = newTempInt32();
cc.mov(vmcallsptr, imm_ptr(VMCalls));
cc.mov(vmcalls, x86::dword_ptr(vmcallsptr));
cc.add(vmcalls, (int)1);
cc.mov(x86::dword_ptr(vmcallsptr), vmcalls);
auto scriptcall = newTempIntPtr();
cc.mov(scriptcall, x86::ptr(vmfunc, offsetof(VMScriptFunction, ScriptCall)));
@ -228,20 +194,7 @@ void JitCompiler::EmitScriptCall(asmjit::X86Gp vmfunc, asmjit::X86Gp paramsptr)
call->setArg(4, Imm(C));
}
void JitCompiler::EmitNativeCall(asmjit::X86Gp vmfunc, asmjit::X86Gp paramsptr)
{
using namespace asmjit;
auto result = newResultInt32();
auto call = CreateCall<int, VMFunction*, int, int, VMValue*, VMReturn*>(&JitCompiler::DoNativeCall);
call->setRet(0, result);
call->setArg(0, vmfunc);
call->setArg(1, Imm(B));
call->setArg(2, Imm(C));
call->setArg(3, paramsptr);
call->setArg(4, callReturns);
}
void JitCompiler::EmitDoTail(asmjit::X86Gp vmfunc, CallType calltype)
void JitCompiler::EmitDoTail(asmjit::X86Gp vmfunc)
{
// Whereas the CALL instruction uses its third operand to specify how many return values
// it expects, TAIL ignores its third operand and uses whatever was passed to this Exec call.
@ -268,28 +221,7 @@ void JitCompiler::EmitDoTail(asmjit::X86Gp vmfunc, CallType calltype)
auto result = newResultInt32();
if (calltype == CallType::Script)
{
EmitScriptTailCall(vmfunc, result, paramsptr);
}
else if (calltype == CallType::Native)
{
EmitNativeTailCall(vmfunc, result, paramsptr);
}
else
{
auto nativecall = cc.newLabel();
auto endcall = cc.newLabel();
auto varflags = newTempInt32();
cc.mov(varflags, x86::dword_ptr(vmfunc, offsetof(VMFunction, VarFlags)));
cc.test(varflags, (int)VARF_Native);
cc.jnz(nativecall);
EmitScriptTailCall(vmfunc, result, paramsptr);
cc.jmp(endcall);
cc.bind(nativecall);
EmitNativeTailCall(vmfunc, result, paramsptr);
cc.bind(endcall);
}
EmitScriptTailCall(vmfunc, result, paramsptr);
EmitPopFrame();
cc.ret(result);
@ -302,14 +234,6 @@ void JitCompiler::EmitScriptTailCall(asmjit::X86Gp vmfunc, asmjit::X86Gp result,
{
using namespace asmjit;
// VMCalls[0]++
auto vmcallsptr = newTempIntPtr();
auto vmcalls = newTempInt32();
cc.mov(vmcallsptr, imm_ptr(VMCalls));
cc.mov(vmcalls, x86::dword_ptr(vmcallsptr));
cc.add(vmcalls, (int)1);
cc.mov(x86::dword_ptr(vmcallsptr), vmcalls);
auto scriptcall = newTempIntPtr();
cc.mov(scriptcall, x86::ptr(vmfunc, offsetof(VMScriptFunction, ScriptCall)));
@ -322,19 +246,6 @@ void JitCompiler::EmitScriptTailCall(asmjit::X86Gp vmfunc, asmjit::X86Gp result,
call->setArg(4, numret);
}
void JitCompiler::EmitNativeTailCall(asmjit::X86Gp vmfunc, asmjit::X86Gp result, asmjit::X86Gp paramsptr)
{
using namespace asmjit;
auto call = CreateCall<int, VMFunction*, int, int, VMValue*, VMReturn*>(&JitCompiler::DoNativeCall);
call->setRet(0, result);
call->setArg(0, vmfunc);
call->setArg(1, Imm(B));
call->setArg(2, numret);
call->setArg(3, paramsptr);
call->setArg(4, ret);
}
void JitCompiler::StoreInOuts(int b)
{
using namespace asmjit;
@ -497,29 +408,3 @@ void JitCompiler::FillReturns(const VMOP *retval, int numret)
cc.mov(x86::byte_ptr(callReturns, i * sizeof(VMReturn) + offsetof(VMReturn, RegType)), type);
}
}
int JitCompiler::DoNativeCall(VMFunction *call, int b, int c, VMValue *param, VMReturn *returns)
{
try
{
assert((call->VarFlags & VARF_Native) && "DoNativeCall must only be called for native functions");
VMCycles[0].Unclock();
int numret = static_cast<VMNativeFunction *>(call)->NativeCall(param, call->DefaultArgs, b, returns, c);
VMCycles[0].Clock();
return numret;
}
catch (CVMAbortException &err)
{
err.MaybePrintMessage();
err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName.GetChars());
VMThrowException(std::current_exception());
return 0;
}
catch (...)
{
VMThrowException(std::current_exception());
return 0;
}
}