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