mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-30 15:52:09 +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()
|
||||
{
|
||||
EmitDoCall(regA[A]);
|
||||
EmitDoCall(regA[A], CallType::Unknown);
|
||||
}
|
||||
|
||||
void JitCompiler::EmitCALL_K()
|
||||
{
|
||||
VMFunction *func = (VMFunction*)konsta[A].o;
|
||||
|
||||
auto ptr = newTempIntPtr();
|
||||
cc.mov(ptr, asmjit::imm_ptr(konsta[A].o));
|
||||
EmitDoCall(ptr);
|
||||
cc.mov(ptr, asmjit::imm_ptr(func));
|
||||
EmitDoCall(ptr, (func->VarFlags & VARF_Native) ? CallType::Native : CallType::Script);
|
||||
}
|
||||
|
||||
void JitCompiler::EmitTAIL()
|
||||
{
|
||||
EmitDoTail(regA[A]);
|
||||
EmitDoTail(regA[A], CallType::Unknown);
|
||||
}
|
||||
|
||||
void JitCompiler::EmitTAIL_K()
|
||||
{
|
||||
VMFunction *func = (VMFunction*)konsta[A].o;
|
||||
|
||||
auto ptr = newTempIntPtr();
|
||||
cc.mov(ptr, asmjit::imm_ptr(konsta[A].o));
|
||||
EmitDoTail(ptr);
|
||||
cc.mov(ptr, asmjit::imm_ptr(func));
|
||||
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;
|
||||
|
||||
|
@ -169,14 +173,28 @@ void JitCompiler::EmitDoCall(asmjit::X86Gp ptr)
|
|||
paramsptr = params;
|
||||
}
|
||||
|
||||
auto result = newResultInt32();
|
||||
auto call = CreateCall<int, VMFunction*, int, int, VMValue*, VMReturn*>(&JitCompiler::DoCall);
|
||||
call->setRet(0, result);
|
||||
call->setArg(0, ptr);
|
||||
call->setArg(1, Imm(B));
|
||||
call->setArg(2, Imm(C));
|
||||
call->setArg(3, paramsptr);
|
||||
call->setArg(4, callReturns);
|
||||
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);
|
||||
}
|
||||
|
||||
LoadInOuts(B);
|
||||
LoadReturns(pc + 1, C);
|
||||
|
@ -185,7 +203,45 @@ void JitCompiler::EmitDoCall(asmjit::X86Gp ptr)
|
|||
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
|
||||
// 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 call = CreateCall<int, VMFunction*, int, int, VMValue*, VMReturn*>(&JitCompiler::DoCall);
|
||||
call->setRet(0, result);
|
||||
call->setArg(0, ptr);
|
||||
call->setArg(1, Imm(B));
|
||||
call->setArg(2, numret);
|
||||
call->setArg(3, paramsptr);
|
||||
call->setArg(4, ret);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
EmitPopFrame();
|
||||
cc.ret(result);
|
||||
|
@ -226,6 +298,43 @@ void JitCompiler::EmitDoTail(asmjit::X86Gp ptr)
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
try
|
||||
{
|
||||
int numret;
|
||||
if (call->VarFlags & VARF_Native)
|
||||
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();
|
||||
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();
|
||||
|
||||
return numret;
|
||||
}
|
||||
catch (CVMAbortException &err)
|
||||
{
|
||||
err.MaybePrintMessage();
|
||||
err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName.GetChars());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VMCalls[0]++;
|
||||
auto sfunc = static_cast<VMScriptFunction *>(call);
|
||||
numret = sfunc->ScriptCall(sfunc, param, b, returns, c);
|
||||
}
|
||||
|
||||
return numret;
|
||||
VMThrowException(std::current_exception());
|
||||
return 0;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
|
|
@ -42,14 +42,28 @@ private:
|
|||
void EmitOpcode();
|
||||
void EmitPopFrame();
|
||||
|
||||
void EmitDoCall(asmjit::X86Gp ptr);
|
||||
void EmitDoTail(asmjit::X86Gp ptr);
|
||||
enum class CallType
|
||||
{
|
||||
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 LoadInOuts(int b);
|
||||
void LoadReturns(const VMOP *retval, int numret);
|
||||
void FillReturns(const VMOP *retval, int numret);
|
||||
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>
|
||||
void EmitComparisonOpcode(Func jmpFunc)
|
||||
|
|
Loading…
Reference in a new issue