mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-30 15:52:09 +00:00
- handle JIT errors in a more user-friendly fashion than aborting.
* use I_Error instead of I_FatalError to abort. I_FatalError is only for things that are not recoverable and should not be handled outside of error cleanup and rethrowing. * only catch CRecoverableError in JitCompile. Everything else should fall through to the outermost catch block. * Do not I_FatalError out after handling the exception locally. Just print an error and return null, indicating failure.
This commit is contained in:
parent
45d7e5a038
commit
d7da2d838f
5 changed files with 32 additions and 32 deletions
|
@ -30,10 +30,10 @@ JitFuncPtr JitCompile(VMScriptFunction *sfunc)
|
||||||
|
|
||||||
return reinterpret_cast<JitFuncPtr>(AddJitFunction(&code, func));
|
return reinterpret_cast<JitFuncPtr>(AddJitFunction(&code, func));
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const CRecoverableError &e)
|
||||||
{
|
{
|
||||||
OutputJitLog(logger);
|
OutputJitLog(logger);
|
||||||
I_FatalError("Unexpected JIT error: %s\n", e.what());
|
Printf("%s: Unexpected JIT error: %s\n",sfunc->PrintableName.GetChars(), e.what());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ void JitCompiler::EmitVMCall(asmjit::X86Gp vmfunc, VMFunction *target)
|
||||||
|
|
||||||
int numparams = StoreCallParams();
|
int numparams = StoreCallParams();
|
||||||
if (numparams != B)
|
if (numparams != B)
|
||||||
I_FatalError("OP_CALL parameter count does not match the number of preceding OP_PARAM instructions");
|
I_Error("OP_CALL parameter count does not match the number of preceding OP_PARAM instructions");
|
||||||
|
|
||||||
if ((pc - 1)->op == OP_VTBL)
|
if ((pc - 1)->op == OP_VTBL)
|
||||||
EmitVtbl(pc - 1);
|
EmitVtbl(pc - 1);
|
||||||
|
@ -199,7 +199,7 @@ int JitCompiler::StoreCallParams()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
I_FatalError("Unknown REGT value passed to EmitPARAM\n");
|
I_Error("Unknown REGT value passed to EmitPARAM\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,7 @@ void JitCompiler::LoadReturns(const VMOP *retval, int numret)
|
||||||
for (int i = 0; i < numret; ++i)
|
for (int i = 0; i < numret; ++i)
|
||||||
{
|
{
|
||||||
if (retval[i].op != OP_RESULT)
|
if (retval[i].op != OP_RESULT)
|
||||||
I_FatalError("Expected OP_RESULT to follow OP_CALL\n");
|
I_Error("Expected OP_RESULT to follow OP_CALL\n");
|
||||||
|
|
||||||
LoadCallResult(retval[i].b, retval[i].c, false);
|
LoadCallResult(retval[i].b, retval[i].c, false);
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,7 @@ void JitCompiler::LoadCallResult(int type, int regnum, bool addrof)
|
||||||
cc.mov(regA[regnum], asmjit::x86::ptr(vmframe, offsetA + regnum * sizeof(void*)));
|
cc.mov(regA[regnum], asmjit::x86::ptr(vmframe, offsetA + regnum * sizeof(void*)));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
I_FatalError("Unknown OP_RESULT/OP_PARAM type encountered in LoadCallResult\n");
|
I_Error("Unknown OP_RESULT/OP_PARAM type encountered in LoadCallResult\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,7 +277,7 @@ void JitCompiler::FillReturns(const VMOP *retval, int numret)
|
||||||
{
|
{
|
||||||
if (retval[i].op != OP_RESULT)
|
if (retval[i].op != OP_RESULT)
|
||||||
{
|
{
|
||||||
I_FatalError("Expected OP_RESULT to follow OP_CALL\n");
|
I_Error("Expected OP_RESULT to follow OP_CALL\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int type = retval[i].b;
|
int type = retval[i].b;
|
||||||
|
@ -285,7 +285,7 @@ void JitCompiler::FillReturns(const VMOP *retval, int numret)
|
||||||
|
|
||||||
if (type & REGT_KONST)
|
if (type & REGT_KONST)
|
||||||
{
|
{
|
||||||
I_FatalError("OP_RESULT with REGT_KONST is not allowed\n");
|
I_Error("OP_RESULT with REGT_KONST is not allowed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto regPtr = newTempIntPtr();
|
auto regPtr = newTempIntPtr();
|
||||||
|
@ -305,7 +305,7 @@ void JitCompiler::FillReturns(const VMOP *retval, int numret)
|
||||||
cc.lea(regPtr, x86::ptr(vmframe, offsetA + (int)(regnum * sizeof(void*))));
|
cc.lea(regPtr, x86::ptr(vmframe, offsetA + (int)(regnum * sizeof(void*))));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
I_FatalError("Unknown OP_RESULT type encountered in FillReturns\n");
|
I_Error("Unknown OP_RESULT type encountered in FillReturns\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +320,7 @@ void JitCompiler::EmitNativeCall(VMNativeFunction *target)
|
||||||
|
|
||||||
if ((pc - 1)->op == OP_VTBL)
|
if ((pc - 1)->op == OP_VTBL)
|
||||||
{
|
{
|
||||||
I_FatalError("Native direct member function calls not implemented\n");
|
I_Error("Native direct member function calls not implemented\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
asmjit::CBNode *cursorBefore = cc.getCursor();
|
asmjit::CBNode *cursorBefore = cc.getCursor();
|
||||||
|
@ -397,18 +397,18 @@ void JitCompiler::EmitNativeCall(VMNativeFunction *target)
|
||||||
case REGT_INT | REGT_ADDROF:
|
case REGT_INT | REGT_ADDROF:
|
||||||
case REGT_POINTER | REGT_ADDROF:
|
case REGT_POINTER | REGT_ADDROF:
|
||||||
case REGT_FLOAT | REGT_ADDROF:
|
case REGT_FLOAT | REGT_ADDROF:
|
||||||
I_FatalError("REGT_ADDROF not implemented for native direct calls\n");
|
I_Error("REGT_ADDROF not implemented for native direct calls\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
I_FatalError("Unknown REGT value passed to EmitPARAM\n");
|
I_Error("Unknown REGT value passed to EmitPARAM\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numparams != B)
|
if (numparams != B)
|
||||||
I_FatalError("OP_CALL parameter count does not match the number of preceding OP_PARAM instructions\n");
|
I_Error("OP_CALL parameter count does not match the number of preceding OP_PARAM instructions\n");
|
||||||
|
|
||||||
// Note: the usage of newResultXX is intentional. Asmjit has a register allocation bug
|
// Note: the usage of newResultXX is intentional. Asmjit has a register allocation bug
|
||||||
// if the return virtual register is already allocated in an argument slot.
|
// if the return virtual register is already allocated in an argument slot.
|
||||||
|
@ -441,7 +441,7 @@ void JitCompiler::EmitNativeCall(VMNativeFunction *target)
|
||||||
|
|
||||||
if (type & REGT_KONST)
|
if (type & REGT_KONST)
|
||||||
{
|
{
|
||||||
I_FatalError("OP_RESULT with REGT_KONST is not allowed\n");
|
I_Error("OP_RESULT with REGT_KONST is not allowed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckVMFrame();
|
CheckVMFrame();
|
||||||
|
@ -470,7 +470,7 @@ void JitCompiler::EmitNativeCall(VMNativeFunction *target)
|
||||||
cc.lea(regPtr, x86::ptr(vmframe, offsetA + (int)(regnum * sizeof(void*))));
|
cc.lea(regPtr, x86::ptr(vmframe, offsetA + (int)(regnum * sizeof(void*))));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
I_FatalError("Unknown OP_RESULT type encountered\n");
|
I_Error("Unknown OP_RESULT type encountered\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,7 +535,7 @@ void JitCompiler::EmitNativeCall(VMNativeFunction *target)
|
||||||
cc.mov(regA[regnum], asmjit::x86::ptr(vmframe, offsetA + regnum * sizeof(void*)));
|
cc.mov(regA[regnum], asmjit::x86::ptr(vmframe, offsetA + regnum * sizeof(void*)));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
I_FatalError("Unknown OP_RESULT type encountered\n");
|
I_Error("Unknown OP_RESULT type encountered\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -602,7 +602,7 @@ asmjit::FuncSignature JitCompiler::CreateFuncSignature()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
I_FatalError("Unknown REGT value passed to EmitPARAM\n");
|
I_Error("Unknown REGT value passed to EmitPARAM\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -619,7 +619,7 @@ asmjit::FuncSignature JitCompiler::CreateFuncSignature()
|
||||||
{
|
{
|
||||||
if (retval[0].op != OP_RESULT)
|
if (retval[0].op != OP_RESULT)
|
||||||
{
|
{
|
||||||
I_FatalError("Expected OP_RESULT to follow OP_CALL\n");
|
I_Error("Expected OP_RESULT to follow OP_CALL\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int type = retval[0].b;
|
int type = retval[0].b;
|
||||||
|
@ -649,7 +649,7 @@ asmjit::FuncSignature JitCompiler::CreateFuncSignature()
|
||||||
{
|
{
|
||||||
if (retval[i].op != OP_RESULT)
|
if (retval[i].op != OP_RESULT)
|
||||||
{
|
{
|
||||||
I_FatalError("Expected OP_RESULT to follow OP_CALL\n");
|
I_Error("Expected OP_RESULT to follow OP_CALL\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
args.Push(TypeIdOf<void*>::kTypeId);
|
args.Push(TypeIdOf<void*>::kTypeId);
|
||||||
|
|
|
@ -962,7 +962,7 @@ void JitCompiler::EmitFLOP()
|
||||||
FuncPtr func = nullptr;
|
FuncPtr func = nullptr;
|
||||||
switch (C)
|
switch (C)
|
||||||
{
|
{
|
||||||
default: I_FatalError("Unknown OP_FLOP subfunction");
|
default: I_Error("Unknown OP_FLOP subfunction");
|
||||||
case FLOP_ABS: func = fabs; break;
|
case FLOP_ABS: func = fabs; break;
|
||||||
case FLOP_EXP: func = g_exp; break;
|
case FLOP_EXP: func = g_exp; break;
|
||||||
case FLOP_LOG: func = g_log; break;
|
case FLOP_LOG: func = g_log; break;
|
||||||
|
@ -1090,7 +1090,7 @@ void JitCompiler::EmitEQF_K()
|
||||||
void JitCompiler::EmitLTF_RR()
|
void JitCompiler::EmitLTF_RR()
|
||||||
{
|
{
|
||||||
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
||||||
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LTF_RR.\n");
|
if (static_cast<bool>(A & CMP_APPROX)) I_Error("CMP_APPROX not implemented for LTF_RR.\n");
|
||||||
|
|
||||||
cc.ucomisd(regF[C], regF[B]);
|
cc.ucomisd(regF[C], regF[B]);
|
||||||
if (check) cc.ja(fail);
|
if (check) cc.ja(fail);
|
||||||
|
@ -1101,7 +1101,7 @@ void JitCompiler::EmitLTF_RR()
|
||||||
void JitCompiler::EmitLTF_RK()
|
void JitCompiler::EmitLTF_RK()
|
||||||
{
|
{
|
||||||
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
||||||
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LTF_RK.\n");
|
if (static_cast<bool>(A & CMP_APPROX)) I_Error("CMP_APPROX not implemented for LTF_RK.\n");
|
||||||
|
|
||||||
auto constTmp = newTempIntPtr();
|
auto constTmp = newTempIntPtr();
|
||||||
auto xmmTmp = newTempXmmSd();
|
auto xmmTmp = newTempXmmSd();
|
||||||
|
@ -1117,7 +1117,7 @@ void JitCompiler::EmitLTF_RK()
|
||||||
void JitCompiler::EmitLTF_KR()
|
void JitCompiler::EmitLTF_KR()
|
||||||
{
|
{
|
||||||
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
||||||
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LTF_KR.\n");
|
if (static_cast<bool>(A & CMP_APPROX)) I_Error("CMP_APPROX not implemented for LTF_KR.\n");
|
||||||
|
|
||||||
auto tmp = newTempIntPtr();
|
auto tmp = newTempIntPtr();
|
||||||
cc.mov(tmp, asmjit::imm_ptr(&konstf[B]));
|
cc.mov(tmp, asmjit::imm_ptr(&konstf[B]));
|
||||||
|
@ -1131,7 +1131,7 @@ void JitCompiler::EmitLTF_KR()
|
||||||
void JitCompiler::EmitLEF_RR()
|
void JitCompiler::EmitLEF_RR()
|
||||||
{
|
{
|
||||||
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
||||||
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LEF_RR.\n");
|
if (static_cast<bool>(A & CMP_APPROX)) I_Error("CMP_APPROX not implemented for LEF_RR.\n");
|
||||||
|
|
||||||
cc.ucomisd(regF[C], regF[B]);
|
cc.ucomisd(regF[C], regF[B]);
|
||||||
if (check) cc.jae(fail);
|
if (check) cc.jae(fail);
|
||||||
|
@ -1142,7 +1142,7 @@ void JitCompiler::EmitLEF_RR()
|
||||||
void JitCompiler::EmitLEF_RK()
|
void JitCompiler::EmitLEF_RK()
|
||||||
{
|
{
|
||||||
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
||||||
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LEF_RK.\n");
|
if (static_cast<bool>(A & CMP_APPROX)) I_Error("CMP_APPROX not implemented for LEF_RK.\n");
|
||||||
|
|
||||||
auto constTmp = newTempIntPtr();
|
auto constTmp = newTempIntPtr();
|
||||||
auto xmmTmp = newTempXmmSd();
|
auto xmmTmp = newTempXmmSd();
|
||||||
|
@ -1158,7 +1158,7 @@ void JitCompiler::EmitLEF_RK()
|
||||||
void JitCompiler::EmitLEF_KR()
|
void JitCompiler::EmitLEF_KR()
|
||||||
{
|
{
|
||||||
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
||||||
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LEF_KR.\n");
|
if (static_cast<bool>(A & CMP_APPROX)) I_Error("CMP_APPROX not implemented for LEF_KR.\n");
|
||||||
|
|
||||||
auto tmp = newTempIntPtr();
|
auto tmp = newTempIntPtr();
|
||||||
cc.mov(tmp, asmjit::imm_ptr(&konstf[B]));
|
cc.mov(tmp, asmjit::imm_ptr(&konstf[B]));
|
||||||
|
@ -1275,7 +1275,7 @@ void JitCompiler::EmitEQV2_R()
|
||||||
|
|
||||||
void JitCompiler::EmitEQV2_K()
|
void JitCompiler::EmitEQV2_K()
|
||||||
{
|
{
|
||||||
I_FatalError("EQV2_K is not used.");
|
I_Error("EQV2_K is not used.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1442,7 +1442,7 @@ void JitCompiler::EmitEQV3_R()
|
||||||
|
|
||||||
void JitCompiler::EmitEQV3_K()
|
void JitCompiler::EmitEQV3_K()
|
||||||
{
|
{
|
||||||
I_FatalError("EQV3_K is not used.");
|
I_Error("EQV3_K is not used.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -174,7 +174,7 @@ void JitCompiler::EmitCAST()
|
||||||
call->setArg(1, regD[B]);
|
call->setArg(1, regD[B]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
I_FatalError("Unknown OP_CAST type\n");
|
I_Error("Unknown OP_CAST type\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ static TArray<uint16_t> CreateUnwindInfoWindows(asmjit::CCFunc *func)
|
||||||
FuncFrameLayout layout;
|
FuncFrameLayout layout;
|
||||||
Error error = layout.init(func->getDetail(), func->getFrameInfo());
|
Error error = layout.init(func->getDetail(), func->getFrameInfo());
|
||||||
if (error != kErrorOk)
|
if (error != kErrorOk)
|
||||||
I_FatalError("FuncFrameLayout.init failed");
|
I_Error("FuncFrameLayout.init failed");
|
||||||
|
|
||||||
// We need a dummy emitter for instruction size calculations
|
// We need a dummy emitter for instruction size calculations
|
||||||
CodeHolder code;
|
CodeHolder code;
|
||||||
|
@ -275,7 +275,7 @@ void *AddJitFunction(asmjit::CodeHolder* code, asmjit::CCFunc *func)
|
||||||
BOOLEAN result = RtlAddFunctionTable(table, 1, (DWORD64)baseaddr);
|
BOOLEAN result = RtlAddFunctionTable(table, 1, (DWORD64)baseaddr);
|
||||||
JitFrames.Push((uint8_t*)table);
|
JitFrames.Push((uint8_t*)table);
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
I_FatalError("RtlAddFunctionTable failed");
|
I_Error("RtlAddFunctionTable failed");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
|
@ -549,7 +549,7 @@ static TArray<uint8_t> CreateUnwindInfoUnix(asmjit::CCFunc *func, unsigned int &
|
||||||
FuncFrameLayout layout;
|
FuncFrameLayout layout;
|
||||||
Error error = layout.init(func->getDetail(), func->getFrameInfo());
|
Error error = layout.init(func->getDetail(), func->getFrameInfo());
|
||||||
if (error != kErrorOk)
|
if (error != kErrorOk)
|
||||||
I_FatalError("FuncFrameLayout.init failed");
|
I_Error("FuncFrameLayout.init failed");
|
||||||
|
|
||||||
// We need a dummy emitter for instruction size calculations
|
// We need a dummy emitter for instruction size calculations
|
||||||
CodeHolder code;
|
CodeHolder code;
|
||||||
|
|
Loading…
Reference in a new issue