mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-24 21:11:39 +00:00
- 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:
parent
b6bc06e568
commit
0120ea190c
8 changed files with 68 additions and 157 deletions
|
@ -250,6 +250,14 @@ void JitCompiler::Setup()
|
|||
for (int i = 0; i < size; i++)
|
||||
labels[i] = cc.newLabel();
|
||||
|
||||
// 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);
|
||||
|
||||
frameD = cc.newIntPtr();
|
||||
frameF = cc.newIntPtr();
|
||||
frameS = cc.newIntPtr();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,20 +42,11 @@ private:
|
|||
void EmitOpcode();
|
||||
void EmitPopFrame();
|
||||
|
||||
enum class CallType
|
||||
{
|
||||
Unknown,
|
||||
Script,
|
||||
Native
|
||||
};
|
||||
|
||||
void EmitDoCall(asmjit::X86Gp ptr, CallType calltype);
|
||||
void EmitDoCall(asmjit::X86Gp ptr);
|
||||
void EmitScriptCall(asmjit::X86Gp vmfunc, asmjit::X86Gp paramsptr);
|
||||
void EmitNativeCall(asmjit::X86Gp vmfunc, asmjit::X86Gp paramsptr);
|
||||
|
||||
void EmitDoTail(asmjit::X86Gp ptr, CallType calltype);
|
||||
void EmitDoTail(asmjit::X86Gp ptr);
|
||||
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);
|
||||
|
@ -63,8 +54,6 @@ private:
|
|||
void FillReturns(const VMOP *retval, int numret);
|
||||
void LoadCallResult(const VMOP &opdata, bool addrof);
|
||||
|
||||
static int DoNativeCall(VMFunction *call, int b, int c, VMValue *param, VMReturn *returns);
|
||||
|
||||
template <typename Func>
|
||||
void EmitComparisonOpcode(Func jmpFunc)
|
||||
{
|
||||
|
|
|
@ -330,6 +330,8 @@ public:
|
|||
|
||||
class PPrototype *Proto;
|
||||
|
||||
int(*ScriptCall)(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret) = nullptr;
|
||||
|
||||
VMFunction(FName name = NAME_None) : ImplicitArgs(0), Name(name), Proto(NULL)
|
||||
{
|
||||
AllFunctions.Push(this);
|
||||
|
@ -361,12 +363,15 @@ public:
|
|||
typedef int (*NativeCallType)(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);
|
||||
|
||||
// 8 is VARF_Native. I can't write VARF_Native because of circular references between this and dobject/dobjtype.
|
||||
VMNativeFunction() : NativeCall(NULL) { VarFlags = 8; }
|
||||
VMNativeFunction(NativeCallType call) : NativeCall(call) { VarFlags = 8; }
|
||||
VMNativeFunction(NativeCallType call, FName name) : VMFunction(name), NativeCall(call) { VarFlags = 8; }
|
||||
VMNativeFunction() : NativeCall(NULL) { VarFlags = 8; ScriptCall = &VMNativeFunction::NativeScriptCall; }
|
||||
VMNativeFunction(NativeCallType call) : NativeCall(call) { VarFlags = 8; ScriptCall = &VMNativeFunction::NativeScriptCall; }
|
||||
VMNativeFunction(NativeCallType call, FName name) : VMFunction(name), NativeCall(call) { VarFlags = 8; ScriptCall = &VMNativeFunction::NativeScriptCall; }
|
||||
|
||||
// Return value is the number of results.
|
||||
NativeCallType NativeCall;
|
||||
|
||||
private:
|
||||
static int NativeScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret);
|
||||
};
|
||||
|
||||
int VMCall(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults/*, VMException **trap = NULL*/);
|
||||
|
|
|
@ -134,7 +134,7 @@ struct VMExec_Unchecked
|
|||
#undef assert
|
||||
#include <assert.h>
|
||||
|
||||
int (*VMExec)(VMScriptFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret) =
|
||||
int (*VMExec)(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret) =
|
||||
#ifdef NDEBUG
|
||||
VMExec_Unchecked::Exec
|
||||
#else
|
||||
|
|
|
@ -710,7 +710,6 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret)
|
|||
}
|
||||
else
|
||||
{
|
||||
VMCalls[0]++;
|
||||
auto sfunc = static_cast<VMScriptFunction *>(call);
|
||||
numret = sfunc->ScriptCall(sfunc, reg.param + f->NumParam - b, b, returns, C);
|
||||
}
|
||||
|
@ -753,7 +752,6 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret)
|
|||
}
|
||||
else
|
||||
{ // FIXME: Not a true tail call
|
||||
VMCalls[0]++;
|
||||
auto sfunc = static_cast<VMScriptFunction *>(call);
|
||||
return sfunc->ScriptCall(sfunc, reg.param + f->NumParam - B, B, ret, numret);
|
||||
}
|
||||
|
@ -2046,10 +2044,11 @@ static void SetReturn(const VMRegisters ®, VMFrame *frame, VMReturn *ret, VM_
|
|||
}
|
||||
}
|
||||
|
||||
static int Exec(VMScriptFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret)
|
||||
static int Exec(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret)
|
||||
{
|
||||
VMCalls[0]++;
|
||||
VMFrameStack *stack = &GlobalVMStack;
|
||||
VMFrame *newf = stack->AllocFrame(func);
|
||||
VMFrame *newf = stack->AllocFrame(static_cast<VMScriptFunction*>(func));
|
||||
VMFillParams(params, newf, numparams);
|
||||
try
|
||||
{
|
||||
|
|
|
@ -74,6 +74,7 @@ VMScriptFunction::VMScriptFunction(FName name)
|
|||
NumKonstA = 0;
|
||||
MaxParam = 0;
|
||||
NumArgs = 0;
|
||||
ScriptCall = &VMScriptFunction::FirstScriptCall;
|
||||
}
|
||||
|
||||
VMScriptFunction::~VMScriptFunction()
|
||||
|
@ -213,17 +214,44 @@ int VMScriptFunction::PCToLine(const VMOP *pc)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int VMScriptFunction::FirstScriptCall(VMScriptFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret)
|
||||
int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret)
|
||||
{
|
||||
func->ScriptCall = JitCompile(func);
|
||||
if (!func->ScriptCall)
|
||||
func->ScriptCall = VMExec;
|
||||
VMScriptFunction *sfunc = static_cast<VMScriptFunction*>(func);
|
||||
sfunc->ScriptCall = JitCompile(sfunc);
|
||||
if (!sfunc->ScriptCall)
|
||||
sfunc->ScriptCall = VMExec;
|
||||
else
|
||||
func->FunctionJitted = true;
|
||||
sfunc->FunctionJitted = true;
|
||||
|
||||
return func->ScriptCall(func, params, numparams, ret, numret);
|
||||
}
|
||||
|
||||
int VMNativeFunction::NativeScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *returns, int numret)
|
||||
{
|
||||
try
|
||||
{
|
||||
assert((call->VarFlags & VARF_Native) && "DoNativeCall must only be called for native functions");
|
||||
|
||||
VMCycles[0].Unclock();
|
||||
numret = static_cast<VMNativeFunction *>(func)->NativeCall(params, func->DefaultArgs, numparams, returns, numret);
|
||||
VMCycles[0].Clock();
|
||||
|
||||
return numret;
|
||||
}
|
||||
catch (CVMAbortException &err)
|
||||
{
|
||||
err.MaybePrintMessage();
|
||||
err.stacktrace.AppendFormat("Called from %s\n", func->PrintableName.GetChars());
|
||||
VMThrowException(std::current_exception());
|
||||
return 0;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VMThrowException(std::current_exception());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// VMFrame :: InitRegS
|
||||
|
@ -500,7 +528,6 @@ int VMCall(VMFunction *func, VMValue *params, int numparams, VMReturn *results,
|
|||
else
|
||||
{
|
||||
VMCycles[0].Clock();
|
||||
VMCalls[0]++;
|
||||
|
||||
JitExceptionInfo *prevExceptInfo = CurrentJitExceptInfo;
|
||||
JitExceptionInfo newExceptInfo;
|
||||
|
|
|
@ -429,7 +429,7 @@ enum EVMEngine
|
|||
};
|
||||
|
||||
void VMSelectEngine(EVMEngine engine);
|
||||
extern int (*VMExec)(VMScriptFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret);
|
||||
extern int (*VMExec)(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret);
|
||||
void VMFillParams(VMValue *params, VMFrame *callee, int numparam);
|
||||
|
||||
void VMDumpConstants(FILE *out, const VMScriptFunction *func);
|
||||
|
@ -450,7 +450,7 @@ extern thread_local JitExceptionInfo *CurrentJitExceptInfo;
|
|||
|
||||
void VMThrowException(std::exception_ptr cppException);
|
||||
|
||||
typedef int(*JitFuncPtr)(VMScriptFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret);
|
||||
typedef int(*JitFuncPtr)(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret);
|
||||
|
||||
class VMScriptFunction : public VMFunction
|
||||
{
|
||||
|
@ -482,15 +482,13 @@ public:
|
|||
VM_UBYTE NumArgs; // Number of arguments this function takes
|
||||
TArray<FTypeAndOffset> SpecialInits; // list of all contents on the extra stack which require construction and destruction
|
||||
|
||||
int(*ScriptCall)(VMScriptFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret) = &VMScriptFunction::FirstScriptCall;
|
||||
|
||||
void InitExtra(void *addr);
|
||||
void DestroyExtra(void *addr);
|
||||
int AllocExtraStack(PType *type);
|
||||
int PCToLine(const VMOP *pc);
|
||||
|
||||
private:
|
||||
static int FirstScriptCall(VMScriptFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret);
|
||||
static int FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret);
|
||||
|
||||
bool FunctionJitted = false;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue