From d46b29e597d7be51454e2e017bc9daa3c37b2c3e Mon Sep 17 00:00:00 2001 From: Mahmood - Zer0xFF <5013823+Zer0xFF@users.noreply.github.com> Date: Sat, 30 May 2020 14:53:28 +0100 Subject: [PATCH 1/2] Add x86-64 JIT'ed Trampoline --- build_cmake/CMakeLists.txt | 2 ++ include/Jitter.h | 2 ++ include/Jitter_CodeGen.h | 2 ++ include/Jitter_CodeGen_x86_64.h | 1 + include/Jitter_Trampoline.h | 26 +++++++++++++++++++++++ include/MemoryFunction.h | 2 +- src/Jitter.cpp | 17 +++++++++++++++ src/Jitter_CodeGen.cpp | 5 +++++ src/Jitter_CodeGen_x86_64.cpp | 31 +++++++++++++++++++++------ src/Jitter_Trampoline.cpp | 37 +++++++++++++++++++++++++++++++++ src/MemoryFunction.cpp | 16 ++++++++++---- 11 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 include/Jitter_Trampoline.h create mode 100644 src/Jitter_Trampoline.cpp diff --git a/build_cmake/CMakeLists.txt b/build_cmake/CMakeLists.txt index 2cf245d5..a57ee731 100644 --- a/build_cmake/CMakeLists.txt +++ b/build_cmake/CMakeLists.txt @@ -61,6 +61,7 @@ add_library(CodeGen ../src/Jitter_CodeGen_Wasm.cpp ../src/Jitter_CodeGen.cpp ../src/Jitter_CodeGenFactory.cpp + ../src/Jitter_Trampoline.cpp ../src/Jitter.cpp ../src/Jitter_Optimize.cpp ../src/Jitter_RegAlloc.cpp @@ -93,6 +94,7 @@ add_library(CodeGen ../include/Jitter_Symbol.h ../include/Jitter_SymbolRef.h ../include/Jitter_SymbolTable.h + ../include/Jitter_Trampoline.h ../include/Jitter.h ../include/Literal128.h ../include/LiteralPool.h diff --git a/include/Jitter.h b/include/Jitter.h index 7a1dd06d..6af8fc71 100644 --- a/include/Jitter.h +++ b/include/Jitter.h @@ -74,6 +74,8 @@ namespace Jitter void Add(); void And(); void Break(); + + void CallRel64(size_t, unsigned int); void Call(void*, unsigned int, bool); void Call(void*, unsigned int, RETURN_VALUE_TYPE); void Cmp(CONDITION); diff --git a/include/Jitter_CodeGen.h b/include/Jitter_CodeGen.h index 4a4ef935..482de267 100644 --- a/include/Jitter_CodeGen.h +++ b/include/Jitter_CodeGen.h @@ -32,6 +32,7 @@ namespace Jitter virtual bool CanHold128BitsReturnValueInRegisters() const = 0; virtual void RegisterExternalSymbols(CObjectFile*) const = 0; virtual uint32 GetPointerSize() const = 0; + void SetTrumpoline(bool); protected: enum MATCHTYPE @@ -93,5 +94,6 @@ namespace Jitter MatcherMapType m_matchers; ExternalSymbolReferencedHandler m_externalSymbolReferencedHandler; + bool m_isTrampoline = false; }; } diff --git a/include/Jitter_CodeGen_x86_64.h b/include/Jitter_CodeGen_x86_64.h index 0f62b8f8..39961c9b 100644 --- a/include/Jitter_CodeGen_x86_64.h +++ b/include/Jitter_CodeGen_x86_64.h @@ -92,6 +92,7 @@ namespace Jitter //CALL void Emit_Call(const STATEMENT&); + void Emit_Call_Rel64(const STATEMENT&); //RETURNVALUE void Emit_RetVal_Reg(const STATEMENT&); diff --git a/include/Jitter_Trampoline.h b/include/Jitter_Trampoline.h new file mode 100644 index 00000000..6fd2748c --- /dev/null +++ b/include/Jitter_Trampoline.h @@ -0,0 +1,26 @@ +#include "Singleton.h" +#include "MemoryFunction.h" + +namespace Jitter +{ + class CJitter_Trampoline : public CSingleton + { + public: + CJitter_Trampoline(); + ~CJitter_Trampoline() = default; + + void Trampoline(void*, void*); + + private: + struct CONTEXT + { + void* context; + void* code; + }; + void SetupTrumpoline(); + + CONTEXT m_context; + CMemoryFunction m_function; + + }; +}; diff --git a/include/MemoryFunction.h b/include/MemoryFunction.h index d4ff1f2e..8f6445c3 100644 --- a/include/MemoryFunction.h +++ b/include/MemoryFunction.h @@ -17,7 +17,7 @@ class CMemoryFunction CMemoryFunction& operator =(const CMemoryFunction&) = delete; CMemoryFunction& operator =(CMemoryFunction&&); - void operator()(void*); + void operator()(void*, bool = false); void* GetCode() const; size_t GetSize() const; diff --git a/src/Jitter.cpp b/src/Jitter.cpp index fac3e7b3..5f70f7f6 100644 --- a/src/Jitter.cpp +++ b/src/Jitter.cpp @@ -250,6 +250,23 @@ void CJitter::Break() InsertStatement(statement); } +void CJitter::CallRel64(size_t offset, unsigned int paramCount) +{ + for(unsigned int i = 0; i < paramCount; i++) + { + STATEMENT paramStatement; + paramStatement.src1 = MakeSymbolRef(m_shadow.Pull()); + paramStatement.op = OP_PARAM; + InsertStatement(paramStatement); + } + + STATEMENT callStatement; + callStatement.src1 = MakeSymbolRef(MakeSymbol(SYM_RELATIVE64, static_cast(offset))); + callStatement.src2 = MakeSymbolRef(MakeSymbol(SYM_CONSTANT, paramCount)); + callStatement.op = OP_CALL; + InsertStatement(callStatement); +} + void CJitter::Call(void* func, unsigned int paramCount, bool keepRet) { Call(func, paramCount, keepRet ? RETURN_VALUE_32 : RETURN_VALUE_NONE); diff --git a/src/Jitter_CodeGen.cpp b/src/Jitter_CodeGen.cpp index 65743909..135961de 100644 --- a/src/Jitter_CodeGen.cpp +++ b/src/Jitter_CodeGen.cpp @@ -100,3 +100,8 @@ uint32 CCodeGen::GetRegisterUsage(const StatementList& statements) } return registerUsage; } + +void CCodeGen::SetTrumpoline(bool isTrumpoline) +{ + m_isTrampoline = isTrumpoline; +} diff --git a/src/Jitter_CodeGen_x86_64.cpp b/src/Jitter_CodeGen_x86_64.cpp index b398ceab..a99814e9 100644 --- a/src/Jitter_CodeGen_x86_64.cpp +++ b/src/Jitter_CodeGen_x86_64.cpp @@ -208,6 +208,7 @@ CCodeGen_x86_64::CONSTMATCHER CCodeGen_x86_64::g_constMatchers[] = { OP_PARAM_RET, MATCH_NIL, MATCH_MEMORY128, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_Param_Mem128 }, { OP_CALL, MATCH_NIL, MATCH_CONSTANTPTR, MATCH_CONSTANT, MATCH_NIL, &CCodeGen_x86_64::Emit_Call }, + { OP_CALL, MATCH_NIL, MATCH_RELATIVE64, MATCH_CONSTANT, MATCH_NIL, &CCodeGen_x86_64::Emit_Call_Rel64 }, { OP_RETVAL, MATCH_REGISTER, MATCH_NIL, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_RetVal_Reg }, { OP_RETVAL, MATCH_MEMORY, MATCH_NIL, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_RetVal_Mem }, @@ -325,7 +326,6 @@ uint32 CCodeGen_x86_64::GetPointerSize() const void CCodeGen_x86_64::Emit_Prolog(const StatementList& statements, unsigned int stackSize) { m_params.clear(); - //Compute the size needed to store all function call parameters uint32 maxParamSpillSize = 0; { @@ -363,14 +363,14 @@ void CCodeGen_x86_64::Emit_Prolog(const StatementList& statements, unsigned int m_assembler.MovEq(CX86Assembler::rBP, CX86Assembler::MakeRegisterAddress(m_paramRegs[0])); uint32 savedSize = 0; - for(unsigned int i = 0; i < m_maxRegisters; i++) + if(m_isTrampoline) { - if(m_registerUsage & (1 << i)) + for(unsigned int i = 0; i < m_maxRegisters; i++) { m_assembler.Push(m_registers[i]); savedSize += 8; } - } + } uint32 savedRegAlignAdjust = (savedSize != 0) ? (0x10 - (savedSize & 0xF)) : 0; @@ -402,9 +402,9 @@ void CCodeGen_x86_64::Emit_Epilog() { m_assembler.AddIq(CX86Assembler::MakeRegisterAddress(CX86Assembler::rSP), m_totalStackAlloc); - for(int i = m_maxRegisters - 1; i >= 0; i--) + if(m_isTrampoline) { - if(m_registerUsage & (1 << i)) + for(int i = m_maxRegisters - 1; i >= 0; i--) { m_assembler.Pop(m_registers[i]); } @@ -539,6 +539,25 @@ void CCodeGen_x86_64::Emit_Param_Mem128(const STATEMENT& statement) ); } +void CCodeGen_x86_64::Emit_Call_Rel64(const STATEMENT& statement) +{ + const auto& src1 = statement.src1->GetSymbol().get(); + const auto& src2 = statement.src2->GetSymbol().get(); + + unsigned int paramCount = src2->m_valueLow; + uint32 paramSpillOffset = 0; + + for(unsigned int i = 0; i < paramCount; i++) + { + auto emitter(m_params.back()); + m_params.pop_back(); + paramSpillOffset += emitter(m_paramRegs[i], paramSpillOffset); + } + + m_assembler.MovEq(CX86Assembler::rAX, MakeMemory64SymbolAddress(src1)); + m_assembler.CallEd(CX86Assembler::MakeRegisterAddress(CX86Assembler::rAX)); +} + void CCodeGen_x86_64::Emit_Call(const STATEMENT& statement) { const auto& src1 = statement.src1->GetSymbol().get(); diff --git a/src/Jitter_Trampoline.cpp b/src/Jitter_Trampoline.cpp new file mode 100644 index 00000000..4a42c04e --- /dev/null +++ b/src/Jitter_Trampoline.cpp @@ -0,0 +1,37 @@ +#include "Jitter_Trampoline.h" +#include "Jitter.h" +#include "Jitter_CodeGenFactory.h" + +#include "MemStream.h" + +Jitter::CJitter_Trampoline::CJitter_Trampoline() +{ + SetupTrumpoline(); +} + +void Jitter::CJitter_Trampoline::SetupTrumpoline() +{ + Jitter::CCodeGen* codeGen = Jitter::CreateCodeGen(); + codeGen->SetTrumpoline(true); + Jitter::CJitter jitter(codeGen); + + Framework::CMemStream codeStream; + jitter.SetStream(&codeStream); + + jitter.Begin(); + { + jitter.PushRel64(offsetof(CONTEXT, context)); + jitter.CallRel64(offsetof(CONTEXT, code), 1); + } + jitter.End(); + codeGen->SetTrumpoline(false); + + m_function = CMemoryFunction(codeStream.GetBuffer(), codeStream.GetSize()); +} + +void Jitter::CJitter_Trampoline::Trampoline(void* context, void* code) +{ + m_context.context = context; + m_context.code = code; + m_function(&m_context, true); +} diff --git a/src/MemoryFunction.cpp b/src/MemoryFunction.cpp index 50a9ecb4..adccadb2 100644 --- a/src/MemoryFunction.cpp +++ b/src/MemoryFunction.cpp @@ -5,6 +5,7 @@ #include #include "AlignedAlloc.h" #include "MemoryFunction.h" +#include "Jitter_Trampoline.h" #define BLOCK_ALIGN 0x10 @@ -177,11 +178,18 @@ CMemoryFunction& CMemoryFunction::operator =(CMemoryFunction&& rhs) return (*this); } -void CMemoryFunction::operator()(void* context) +void CMemoryFunction::operator()(void* context, bool isTrampoline) { - typedef void (*FctType)(void*); - auto fct = reinterpret_cast(m_code); - fct(context); + if(isTrampoline) + { + typedef void (*FctType)(void*); + auto fct = reinterpret_cast(m_code); + fct(context); + } + else + { + Jitter::CJitter_Trampoline::GetInstance().Trampoline(context, m_code); + } } void* CMemoryFunction::GetCode() const From 5630683f4b0218ac4fb62fb8c543e4455ce56446 Mon Sep 17 00:00:00 2001 From: Mahmood - Zer0xFF <5013823+Zer0xFF@users.noreply.github.com> Date: Sat, 30 May 2020 14:53:42 +0100 Subject: [PATCH 2/2] Add x86-32 JIT'ed Trampoline --- include/Jitter_CodeGen_x86_32.h | 1 + src/Jitter_CodeGen_x86_32.cpp | 36 +++++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/include/Jitter_CodeGen_x86_32.h b/include/Jitter_CodeGen_x86_32.h index 64594cce..473f97c5 100644 --- a/include/Jitter_CodeGen_x86_32.h +++ b/include/Jitter_CodeGen_x86_32.h @@ -44,6 +44,7 @@ namespace Jitter void Emit_ParamRet_Mem128(const STATEMENT&); //CALL + void Emit_Call_Rel(const STATEMENT&); void Emit_Call(const STATEMENT&); //RETURNVALUE diff --git a/src/Jitter_CodeGen_x86_32.cpp b/src/Jitter_CodeGen_x86_32.cpp index 04ffb013..79e56784 100644 --- a/src/Jitter_CodeGen_x86_32.cpp +++ b/src/Jitter_CodeGen_x86_32.cpp @@ -32,6 +32,7 @@ CCodeGen_x86_32::CONSTMATCHER CCodeGen_x86_32::g_constMatchers[] = { OP_PARAM_RET, MATCH_NIL, MATCH_MEMORY128, MATCH_NIL, &CCodeGen_x86_32::Emit_ParamRet_Mem128 }, + { OP_CALL, MATCH_NIL, MATCH_RELATIVE, MATCH_CONSTANT, &CCodeGen_x86_32::Emit_Call_Rel }, { OP_CALL, MATCH_NIL, MATCH_CONSTANTPTR, MATCH_CONSTANT, &CCodeGen_x86_32::Emit_Call }, { OP_RETVAL, MATCH_TEMPORARY, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_32::Emit_RetVal_Tmp }, @@ -194,9 +195,9 @@ void CCodeGen_x86_32::Emit_Prolog(const StatementList& statements, unsigned int m_assembler.MovEd(CX86Assembler::rBP, CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, 8)); //Save registers - for(unsigned int i = 0; i < MAX_REGISTERS; i++) + if(m_isTrampoline) { - if(m_registerUsage & (1 << i)) + for(unsigned int i = 0; i < MAX_REGISTERS; i++) { m_assembler.Push(m_registers[i]); } @@ -260,9 +261,9 @@ void CCodeGen_x86_32::Emit_Epilog() m_assembler.Pop(CX86Assembler::rSP); - for(int i = MAX_REGISTERS - 1; i >= 0; i--) + if(m_isTrampoline) { - if(m_registerUsage & (1 << i)) + for(int i = MAX_REGISTERS - 1; i >= 0; i--) { m_assembler.Pop(m_registers[i]); } @@ -415,6 +416,33 @@ void CCodeGen_x86_32::Emit_ParamRet_Mem128(const STATEMENT& statement) m_hasImplicitRetValueParam = true; } +void CCodeGen_x86_32::Emit_Call_Rel(const STATEMENT& statement) +{ + auto src1 = statement.src1->GetSymbol().get(); + auto src2 = statement.src2->GetSymbol().get(); + + uint32 paramCount = src2->m_valueLow; + CALL_STATE callState; + for(unsigned int i = 0; i < paramCount; i++) + { + auto emitter(m_params.back()); + m_params.pop_back(); + emitter(callState); + } + + m_assembler.MovEd(CX86Assembler::rAX, MakeRelativeSymbolAddress(src1)); + m_assembler.CallEd(CX86Assembler::MakeRegisterAddress(CX86Assembler::rAX)); + + if(m_hasImplicitRetValueParam && m_implicitRetValueParamFixUpRequired) + { + //Allocated stack space for the extra parameter is cleaned up by the callee. + //So adjust the amount of stack space we free up after the call + m_assembler.SubId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rSP), 4); + } + + m_hasImplicitRetValueParam = false; +} + void CCodeGen_x86_32::Emit_Call(const STATEMENT& statement) { auto src1 = statement.src1->GetSymbol().get();