1 // Copyright 2016 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4
5 #include "Core/PowerPC/Jit64Common/BlockCache.h"
6
7 #include "Common/CommonTypes.h"
8 #include "Common/x64Emitter.h"
9 #include "Core/PowerPC/JitCommon/JitBase.h"
10
JitBlockCache(JitBase & jit)11 JitBlockCache::JitBlockCache(JitBase& jit) : JitBaseBlockCache{jit}
12 {
13 }
14
WriteLinkBlock(const JitBlock::LinkData & source,const JitBlock * dest)15 void JitBlockCache::WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest)
16 {
17 // Do not skip breakpoint check if debugging.
18 const u8* dispatcher = SConfig::GetInstance().bEnableDebugging ?
19 m_jit.GetAsmRoutines()->dispatcher :
20 m_jit.GetAsmRoutines()->dispatcher_no_check;
21
22 u8* location = source.exitPtrs;
23 const u8* address = dest ? dest->checkedEntry : dispatcher;
24 if (source.call)
25 {
26 Gen::XEmitter emit(location, location + 5);
27 emit.CALL(address);
28 }
29 else
30 {
31 // If we're going to link with the next block, there is no need
32 // to emit JMP. So just NOP out the gap to the next block.
33 // Support up to 3 additional bytes because of alignment.
34 s64 offset = address - location;
35 if (offset > 0 && offset <= 5 + 3)
36 {
37 Gen::XEmitter emit(location, location + offset);
38 emit.NOP(offset);
39 }
40 else
41 {
42 Gen::XEmitter emit(location, location + 5);
43 emit.JMP(address, true);
44 }
45 }
46 }
47
WriteDestroyBlock(const JitBlock & block)48 void JitBlockCache::WriteDestroyBlock(const JitBlock& block)
49 {
50 // Only clear the entry points as we might still be within this block.
51 Gen::XEmitter emit(block.checkedEntry, block.checkedEntry + 1);
52 emit.INT3();
53 Gen::XEmitter emit2(block.normalEntry, block.normalEntry + 1);
54 emit2.INT3();
55 }
56
Init()57 void JitBlockCache::Init()
58 {
59 JitBaseBlockCache::Init();
60 ClearRangesToFree();
61 }
62
DestroyBlock(JitBlock & block)63 void JitBlockCache::DestroyBlock(JitBlock& block)
64 {
65 JitBaseBlockCache::DestroyBlock(block);
66
67 if (block.near_begin != block.near_end)
68 m_ranges_to_free_on_next_codegen_near.emplace_back(block.near_begin, block.near_end);
69 if (block.far_begin != block.far_end)
70 m_ranges_to_free_on_next_codegen_far.emplace_back(block.far_begin, block.far_end);
71 }
72
GetRangesToFreeNear() const73 const std::vector<std::pair<u8*, u8*>>& JitBlockCache::GetRangesToFreeNear() const
74 {
75 return m_ranges_to_free_on_next_codegen_near;
76 }
77
GetRangesToFreeFar() const78 const std::vector<std::pair<u8*, u8*>>& JitBlockCache::GetRangesToFreeFar() const
79 {
80 return m_ranges_to_free_on_next_codegen_far;
81 }
82
ClearRangesToFree()83 void JitBlockCache::ClearRangesToFree()
84 {
85 m_ranges_to_free_on_next_codegen_near.clear();
86 m_ranges_to_free_on_next_codegen_far.clear();
87 }
88