Merge pull request #1167 from vlj/llvm36

PPU/LLVM: Try to fix crash (again) when cleaning modules
This commit is contained in:
Hykem 2015-08-02 16:54:12 +01:00
commit 7aa86c50c6
3 changed files with 45 additions and 23 deletions

View File

@ -282,7 +282,15 @@ const Executable *RecompilationEngine::GetExecutable(u32 address, bool isFunctio
return isFunction ? &executeFunc : &executeUntilReturn;
}
const Executable *RecompilationEngine::GetCompiledExecutableIfAvailable(u32 address, std::mutex *mut)
std::mutex* RecompilationEngine::GetMutexForAddress(u32 address) {
std::lock_guard<std::mutex> lock(m_address_locks_lock);
std::unordered_map<u32, std::mutex>::iterator It = m_address_locks.find(address);
if (It == m_address_locks.end())
return nullptr;
return &(It->second);
}
const Executable *RecompilationEngine::GetCompiledExecutableIfAvailable(u32 address)
{
std::lock_guard<std::mutex> lock(m_address_to_function_lock);
std::unordered_map<u32, ExecutableStorage>::iterator It = m_address_to_function.find(address);
@ -290,7 +298,6 @@ const Executable *RecompilationEngine::GetCompiledExecutableIfAvailable(u32 addr
return nullptr;
if (std::get<1>(It->second) == nullptr)
return nullptr;
mut = &(std::get<3>(It->second));
return &(std::get<0>(It->second));
}
@ -528,8 +535,14 @@ void RecompilationEngine::CompileBlock(BlockEntry & block_entry) {
std::get<1>(m_address_to_function[block_entry.cfg.start_address]) = nullptr;
}
// Prevent access on this block
std::lock_guard<std::mutex> lock(std::get<3>(m_address_to_function[block_entry.cfg.start_address]));
std::unordered_map<u32, std::mutex>::iterator It2 = m_address_locks.find(block_entry.cfg.start_address);
if (It2 == m_address_locks.end())
{
std::lock_guard<std::mutex> lock(m_address_locks_lock);
(void)m_address_locks[block_entry.cfg.start_address];
}
std::lock_guard<std::mutex> lock(m_address_locks[block_entry.cfg.start_address]);
std::get<1>(m_address_to_function[block_entry.cfg.start_address]) = std::unique_ptr<llvm::ExecutionEngine>(compileResult.second);
std::get<0>(m_address_to_function[block_entry.cfg.start_address]) = compileResult.first;
@ -679,17 +692,16 @@ u32 ppu_recompiler_llvm::CPUHybridDecoderRecompiler::ExecuteTillReturn(PPUThread
execution_engine->m_tracer.Trace(Tracer::TraceType::ExitFromCompiledFunction, context >> 32, context & 0xFFFFFFFF);
while (PollStatus(ppu_state) == false) {
std::mutex mut;
const Executable *executable = execution_engine->m_recompilation_engine->GetCompiledExecutableIfAvailable(ppu_state->PC, &mut);
if (executable) {
std::lock_guard<std::mutex> lock(mut);
std::mutex *mut = execution_engine->m_recompilation_engine->GetMutexForAddress(ppu_state->PC);
if (mut) {
std::lock_guard<std::mutex> lock(*mut);
const Executable *executable = execution_engine->m_recompilation_engine->GetCompiledExecutableIfAvailable(ppu_state->PC);
auto entry = ppu_state->PC;
u32 exit = (u32)(*executable)(ppu_state, 0);
execution_engine->m_tracer.Trace(Tracer::TraceType::ExitFromCompiledBlock, entry, exit);
if (exit == 0)
return 0;
}
else {
} else {
execution_engine->m_tracer.Trace(Tracer::TraceType::Instruction, ppu_state->PC, 0);
u32 instruction = vm::ps3::read32(ppu_state->PC);
u32 oldPC = ppu_state->PC;
@ -702,11 +714,12 @@ u32 ppu_recompiler_llvm::CPUHybridDecoderRecompiler::ExecuteTillReturn(PPUThread
execution_engine->m_tracer.Trace(Tracer::TraceType::Return, 0, 0);
if (Emu.GetCPUThreadStop() == ppu_state->PC) ppu_state->fast_stop();
return 0;
case BranchType::FunctionCall:
case BranchType::FunctionCall: {
execution_engine->m_tracer.Trace(Tracer::TraceType::CallFunction, ppu_state->PC, 0);
executable = execution_engine->m_recompilation_engine->GetExecutable(ppu_state->PC, true);
const Executable *executable = execution_engine->m_recompilation_engine->GetExecutable(ppu_state->PC, true);
(*executable)(ppu_state, 0);
break;
}
case BranchType::LocalBranch:
break;
case BranchType::NonBranch:

View File

@ -998,6 +998,7 @@ namespace ppu_recompiler_llvm {
* using atomic based locks to avoid undefined behavior.
**/
class RecompilationEngine final : protected thread_t {
friend class CPUHybridDecoderRecompiler;
public:
virtual ~RecompilationEngine() override;
@ -1008,11 +1009,16 @@ namespace ppu_recompiler_llvm {
**/
const Executable *GetExecutable(u32 address, bool isFunction);
/**
* Get a mutex for an address. Used to avoid modifying a block currently in execution.
**/
std::mutex* GetMutexForAddress(u32 address);
/**
* Get the executable for the specified address if a compiled version is
* available, otherwise returns nullptr.
**/
const Executable *GetCompiledExecutableIfAvailable(u32 address, std::mutex*);
const Executable *GetCompiledExecutableIfAvailable(u32 address);
/// Notify the recompilation engine about a newly detected trace. It takes ownership of the trace.
void NotifyTrace(ExecutionTrace * execution_trace);
@ -1094,11 +1100,14 @@ namespace ppu_recompiler_llvm {
/// Lock for accessing m_address_to_function.
std::mutex m_address_to_function_lock;
/// Lock for modifying address mutex table
std::mutex m_address_locks_lock;
/// (function, module containing function, times hit, mutex for access).
typedef std::tuple<Executable, std::unique_ptr<llvm::ExecutionEngine>, u32, std::mutex> ExecutableStorage;
typedef std::tuple<Executable, std::unique_ptr<llvm::ExecutionEngine>, u32> ExecutableStorage;
/// Address to ordinal cahce. Key is address.
std::unordered_map<u32, ExecutableStorage> m_address_to_function;
std::unordered_map<u32, std::mutex> m_address_locks;
/// The time at which the m_address_to_ordinal cache was last cleared
std::chrono::high_resolution_clock::time_point m_last_cache_clear_time;
@ -1233,7 +1242,7 @@ namespace ppu_recompiler_llvm {
std::unordered_map<std::string, Executable>::const_iterator It = executableMap.find(Name);
if (It != executableMap.end())
return (uint64_t)It->second;
return 0;
return getSymbolAddressInProcess(Name);
}
};
}

View File

@ -496,8 +496,8 @@ void Compiler::RunAllTests() {
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VCTSXS, 5, 5, 0u, 3u, 1u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VCTUXS, 0, 5, 0u, 0u, 1u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VCTUXS, 5, 5, 0u, 3u, 1u);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VEXPTEFP, 0, 5, 0u, 1u); CRASH!
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VLOGEFP, 0, 5, 0u, 1u); CRASH!
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VEXPTEFP, 0, 5, 0u, 1u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VLOGEFP, 0, 5, 0u, 1u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VMADDFP, 0, 5, 0u, 1u, 2u, 3u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VMAXFP, 0, 5, 0u, 1u, 2u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VMAXSB, 0, 5, 0u, 1u, 2u);
@ -931,9 +931,9 @@ void Compiler::RunAllTests() {
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWX, 0, input, 3u, 0u, 23u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWX, 1, input, 3u, 14u, 23u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWUX, 0, input, 3u, 14u, 23u);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVLX, 0, input, 0u, 0u, 23u); CRASH
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVLX, 1, input, 0u, 14u, 23u); CRASH
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVLX, 2, input, 0u, 21u, 23u); CRASH
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVLX, 0, input, 0u, 0u, 23u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVLX, 1, input, 0u, 14u, 23u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVLX, 2, input, 0u, 21u, 23u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWBRX, 0, input, 3u, 14u, 23u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STD, 0, input, 3u, 0u, 0x10000);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STD, 1, input, 3u, 14u, 0x10000);
@ -948,9 +948,9 @@ void Compiler::RunAllTests() {
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFSU, 0, input, 3u, 14u, 0x10000);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFSX, 0, input, 3u, 0u, 23u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFSX, 1, input, 3u, 14u, 23u);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVRX, 0, input, 0u, 0u, 23u); CRASH
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVRX, 1, input, 0u, 14u, 23u); CRASH
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVRX, 2, input, 0u, 21u, 23u); CRASH
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVRX, 0, input, 0u, 0u, 23u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVRX, 1, input, 0u, 14u, 23u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVRX, 2, input, 0u, 21u, 23u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFSUX, 0, input, 3u, 14u, 23u);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFD, 0, input, 3u, 0u, 0x10000);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFD, 1, input, 3u, 14u, 0x10000);