- construct our own runtime as the one provided by asmjit is too primitive

This commit is contained in:
Magnus Norddahl 2018-10-14 00:46:54 +02:00
parent 300553a21f
commit cf9bae67a8
5 changed files with 178 additions and 103 deletions

View file

@ -6,24 +6,184 @@ extern PString *TypeString;
extern PStruct *TypeVector2; extern PStruct *TypeVector2;
extern PStruct *TypeVector3; extern PStruct *TypeVector3;
static asmjit::JitRuntime *jit; static void OutputJitLog(const asmjit::StringLogger &logger);
static int jitRefCount = 0;
asmjit::JitRuntime *JitGetRuntime() static TArray<uint8_t*> JitBlocks;
static size_t JitBlockPos = 0;
static size_t JitBlockSize = 0;
static asmjit::CodeInfo GetHostCodeInfo()
{ {
if (!jit) static bool firstCall = true;
jit = new asmjit::JitRuntime; static asmjit::CodeInfo codeInfo;
jitRefCount++;
return jit; if (firstCall)
{
asmjit::JitRuntime rt;
codeInfo = rt.getCodeInfo();
firstCall = false;
}
return codeInfo;
} }
void JitCleanUp(VMScriptFunction *func) void *AllocJitMemory(size_t size)
{ {
jitRefCount--; using namespace asmjit;
if (jitRefCount == 0)
if (JitBlockPos + size <= JitBlockSize)
{ {
delete jit; uint8_t *p = JitBlocks[JitBlocks.Size() - 1];
jit = nullptr; p += JitBlockPos;
JitBlockPos += size;
return p;
}
else
{
size_t allocatedSize = 0;
void *p = OSUtils::allocVirtualMemory(1024 * 1024, &allocatedSize, OSUtils::kVMWritable | OSUtils::kVMExecutable);
if (!p)
return nullptr;
JitBlocks.Push((uint8_t*)p);
JitBlockSize = allocatedSize;
JitBlockPos = size;
return p;
}
}
static TArray<uint32_t> CreateUnwindInfo(asmjit::CCFunc *func)
{
TArray<uint32_t> info;
uint32_t version = 1, flags = 0, sizeOfProlog = 0, countOfCodes = 0, frameRegister = 0, frameOffset = 0;
// To do: query FuncFrameLayout to immitate what X86Internal::emitProlog does
info.Push(version | (flags << 3) | (sizeOfProlog << 8) | (countOfCodes << 16) | (frameRegister << 24) | (frameOffset << 28));
// To do: add UNWIND_CODE entries
info[0] |= (countOfCodes << 16);
/* // For reference, we don't need any of this
if (flags & UNW_FLAG_EHANDLER)
{
uint32_t exceptionHandler = 0;
info.Push(exceptionHandler);
}
else if (flags & UNW_FLAG_CHAININFO)
{
uint32_t functionEntry = 0;
info.Push(functionEntry);
}
if (flags & UNW_FLAG_EHANDLER)
{
uint32_t ExceptionData[];
info.Push(ExceptionData[]);
}
*/
return info;
}
static void *AddJitFunction(asmjit::CodeHolder* code, asmjit::CCFunc *func)
{
using namespace asmjit;
size_t codeSize = code->getCodeSize();
if (codeSize == 0)
return nullptr;
TArray<uint32_t> unwindInfo = CreateUnwindInfo(func);
size_t unwindInfoSize = unwindInfo.Size() * sizeof(uint32_t);
codeSize = (codeSize + 3) / 4 * 4;
uint8_t *p = (uint8_t *)AllocJitMemory(codeSize + unwindInfoSize);
if (!p)
return nullptr;
size_t relocSize = code->relocate(p);
if (relocSize == 0)
return nullptr;
relocSize = (relocSize + 3) / 4 * 4;
JitBlockPos -= codeSize - relocSize;
#ifdef WIN32
uint8_t *unwindptr = p + relocSize;
memcpy(unwindptr, &unwindInfo[0], unwindInfoSize);
RUNTIME_FUNCTION table;
table.BeginAddress = 0;
table.EndAddress = (DWORD)(ptrdiff_t)(unwindptr - p);
table.UnwindData = (DWORD)(ptrdiff_t)(unwindptr - p);
BOOLEAN result = RtlAddFunctionTable(&table, 1, (DWORD64)p);
if (result == 0)
I_FatalError("RtlAddFunctionTable failed");
#endif
return p;
}
JitFuncPtr JitCompile(VMScriptFunction *sfunc)
{
#if 0
if (strcmp(sfunc->PrintableName.GetChars(), "StatusScreen.drawNum") != 0)
return nullptr;
#endif
using namespace asmjit;
StringLogger logger;
try
{
ThrowingErrorHandler errorHandler;
CodeHolder code;
code.init(GetHostCodeInfo());
code.setErrorHandler(&errorHandler);
code.setLogger(&logger);
JitCompiler compiler(&code, sfunc);
CCFunc *func = compiler.Codegen();
return reinterpret_cast<JitFuncPtr>(AddJitFunction(&code, func));
}
catch (const std::exception &e)
{
OutputJitLog(logger);
I_FatalError("Unexpected JIT error: %s\n", e.what());
return nullptr;
}
}
void JitDumpLog(FILE *file, VMScriptFunction *sfunc)
{
using namespace asmjit;
StringLogger logger;
try
{
ThrowingErrorHandler errorHandler;
CodeHolder code;
code.init(GetHostCodeInfo());
code.setErrorHandler(&errorHandler);
code.setLogger(&logger);
JitCompiler compiler(&code, sfunc);
compiler.Codegen();
fwrite(logger.getString(), logger.getLength(), 1, file);
}
catch (const std::exception &e)
{
fwrite(logger.getString(), logger.getLength(), 1, file);
FString err;
err.Format("Unexpected JIT error: %s\n", e.what());
fwrite(err.GetChars(), err.Len(), 1, file);
fclose(file);
I_FatalError("Unexpected JIT error: %s\n", e.what());
} }
} }
@ -46,83 +206,6 @@ static void OutputJitLog(const asmjit::StringLogger &logger)
Printf("%s\n", pos); Printf("%s\n", pos);
} }
//#define DEBUG_JIT
JitFuncPtr JitCompile(VMScriptFunction *sfunc)
{
#if defined(DEBUG_JIT)
if (strcmp(sfunc->PrintableName.GetChars(), "StatusScreen.drawNum") != 0)
return nullptr;
#endif
//Printf("Jitting function: %s\n", sfunc->PrintableName.GetChars());
using namespace asmjit;
StringLogger logger;
try
{
auto *jit = JitGetRuntime();
ThrowingErrorHandler errorHandler;
CodeHolder code;
code.init(jit->getCodeInfo());
code.setErrorHandler(&errorHandler);
code.setLogger(&logger);
JitCompiler compiler(&code, sfunc);
compiler.Codegen();
JitFuncPtr fn = nullptr;
Error err = jit->add(&fn, &code);
if (err)
I_FatalError("JitRuntime::add failed: %d", err);
#if defined(DEBUG_JIT)
OutputJitLog(logger);
#endif
return fn;
}
catch (const std::exception &e)
{
OutputJitLog(logger);
I_FatalError("Unexpected JIT error: %s\n", e.what());
return nullptr;
}
}
void JitDumpLog(FILE *file, VMScriptFunction *sfunc)
{
using namespace asmjit;
StringLogger logger;
try
{
auto *jit = JitGetRuntime();
ThrowingErrorHandler errorHandler;
CodeHolder code;
code.init(jit->getCodeInfo());
code.setErrorHandler(&errorHandler);
code.setLogger(&logger);
JitCompiler compiler(&code, sfunc);
compiler.Codegen();
fwrite(logger.getString(), logger.getLength(), 1, file);
}
catch (const std::exception &e)
{
fwrite(logger.getString(), logger.getLength(), 1, file);
FString err;
err.Format("Unexpected JIT error: %s\n", e.what());
fwrite(err.GetChars(), err.Len(), 1, file);
fclose(file);
I_FatalError("Unexpected JIT error: %s\n", e.what());
}
}
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
static const char *OpNames[NUM_OPS] = static const char *OpNames[NUM_OPS] =
@ -132,7 +215,7 @@ static const char *OpNames[NUM_OPS] =
#undef xx #undef xx
}; };
void JitCompiler::Codegen() asmjit::CCFunc *JitCompiler::Codegen()
{ {
Setup(); Setup();
@ -159,6 +242,8 @@ void JitCompiler::Codegen()
cc.endFunc(); cc.endFunc();
cc.finalize(); cc.finalize();
return func;
} }
void JitCompiler::EmitOpcode() void JitCompiler::EmitOpcode()
@ -214,7 +299,7 @@ void JitCompiler::Setup()
ret = cc.newIntPtr("ret"); // VMReturn *ret ret = cc.newIntPtr("ret"); // VMReturn *ret
numret = cc.newInt32("numret"); // int numret numret = cc.newInt32("numret"); // int numret
cc.addFunc(FuncSignature5<int, VMFunction *, void *, int, void *, int>()); func = cc.addFunc(FuncSignature5<int, VMFunction *, void *, int, void *, int>());
cc.setArg(0, unusedFunc); cc.setArg(0, unusedFunc);
cc.setArg(1, args); cc.setArg(1, args);
cc.setArg(2, numargs); cc.setArg(2, numargs);

