void Jit::CallProtectedFunction(void *func, const OpArg &arg1, const u32 arg2, const u32 arg3) { // On x64, we need to save R8, which is caller saved. ABI_CallFunction((void *)thunks.GetSaveRegsFunction()); ABI_CallFunctionACC(func, arg1, arg2, arg3); ABI_CallFunction((void *)thunks.GetLoadRegsFunction()); }
bool Jit::CheckJitBreakpoint(u32 addr, int downcountOffset) { if (CBreakPoints::IsAddressBreakPoint(addr)) { SAVE_FLAGS; FlushAll(); MOV(32, M(&mips_->pc), Imm32(js.compilerPC)); ABI_CallFunction(&JitBreakpoint); // If 0, the conditional breakpoint wasn't taken. CMP(32, R(EAX), Imm32(0)); FixupBranch skip = J_CC(CC_Z); WriteDowncount(downcountOffset); // Just to fix the stack. LOAD_FLAGS; JMP(asm_.dispatcherCheckCoreState, true); SetJumpTarget(skip); LOAD_FLAGS; return true; } return false; }
void Jit::WriteSyscallExit() { WriteDowncount(); if (js.afterOp & JitState::AFTER_MEMCHECK_CLEANUP) { ABI_CallFunction(&JitMemCheckCleanup); } JMP(asm_.dispatcherCheckCoreState, true); }
void Jit::Comp_ReplacementFunc(MIPSOpcode op) { // We get here if we execute the first instruction of a replaced function. This means // that we do need to return to RA. // Inlined function calls (caught in jal) are handled differently. int index = op.encoding & MIPS_EMUHACK_VALUE_MASK; const ReplacementTableEntry *entry = GetReplacementFunc(index); if (!entry) { ERROR_LOG(HLE, "Invalid replacement op %08x", op.encoding); return; } if (entry->flags & REPFLAG_DISABLED) { MIPSCompileOp(Memory::Read_Instruction(js.compilerPC, true)); } else if (entry->jitReplaceFunc) { MIPSReplaceFunc repl = entry->jitReplaceFunc; int cycles = (this->*repl)(); if (entry->flags & (REPFLAG_HOOKENTER | REPFLAG_HOOKEXIT)) { // Compile the original instruction at this address. We ignore cycles for hooks. MIPSCompileOp(Memory::Read_Instruction(js.compilerPC, true)); } else { FlushAll(); MOV(32, R(ECX), M(¤tMIPS->r[MIPS_REG_RA])); js.downcountAmount += cycles; WriteExitDestInReg(ECX); js.compiling = false; } } else if (entry->replaceFunc) { FlushAll(); // Standard function call, nothing fancy. // The function returns the number of cycles it took in EAX. MOV(32, M(&mips_->pc), Imm32(js.compilerPC)); ABI_CallFunction(entry->replaceFunc); if (entry->flags & (REPFLAG_HOOKENTER | REPFLAG_HOOKEXIT)) { // Compile the original instruction at this address. We ignore cycles for hooks. MIPSCompileOp(Memory::Read_Instruction(js.compilerPC, true)); } else { MOV(32, R(ECX), M(¤tMIPS->r[MIPS_REG_RA])); SUB(32, M(¤tMIPS->downcount), R(EAX)); WriteExitDestInReg(ECX); js.compiling = false; } } else { ERROR_LOG(HLE, "Replacement function %s has neither jit nor regular impl", entry->name); } }
bool Jit::ReplaceJalTo(u32 dest) { MIPSOpcode op(Memory::Read_Opcode_JIT(dest)); if (!MIPS_IS_REPLACEMENT(op.encoding)) return false; int index = op.encoding & MIPS_EMUHACK_VALUE_MASK; const ReplacementTableEntry *entry = GetReplacementFunc(index); if (!entry) { ERROR_LOG(HLE, "ReplaceJalTo: Invalid replacement op %08x at %08x", op.encoding, dest); return false; } if (entry->flags & (REPFLAG_HOOKENTER | REPFLAG_HOOKEXIT | REPFLAG_DISABLED)) { // If it's a hook, we can't replace the jal, we have to go inside the func. return false; } // Warning - this might be bad if the code at the destination changes... if (entry->flags & REPFLAG_ALLOWINLINE) { // Jackpot! Just do it, no flushing. The code will be entirely inlined. // First, compile the delay slot. It's unconditional so no issues. CompileDelaySlot(DELAYSLOT_NICE); // Technically, we should write the unused return address to RA, but meh. MIPSReplaceFunc repl = entry->jitReplaceFunc; int cycles = (this->*repl)(); js.downcountAmount += cycles; } else { gpr.SetImm(MIPS_REG_RA, js.compilerPC + 8); CompileDelaySlot(DELAYSLOT_NICE); FlushAll(); MOV(32, M(&mips_->pc), Imm32(js.compilerPC)); ABI_CallFunction(entry->replaceFunc); SUB(32, M(¤tMIPS->downcount), R(EAX)); } js.compilerPC += 4; // No writing exits, keep going! // Add a trigger so that if the inlined code changes, we invalidate this block. // TODO: Correctly determine the size of this block. blocks.ProxyBlock(js.blockStart, dest, 4, GetCodePtr()); return true; }