mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 23:32:02 +00:00
- implement throwing by storing exception information in a struct, then return from the jitted function and throw from c++
This commit is contained in:
parent
b6f52c319a
commit
3453f05f06
5 changed files with 70 additions and 29 deletions
|
@ -292,22 +292,6 @@ static int64_t ToMemAddress(const void *d)
|
|||
return (int64_t)(ptrdiff_t)d;
|
||||
}
|
||||
|
||||
void setPCOnAbort(VMScriptFunction *sfunc, VMOP* pc) {
|
||||
sfunc->pcOnJitAbort = pc;
|
||||
}
|
||||
|
||||
void emitAbortExceptionCall(asmjit::X86Compiler& cc, VMScriptFunction* sfunc, const VMOP* pc, EVMAbortException reason, const char* moreinfo) {
|
||||
using namespace asmjit;
|
||||
|
||||
CCFuncCall* setPCCall = cc.call(imm_ptr((void*)setPCOnAbort), FuncSignature2<void, VMScriptFunction*, VMOP*>(CallConv::kIdHost));
|
||||
setPCCall->setArg(0, imm_ptr(sfunc));
|
||||
setPCCall->setArg(1, imm_ptr(pc));
|
||||
|
||||
CCFuncCall* throwAbortCall = cc.call(imm_ptr((void*)ThrowAbortException), FuncSignatureT<void, int, const char*>(CallConv::kIdHost));
|
||||
throwAbortCall->setArg(0, imm(reason));
|
||||
throwAbortCall->setArg(1, imm_ptr(moreinfo));
|
||||
}
|
||||
|
||||
static void CallSqrt(asmjit::X86Compiler& cc, const asmjit::X86Xmm &a, const asmjit::X86Xmm &b)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
@ -317,6 +301,43 @@ static void CallSqrt(asmjit::X86Compiler& cc, const asmjit::X86Xmm &a, const asm
|
|||
call->setArg(0, b);
|
||||
}
|
||||
|
||||
static void EmitThrowException(asmjit::X86Compiler& cc, asmjit::X86Gp exceptInfo, const VMOP* pc, EVMAbortException reason)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
// Update JitExceptionInfo struct
|
||||
cc.mov(x86::dword_ptr(exceptInfo, 0 * 4), (int32_t)reason);
|
||||
#ifdef ASMJIT_ARCH_X64
|
||||
cc.mov(x86::qword_ptr(exceptInfo, 4 * 4), ToMemAddress(pc));
|
||||
#else
|
||||
cc.mov(x86::dword_ptr(exceptInfo, 4 * 4), ToMemAddress(pc));
|
||||
#endif
|
||||
|
||||
// Return from function
|
||||
X86Gp vReg = cc.newInt32();
|
||||
cc.mov(vReg, 0);
|
||||
cc.ret(vReg);
|
||||
}
|
||||
|
||||
static void EmitThrowException(asmjit::X86Compiler& cc, asmjit::X86Gp exceptInfo, const VMOP* pc, EVMAbortException reason, asmjit::X86Gp arg1)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
// Update JitExceptionInfo struct
|
||||
cc.mov(x86::dword_ptr(exceptInfo, 0 * 4), (int32_t)reason);
|
||||
cc.mov(x86::dword_ptr(exceptInfo, 1 * 4), arg1);
|
||||
#ifdef ASMJIT_ARCH_X64
|
||||
cc.mov(x86::qword_ptr(exceptInfo, 4 * 4), ToMemAddress(pc));
|
||||
#else
|
||||
cc.mov(x86::dword_ptr(exceptInfo, 4 * 4), ToMemAddress(pc));
|
||||
#endif
|
||||
|
||||
// Return from function
|
||||
X86Gp vReg = cc.newInt32();
|
||||
cc.mov(vReg, 0);
|
||||
cc.ret(vReg);
|
||||
}
|
||||
|
||||
JitFuncPtr JitCompile(VMScriptFunction *sfunc)
|
||||
{
|
||||
#if 0 // For debugging
|
||||
|
@ -345,12 +366,14 @@ JitFuncPtr JitCompile(VMScriptFunction *sfunc)
|
|||
X86Gp vmregs = cc.newIntPtr("vmregs"); // void *vmregs
|
||||
X86Gp ret = cc.newIntPtr("ret"); // VMReturn *ret
|
||||
X86Gp numret = cc.newInt32("numret"); // int numret
|
||||
X86Gp exceptInfo = cc.newIntPtr("exceptinfo"); // JitExceptionInfo *exceptInfo
|
||||
|
||||
cc.addFunc(FuncSignature4<int, void *, void *, void *, int>());
|
||||
cc.addFunc(FuncSignature5<int, void *, void *, void *, int, void *>());
|
||||
cc.setArg(0, stack);
|
||||
cc.setArg(1, vmregs);
|
||||
cc.setArg(2, ret);
|
||||
cc.setArg(3, numret);
|
||||
cc.setArg(4, exceptInfo);
|
||||
|
||||
const int *konstd = sfunc->KonstD;
|
||||
const double *konstf = sfunc->KonstF;
|
||||
|
@ -929,7 +952,7 @@ JitFuncPtr JitCompile(VMScriptFunction *sfunc)
|
|||
cc.mov(regD[A], tmp0);
|
||||
|
||||
cc.bind(label);
|
||||
emitAbortExceptionCall(cc, sfunc, pc, X_DIVISION_BY_ZERO, nullptr);
|
||||
EmitThrowException(cc, exceptInfo, pc, X_DIVISION_BY_ZERO);
|
||||
break;
|
||||
}
|
||||
case OP_DIV_RK:
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
#include "scripting/backend/scopebarrier.h"
|
||||
|
||||
class DObject;
|
||||
union VMOP;
|
||||
class VMScriptFunction;
|
||||
|
||||
extern FMemArena ClassDataAllocator;
|
||||
|
||||
|
@ -104,6 +106,7 @@ public:
|
|||
|
||||
// This must be a separate function because the VC compiler would otherwise allocate memory on the stack for every separate instance of the exception object that may get thrown.
|
||||
void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...);
|
||||
void ThrowAbortException(VMScriptFunction *sfunc, VMOP *line, EVMAbortException reason, const char *moreinfo, ...);
|
||||
|
||||
struct VMReturn
|
||||
{
|
||||
|
|
|
@ -80,17 +80,16 @@ static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret)
|
|||
sfunc->JitFunc = JitCompile(sfunc);
|
||||
sfunc->JitCompiled = true;
|
||||
}
|
||||
if (sfunc->JitFunc) {
|
||||
try {
|
||||
return sfunc->JitFunc(stack, ®, ret, numret);
|
||||
}
|
||||
catch (CVMAbortException &err)
|
||||
if (sfunc->JitFunc)
|
||||
{
|
||||
err.MaybePrintMessage();
|
||||
err.stacktrace.AppendFormat("Called from %s at %s, line %d\n", sfunc->PrintableName.GetChars(), sfunc->SourceFileName.GetChars(), sfunc->PCToLine(sfunc->pcOnJitAbort));
|
||||
// PrintParameters(reg.param + f->NumParam - B, B);
|
||||
throw;
|
||||
JitExceptionInfo exceptInfo;
|
||||
exceptInfo.reason = -1;
|
||||
int result = sfunc->JitFunc(stack, ®, ret, numret, &exceptInfo);
|
||||
if (exceptInfo.reason != -1)
|
||||
{
|
||||
ThrowAbortException(sfunc, exceptInfo.pcOnJitAbort, (EVMAbortException)exceptInfo.reason, nullptr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -577,6 +577,16 @@ void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...)
|
|||
va_end(ap);
|
||||
}
|
||||
|
||||
void ThrowAbortException(VMScriptFunction *sfunc, VMOP *line, EVMAbortException reason, const char *moreinfo, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, moreinfo);
|
||||
CVMAbortException err(reason, moreinfo, ap);
|
||||
err.stacktrace.AppendFormat("Called from %s at %s, line %d\n", sfunc->PrintableName.GetChars(), sfunc->SourceFileName.GetChars(), sfunc->PCToLine(line));
|
||||
throw err;
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(DObject, ThrowAbortException)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
|
|
|
@ -437,7 +437,14 @@ extern thread_local VMFrameStack GlobalVMStack;
|
|||
|
||||
typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
|
||||
|
||||
typedef int(*JitFuncPtr)(VMFrameStack *stack, const void *vmregs, VMReturn *ret, int numret);
|
||||
struct JitExceptionInfo
|
||||
{
|
||||
int32_t reason; // EVMAbortException
|
||||
int32_t args[3];
|
||||
VMOP* pcOnJitAbort;
|
||||
};
|
||||
|
||||
typedef int(*JitFuncPtr)(VMFrameStack *stack, const void *vmregs, VMReturn *ret, int numret, JitExceptionInfo *exceptInfo);
|
||||
|
||||
class VMScriptFunction : public VMFunction
|
||||
{
|
||||
|
@ -471,7 +478,6 @@ public:
|
|||
|
||||
bool JitCompiled = false;
|
||||
JitFuncPtr JitFunc = nullptr;
|
||||
VMOP* pcOnJitAbort = nullptr;
|
||||
|
||||
void InitExtra(void *addr);
|
||||
void DestroyExtra(void *addr);
|
||||
|
|
Loading…
Reference in a new issue