Skip to content

Commit

Permalink
- construct our own runtime as the one provided by asmjit is too prim…
Browse files Browse the repository at this point in the history
…itive
  • Loading branch information
dpjudas committed Oct 13, 2018
1 parent 300553a commit cf9bae6
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 61 deletions.
183 changes: 134 additions & 49 deletions src/scripting/vm/jit.cpp
Expand Up @@ -6,82 +6,148 @@ extern PString *TypeString;
extern PStruct *TypeVector2;
extern PStruct *TypeVector3;

static asmjit::JitRuntime *jit;
static int jitRefCount = 0;
static void OutputJitLog(const asmjit::StringLogger &logger);

asmjit::JitRuntime *JitGetRuntime()
static TArray<uint8_t*> JitBlocks;
static size_t JitBlockPos = 0;
static size_t JitBlockSize = 0;

static asmjit::CodeInfo GetHostCodeInfo()
{
if (!jit)
jit = new asmjit::JitRuntime;
jitRefCount++;
return jit;
static bool firstCall = true;
static asmjit::CodeInfo codeInfo;

if (firstCall)
{
asmjit::JitRuntime rt;
codeInfo = rt.getCodeInfo();
firstCall = false;
}

return codeInfo;
}

void JitCleanUp(VMScriptFunction *func)
void *AllocJitMemory(size_t size)
{
jitRefCount--;
if (jitRefCount == 0)
using namespace asmjit;

if (JitBlockPos + size <= JitBlockSize)
{
uint8_t *p = JitBlocks[JitBlocks.Size() - 1];
p += JitBlockPos;
JitBlockPos += size;
return p;
}
else
{
delete jit;
jit = nullptr;
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 void OutputJitLog(const asmjit::StringLogger &logger)
static TArray<uint32_t> CreateUnwindInfo(asmjit::CCFunc *func)
{
// Write line by line since I_FatalError seems to cut off long strings
const char *pos = logger.getString();
const char *end = pos;
while (*end)
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)
{
if (*end == '\n')
{
FString substr(pos, (int)(ptrdiff_t)(end - pos));
Printf("%s\n", substr.GetChars());
pos = end + 1;
}
end++;
uint32_t exceptionHandler = 0;
info.Push(exceptionHandler);
}
if (pos != end)
Printf("%s\n", pos);
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;
}

//#define DEBUG_JIT
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 defined(DEBUG_JIT)
#if 0
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.init(GetHostCodeInfo());
code.setErrorHandler(&errorHandler);
code.setLogger(&logger);

JitCompiler compiler(&code, sfunc);
compiler.Codegen();
CCFunc *func = 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;
return reinterpret_cast<JitFuncPtr>(AddJitFunction(&code, func));
}
catch (const std::exception &e)
{
Expand All @@ -97,11 +163,9 @@ void JitDumpLog(FILE *file, VMScriptFunction *sfunc)
StringLogger logger;
try
{
auto *jit = JitGetRuntime();

ThrowingErrorHandler errorHandler;
CodeHolder code;
code.init(jit->getCodeInfo());
code.init(GetHostCodeInfo());
code.setErrorHandler(&errorHandler);
code.setLogger(&logger);

Expand All @@ -123,6 +187,25 @@ void JitDumpLog(FILE *file, VMScriptFunction *sfunc)
}
}

static void OutputJitLog(const asmjit::StringLogger &logger)
{
// Write line by line since I_FatalError seems to cut off long strings
const char *pos = logger.getString();
const char *end = pos;
while (*end)
{
if (*end == '\n')
{
FString substr(pos, (int)(ptrdiff_t)(end - pos));
Printf("%s\n", substr.GetChars());
pos = end + 1;
}
end++;
}
if (pos != end)
Printf("%s\n", pos);
}

/////////////////////////////////////////////////////////////////////////////

static const char *OpNames[NUM_OPS] =
Expand All @@ -132,7 +215,7 @@ static const char *OpNames[NUM_OPS] =
#undef xx
};

void JitCompiler::Codegen()
asmjit::CCFunc *JitCompiler::Codegen()
{
Setup();

Expand All @@ -159,6 +242,8 @@ void JitCompiler::Codegen()

cc.endFunc();
cc.finalize();

return func;
}

void JitCompiler::EmitOpcode()
Expand Down Expand Up @@ -214,7 +299,7 @@ void JitCompiler::Setup()
ret = cc.newIntPtr("ret"); // VMReturn *ret
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(1, args);
cc.setArg(2, numargs);
Expand Down
1 change: 0 additions & 1 deletion src/scripting/vm/jit.h
Expand Up @@ -4,5 +4,4 @@
#include "vmintern.h"

JitFuncPtr JitCompile(VMScriptFunction *func);
void JitCleanUp(VMScriptFunction *func);
void JitDumpLog(FILE *file, VMScriptFunction *func);
3 changes: 2 additions & 1 deletion src/scripting/vm/jitintern.h
Expand Up @@ -30,7 +30,7 @@ class JitCompiler
public:
JitCompiler(asmjit::CodeHolder *code, VMScriptFunction *sfunc) : cc(code), sfunc(sfunc) { }

void Codegen();
asmjit::CCFunc *Codegen();

private:
// Declare EmitXX functions for the opcodes:
Expand Down Expand Up @@ -158,6 +158,7 @@ class JitCompiler
asmjit::X86Compiler cc;
VMScriptFunction *sfunc;

asmjit::CCFunc *func = nullptr;
asmjit::X86Gp args;
asmjit::X86Gp numargs;
asmjit::X86Gp ret;
Expand Down
8 changes: 0 additions & 8 deletions src/scripting/vm/vmframe.cpp
Expand Up @@ -79,12 +79,6 @@ VMScriptFunction::VMScriptFunction(FName name)

VMScriptFunction::~VMScriptFunction()
{
if (FunctionJitted)
{
JitCleanUp(this);
FunctionJitted = false;
}

if (Code != NULL)
{
if (KonstS != NULL)
Expand Down Expand Up @@ -220,8 +214,6 @@ int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int num
sfunc->ScriptCall = JitCompile(sfunc);
if (!sfunc->ScriptCall)
sfunc->ScriptCall = VMExec;
else
sfunc->FunctionJitted = true;

return func->ScriptCall(func, params, numparams, ret, numret);
}
Expand Down
2 changes: 0 additions & 2 deletions src/scripting/vm/vmintern.h
Expand Up @@ -489,6 +489,4 @@ class VMScriptFunction : public VMFunction

private:
static int FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret);

bool FunctionJitted = false;
};

0 comments on commit cf9bae6

Please sign in to comment.