diff --git a/src/scripting/vm/jit.cpp b/src/scripting/vm/jit.cpp index bd130c0caf..b5b8869e9a 100644 --- a/src/scripting/vm/jit.cpp +++ b/src/scripting/vm/jit.cpp @@ -146,15 +146,8 @@ bool JitCompiler::CanJit(VMScriptFunction *sfunc) { // Functions not implemented at all yet: - switch (sfunc->Code[i].op) - { - default: - break; - case OP_IJMP: - case OP_TAIL: - case OP_TAIL_K: + if (sfunc->Code[i].op == OP_IJMP) return false; - } // Partially implemented functions: diff --git a/src/scripting/vm/jit_call.cpp b/src/scripting/vm/jit_call.cpp index a978d213af..154e41c288 100644 --- a/src/scripting/vm/jit_call.cpp +++ b/src/scripting/vm/jit_call.cpp @@ -138,12 +138,14 @@ void JitCompiler::EmitCALL_K() void JitCompiler::EmitTAIL() { - I_FatalError("EmitTAIL not implemented\n"); + EmitDoTail(regA[A]); } void JitCompiler::EmitTAIL_K() { - I_FatalError("EmitTAIL_K not implemented\n"); + auto ptr = cc.newIntPtr(); + cc.mov(ptr, ToMemAddress(konsta[A].o)); + EmitDoTail(ptr); } void JitCompiler::EmitDoCall(asmjit::X86Gp ptr) @@ -160,8 +162,7 @@ void JitCompiler::EmitDoCall(asmjit::X86Gp ptr) if (B != NumParam) { paramsptr = cc.newIntPtr(); - cc.mov(paramsptr, params); - cc.add(paramsptr, (int)((NumParam - B) * sizeof(VMValue))); + cc.lea(paramsptr, x86::ptr(params, (int)((NumParam - B) * sizeof(VMValue)))); } else { @@ -196,6 +197,48 @@ void JitCompiler::EmitDoCall(asmjit::X86Gp ptr) ParamOpcodes.Resize(ParamOpcodes.Size() - B); } +void JitCompiler::EmitDoTail(asmjit::X86Gp ptr) +{ + // Whereas the CALL instruction uses its third operand to specify how many return values + // it expects, TAIL ignores its third operand and uses whatever was passed to this Exec call. + + // Note: this is not a true tail call, but then again, it isn't in the vmexec implementation either.. + + using namespace asmjit; + + if (NumParam < B) + I_FatalError("OP_TAIL parameter count does not match the number of preceding OP_PARAM instructions"); + + StoreInOuts(B); // Is REGT_ADDROF even allowed for (true) tail calls? + + X86Gp paramsptr; + if (B != NumParam) + { + paramsptr = cc.newIntPtr(); + cc.lea(paramsptr, x86::ptr(params, (int)((NumParam - B) * sizeof(VMValue)))); + } + else + { + paramsptr = params; + } + + auto result = cc.newInt32(); + auto call = cc.call(ToMemAddress(reinterpret_cast(&JitCompiler::DoCall)), FuncSignature7()); + call->setRet(0, result); + call->setArg(0, stack); + call->setArg(1, ptr); + call->setArg(2, asmjit::Imm(B)); + call->setArg(3, numret); + call->setArg(4, paramsptr); + call->setArg(5, ret); + call->setArg(6, exceptInfo); + + cc.ret(result); + + NumParam -= B; + ParamOpcodes.Resize(ParamOpcodes.Size() - B); +} + void JitCompiler::StoreInOuts(int b) { using namespace asmjit; diff --git a/src/scripting/vm/jitintern.h b/src/scripting/vm/jitintern.h index 348723622a..83bacdfa02 100644 --- a/src/scripting/vm/jitintern.h +++ b/src/scripting/vm/jitintern.h @@ -43,6 +43,7 @@ private: void EmitOpcode(); void EmitDoCall(asmjit::X86Gp ptr); + void EmitDoTail(asmjit::X86Gp ptr); void StoreInOuts(int b); void LoadInOuts(int b); void LoadReturns(const VMOP *retval, int numret);