View file

@ -4,5 +4,4 @@
#include "vmintern.h" #include "vmintern.h"
JitFuncPtr JitCompile(VMScriptFunction *func); JitFuncPtr JitCompile(VMScriptFunction *func);
void JitCleanUp(VMScriptFunction *func);
void JitDumpLog(FILE *file, VMScriptFunction *func); void JitDumpLog(FILE *file, VMScriptFunction *func);

View file

@ -30,7 +30,7 @@ class JitCompiler
public: public:
JitCompiler(asmjit::CodeHolder *code, VMScriptFunction *sfunc) : cc(code), sfunc(sfunc) { } JitCompiler(asmjit::CodeHolder *code, VMScriptFunction *sfunc) : cc(code), sfunc(sfunc) { }
void Codegen(); asmjit::CCFunc *Codegen();
private: private:
// Declare EmitXX functions for the opcodes: // Declare EmitXX functions for the opcodes:
@ -158,6 +158,7 @@ private:
asmjit::X86Compiler cc; asmjit::X86Compiler cc;
VMScriptFunction *sfunc; VMScriptFunction *sfunc;
asmjit::CCFunc *func = nullptr;
asmjit::X86Gp args; asmjit::X86Gp args;
asmjit::X86Gp numargs; asmjit::X86Gp numargs;
asmjit::X86Gp ret; asmjit::X86Gp ret;

View file

@ -79,12 +79,6 @@ VMScriptFunction::VMScriptFunction(FName name)
VMScriptFunction::~VMScriptFunction() VMScriptFunction::~VMScriptFunction()
{ {
if (FunctionJitted)
{
JitCleanUp(this);
FunctionJitted = false;
}
if (Code != NULL) if (Code != NULL)
{ {
if (KonstS != NULL) if (KonstS != NULL)
@ -220,8 +214,6 @@ int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int num
sfunc->ScriptCall = JitCompile(sfunc); sfunc->ScriptCall = JitCompile(sfunc);
if (!sfunc->ScriptCall) if (!sfunc->ScriptCall)
sfunc->ScriptCall = VMExec; sfunc->ScriptCall = VMExec;
else
sfunc->FunctionJitted = true;
return func->ScriptCall(func, params, numparams, ret, numret); return func->ScriptCall(func, params, numparams, ret, numret);
} }

View file

@ -489,6 +489,4 @@ public:
private: private:
static int FirstScriptCall(VMFunction *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;
}; };