CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/MIPS/JitCommon/JitBlockCache.h
Views: 1401
1
// Copyright (c) 2012- PPSSPP Project / Dolphin Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#pragma once
19
20
#include <cstdint>
21
#include <map>
22
#include <unordered_map>
23
#include <vector>
24
#include <string>
25
26
#include "ppsspp_config.h"
27
#include "Common/CommonTypes.h"
28
#include "Common/CodeBlock.h"
29
#include "Core/MIPS/MIPS.h"
30
31
#if PPSSPP_ARCH(ARM) || PPSSPP_ARCH(ARM64)
32
const int MAX_JIT_BLOCK_EXITS = 4;
33
#else
34
const int MAX_JIT_BLOCK_EXITS = 8;
35
#endif
36
constexpr bool JIT_USE_COMPILEDHASH = true;
37
38
struct BlockCacheStats {
39
int numBlocks;
40
float avgBloat; // In code bytes, not instructions!
41
float minBloat;
42
u32 minBloatBlock;
43
float maxBloat;
44
u32 maxBloatBlock;
45
};
46
47
enum class DestroyType {
48
DESTROY,
49
INVALIDATE,
50
// Skips jit unlink, since it'll be poisoned anyway.
51
CLEAR,
52
};
53
54
// Define this in order to get VTune profile support for the Jit generated code.
55
// Add the VTune include/lib directories to the project directories to get this to build.
56
// #define USE_VTUNE
57
58
// We should be careful not to access these block structures during runtime as they are large.
59
// Fine to mess with them at block compile time though.
60
struct JitBlock {
61
bool ContainsAddress(u32 em_address) const;
62
63
const u8 *checkedEntry; // const, we have to translate to writable.
64
const u8 *normalEntry;
65
66
u8 *exitPtrs[MAX_JIT_BLOCK_EXITS]; // to be able to rewrite the exit jump
67
u32 exitAddress[MAX_JIT_BLOCK_EXITS]; // 0xFFFFFFFF == unknown
68
69
u32 originalAddress;
70
MIPSOpcode originalFirstOpcode; //to be able to restore
71
uint64_t compiledHash;
72
u16 codeSize;
73
u16 originalSize;
74
u16 blockNum;
75
76
bool invalid;
77
bool linkStatus[MAX_JIT_BLOCK_EXITS];
78
79
#ifdef USE_VTUNE
80
char blockName[32];
81
#endif
82
83
// By having a pointer, we avoid a constructor/destructor being generated and dog slow
84
// performance in debug.
85
std::vector<u32> *proxyFor;
86
87
bool IsPureProxy() const {
88
return originalFirstOpcode.encoding == 0x68FF0000;
89
}
90
void SetPureProxy() {
91
// Magic number that won't be a real opcode.
92
originalFirstOpcode.encoding = 0x68FF0000;
93
}
94
};
95
96
typedef void (*CompiledCode)();
97
98
struct JitBlockDebugInfo {
99
uint32_t originalAddress;
100
std::vector<std::string> origDisasm;
101
std::vector<std::string> irDisasm; // if any
102
std::vector<std::string> targetDisasm;
103
};
104
105
struct JitBlockMeta {
106
bool valid;
107
uint32_t addr;
108
uint32_t sizeInBytes;
109
};
110
111
struct JitBlockProfileStats {
112
int64_t executions;
113
int64_t totalNanos;
114
};
115
116
class JitBlockCacheDebugInterface {
117
public:
118
virtual int GetNumBlocks() const = 0;
119
virtual int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const = 0;
120
virtual JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const = 0; // Expensive
121
virtual JitBlockMeta GetBlockMeta(int blockNum) const = 0;
122
virtual JitBlockProfileStats GetBlockProfileStats(int blockNum) const = 0;
123
virtual void ComputeStats(BlockCacheStats &bcStats) const = 0;
124
virtual bool IsValidBlock(int blockNum) const = 0;
125
virtual bool SupportsProfiling() const { return false; }
126
127
virtual ~JitBlockCacheDebugInterface() {}
128
};
129
130
class JitBlockCache : public JitBlockCacheDebugInterface {
131
public:
132
JitBlockCache(MIPSState *mipsState, CodeBlockCommon *codeBlock);
133
~JitBlockCache();
134
135
int AllocateBlock(u32 em_address);
136
// When a proxy block is invalidated, the block located at the rootAddress is invalidated too.
137
void ProxyBlock(u32 rootAddress, u32 startAddress, u32 size, const u8 *codePtr);
138
void FinalizeBlock(int block_num, bool block_link);
139
140
void Clear();
141
void Init();
142
void Shutdown();
143
void Reset();
144
145
bool IsFull() const;
146
void ComputeStats(BlockCacheStats &bcStats) const override;
147
148
// Code Cache
149
JitBlock *GetBlock(int block_num);
150
const JitBlock *GetBlock(int block_num) const;
151
152
// Fast way to get a block. Only works on the first source-cpu instruction of a block.
153
int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const override;
154
155
// slower, but can get numbers from within blocks, not just the first instruction.
156
// WARNING! WILL NOT WORK WITH JIT INLINING ENABLED (not yet a feature but will be soon)
157
// Returns a list of block numbers - only one block can start at a particular address, but they CAN overlap.
158
// This one is slow so should only be used for one-shots from the debugger UI, not for anything during runtime.
159
void GetBlockNumbersFromAddress(u32 em_address, std::vector<int> *block_numbers);
160
// Similar to above, but only the first matching address.
161
int GetBlockNumberFromAddress(u32 em_address);
162
int GetBlockNumberFromEmuHackOp(MIPSOpcode inst, bool ignoreBad = false) const;
163
164
u32 GetAddressFromBlockPtr(const u8 *ptr) const;
165
166
MIPSOpcode GetOriginalFirstOp(int block_num);
167
168
bool RangeMayHaveEmuHacks(u32 start, u32 end) const;
169
170
// DOES NOT WORK CORRECTLY WITH JIT INLINING
171
void InvalidateICache(u32 address, const u32 length);
172
void InvalidateChangedBlocks();
173
void DestroyBlock(int block_num, DestroyType type);
174
175
// No jit operations may be run between these calls.
176
// Meant to be used to make memory safe for savestates, memcpy, etc.
177
std::vector<u32> SaveAndClearEmuHackOps();
178
void RestoreSavedEmuHackOps(const std::vector<u32> &saved);
179
180
int GetNumBlocks() const override { return num_blocks_; }
181
bool IsValidBlock(int blockNum) const override { return blockNum >= 0 && blockNum < num_blocks_ && !blocks_[blockNum].invalid; }
182
JitBlockMeta GetBlockMeta(int blockNum) const override {
183
JitBlockMeta meta{};
184
if (IsValidBlock(blockNum)) {
185
meta.valid = true;
186
meta.addr = blocks_[blockNum].originalAddress;
187
meta.sizeInBytes = blocks_[blockNum].originalSize;
188
}
189
return meta;
190
}
191
JitBlockProfileStats GetBlockProfileStats(int blockNum) const override {
192
return JitBlockProfileStats{};
193
}
194
195
static int GetBlockExitSize();
196
197
JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const override;
198
199
enum {
200
MAX_BLOCK_INSTRUCTIONS = 0x4000,
201
};
202
203
private:
204
void LinkBlockExits(int i);
205
void LinkBlock(int i);
206
void UnlinkBlock(int i);
207
208
void AddBlockMap(int block_num);
209
void RemoveBlockMap(int block_num);
210
211
MIPSOpcode GetEmuHackOpForBlock(int block_num) const;
212
213
CodeBlockCommon *codeBlock_;
214
JitBlock *blocks_ = nullptr;
215
std::unordered_multimap<u32, int> proxyBlockMap_;
216
217
int num_blocks_ = 0;
218
std::unordered_multimap<u32, int> links_to_;
219
std::map<std::pair<u32,u32>, u32> block_map_; // (end_addr, start_addr) -> number
220
221
enum {
222
JITBLOCK_RANGE_SCRATCH = 0,
223
JITBLOCK_RANGE_RAMBOTTOM = 1,
224
JITBLOCK_RANGE_RAMTOP = 2,
225
JITBLOCK_RANGE_COUNT = 3,
226
};
227
std::pair<u32, u32> blockMemRanges_[3];
228
229
enum {
230
MAX_NUM_BLOCKS = 65536*2
231
};
232
};
233
234
235