mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-12-01 00:12:27 +00:00
- do script calls directly from asmjit without using a lambda wrapper
- do VARF_Native check at compile time when possible
This commit is contained in:
parent
01825231ec
commit
b6bc06e568
2 changed files with 162 additions and 49 deletions
|
@ -126,29 +126,33 @@ void JitCompiler::EmitRESULT()
|
||||||
|
|
||||||
void JitCompiler::EmitCALL()
|
void JitCompiler::EmitCALL()
|
||||||
{
|
{
|
||||||
EmitDoCall(regA[A]);
|
EmitDoCall(regA[A], CallType::Unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitCompiler::EmitCALL_K()
|
void JitCompiler::EmitCALL_K()
|
||||||
{
|
{
|
||||||
|
VMFunction *func = (VMFunction*)konsta[A].o;
|
||||||
|
|
||||||
auto ptr = newTempIntPtr();
|
auto ptr = newTempIntPtr();
|
||||||
cc.mov(ptr, asmjit::imm_ptr(konsta[A].o));
|
cc.mov(ptr, asmjit::imm_ptr(func));
|
||||||
EmitDoCall(ptr);
|
EmitDoCall(ptr, (func->VarFlags & VARF_Native) ? CallType::Native : CallType::Script);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitCompiler::EmitTAIL()
|
void JitCompiler::EmitTAIL()
|
||||||
{
|
{
|
||||||
EmitDoTail(regA[A]);
|
EmitDoTail(regA[A], CallType::Unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitCompiler::EmitTAIL_K()
|
void JitCompiler::EmitTAIL_K()
|
||||||
{
|
{
|
||||||
|
VMFunction *func = (VMFunction*)konsta[A].o;
|
||||||
|
|
||||||
auto ptr = newTempIntPtr();
|
auto ptr = newTempIntPtr();
|
||||||
cc.mov(ptr, asmjit::imm_ptr(konsta[A].o));
|
cc.mov(ptr, asmjit::imm_ptr(func));
|
||||||
EmitDoTail(ptr);
|
EmitDoTail(ptr, (func->VarFlags & VARF_Native) ? CallType::Native : CallType::Script);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitCompiler::EmitDoCall(asmjit::X86Gp ptr)
|
void JitCompiler::EmitDoCall(asmjit::X86Gp vmfunc, CallType calltype)
|
||||||
{
|
{
|
||||||
using namespace asmjit;
|
using namespace asmjit;
|
||||||
|
|
||||||
|
@ -169,14 +173,28 @@ void JitCompiler::EmitDoCall(asmjit::X86Gp ptr)
|
||||||
paramsptr = params;
|
paramsptr = params;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = newResultInt32();
|
if (calltype == CallType::Script)
|
||||||
auto call = CreateCall<int, VMFunction*, int, int, VMValue*, VMReturn*>(&JitCompiler::DoCall);
|
{
|
||||||
call->setRet(0, result);
|
EmitScriptCall(vmfunc, paramsptr);
|
||||||
call->setArg(0, ptr);
|
}
|
||||||
call->setArg(1, Imm(B));
|
else if (calltype == CallType::Native)
|
||||||
call->setArg(2, Imm(C));
|
{
|
||||||
call->setArg(3, paramsptr);
|
EmitNativeCall(vmfunc, paramsptr);
|
||||||
call->setArg(4, callReturns);
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
LoadInOuts(B);
|
LoadInOuts(B);
|
||||||
LoadReturns(pc + 1, C);
|
LoadReturns(pc + 1, C);
|
||||||
|
@ -185,7 +203,45 @@ void JitCompiler::EmitDoCall(asmjit::X86Gp ptr)
|
||||||
ParamOpcodes.Resize(ParamOpcodes.Size() - B);
|
ParamOpcodes.Resize(ParamOpcodes.Size() - B);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitCompiler::EmitDoTail(asmjit::X86Gp ptr)
|
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)));
|
||||||
|
|
||||||
|
auto result = newResultInt32();
|
||||||
|
auto call = cc.call(scriptcall, FuncSignature5<int, VMFunction *, VMValue*, int, VMReturn*, int>());
|
||||||
|
call->setRet(0, result);
|
||||||
|
call->setArg(0, vmfunc);
|
||||||
|
call->setArg(1, paramsptr);
|
||||||
|
call->setArg(2, Imm(B));
|
||||||
|
call->setArg(3, callReturns);
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
// Whereas the CALL instruction uses its third operand to specify how many return values
|
// 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.
|
// it expects, TAIL ignores its third operand and uses whatever was passed to this Exec call.
|
||||||
|
@ -211,13 +267,29 @@ void JitCompiler::EmitDoTail(asmjit::X86Gp ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = newResultInt32();
|
auto result = newResultInt32();
|
||||||
auto call = CreateCall<int, VMFunction*, int, int, VMValue*, VMReturn*>(&JitCompiler::DoCall);
|
|
||||||
call->setRet(0, result);
|
if (calltype == CallType::Script)
|
||||||
call->setArg(0, ptr);
|
{
|
||||||
call->setArg(1, Imm(B));
|
EmitScriptTailCall(vmfunc, result, paramsptr);
|
||||||
call->setArg(2, numret);
|
}
|
||||||
call->setArg(3, paramsptr);
|
else if (calltype == CallType::Native)
|
||||||
call->setArg(4, ret);
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
EmitPopFrame();
|
EmitPopFrame();
|
||||||
cc.ret(result);
|
cc.ret(result);
|
||||||
|
@ -226,6 +298,43 @@ void JitCompiler::EmitDoTail(asmjit::X86Gp ptr)
|
||||||
ParamOpcodes.Resize(ParamOpcodes.Size() - B);
|
ParamOpcodes.Resize(ParamOpcodes.Size() - B);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JitCompiler::EmitScriptTailCall(asmjit::X86Gp vmfunc, asmjit::X86Gp result, 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)));
|
||||||
|
|
||||||
|
auto call = cc.call(scriptcall, FuncSignature5<int, VMFunction *, VMValue*, int, VMReturn*, int>());
|
||||||
|
call->setRet(0, result);
|
||||||
|
call->setArg(0, vmfunc);
|
||||||
|
call->setArg(1, paramsptr);
|
||||||
|
call->setArg(2, Imm(B));
|
||||||
|
call->setArg(3, ret);
|
||||||
|
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)
|
void JitCompiler::StoreInOuts(int b)
|
||||||
{
|
{
|
||||||
using namespace asmjit;
|
using namespace asmjit;
|
||||||
|
@ -389,34 +498,24 @@ void JitCompiler::FillReturns(const VMOP *retval, int numret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int JitCompiler::DoCall(VMFunction *call, int b, int c, VMValue *param, VMReturn *returns)
|
int JitCompiler::DoNativeCall(VMFunction *call, int b, int c, VMValue *param, VMReturn *returns)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int numret;
|
|
||||||
if (call->VarFlags & VARF_Native)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
assert((call->VarFlags & VARF_Native) && "DoNativeCall must only be called for native functions");
|
||||||
|
|
||||||
VMCycles[0].Unclock();
|
VMCycles[0].Unclock();
|
||||||
numret = static_cast<VMNativeFunction *>(call)->NativeCall(param, call->DefaultArgs, b, returns, c);
|
int numret = static_cast<VMNativeFunction *>(call)->NativeCall(param, call->DefaultArgs, b, returns, c);
|
||||||
VMCycles[0].Clock();
|
VMCycles[0].Clock();
|
||||||
|
|
||||||
|
return numret;
|
||||||
}
|
}
|
||||||
catch (CVMAbortException &err)
|
catch (CVMAbortException &err)
|
||||||
{
|
{
|
||||||
err.MaybePrintMessage();
|
err.MaybePrintMessage();
|
||||||
err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName.GetChars());
|
err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName.GetChars());
|
||||||
throw;
|
VMThrowException(std::current_exception());
|
||||||
}
|
return 0;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VMCalls[0]++;
|
|
||||||
auto sfunc = static_cast<VMScriptFunction *>(call);
|
|
||||||
numret = sfunc->ScriptCall(sfunc, param, b, returns, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
return numret;
|
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,14 +42,28 @@ private:
|
||||||
void EmitOpcode();
|
void EmitOpcode();
|
||||||
void EmitPopFrame();
|
void EmitPopFrame();
|
||||||
|
|
||||||
void EmitDoCall(asmjit::X86Gp ptr);
|
enum class CallType
|
||||||
void EmitDoTail(asmjit::X86Gp ptr);
|
{
|
||||||
|
Unknown,
|
||||||
|
Script,
|
||||||
|
Native
|
||||||
|
};
|
||||||
|
|
||||||
|
void EmitDoCall(asmjit::X86Gp ptr, CallType calltype);
|
||||||
|
void EmitScriptCall(asmjit::X86Gp vmfunc, asmjit::X86Gp paramsptr);
|
||||||
|
void EmitNativeCall(asmjit::X86Gp vmfunc, asmjit::X86Gp paramsptr);
|
||||||
|
|
||||||
|
void EmitDoTail(asmjit::X86Gp ptr, CallType calltype);
|
||||||
|
void EmitScriptTailCall(asmjit::X86Gp vmfunc, asmjit::X86Gp result, asmjit::X86Gp paramsptr);
|
||||||
|
void EmitNativeTailCall(asmjit::X86Gp vmfunc, asmjit::X86Gp result, asmjit::X86Gp paramsptr);
|
||||||
|
|
||||||
void StoreInOuts(int b);
|
void StoreInOuts(int b);
|
||||||
void LoadInOuts(int b);
|
void LoadInOuts(int b);
|
||||||
void LoadReturns(const VMOP *retval, int numret);
|
void LoadReturns(const VMOP *retval, int numret);
|
||||||
void FillReturns(const VMOP *retval, int numret);
|
void FillReturns(const VMOP *retval, int numret);
|
||||||
void LoadCallResult(const VMOP &opdata, bool addrof);
|
void LoadCallResult(const VMOP &opdata, bool addrof);
|
||||||
static int DoCall(VMFunction *call, int b, int c, VMValue *param, VMReturn *returns);
|
|
||||||
|
static int DoNativeCall(VMFunction *call, int b, int c, VMValue *param, VMReturn *returns);
|
||||||
|
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
void EmitComparisonOpcode(Func jmpFunc)
|
void EmitComparisonOpcode(Func jmpFunc)
|
||||||
|
|
Loading…
Reference in a new issue