152 lines
5.1 KiB
C++
152 lines
5.1 KiB
C++
/* Copyright (c) 2014 Steven Flintham
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the 'Software'),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, provided that the above copyright notice(s) and this
|
|
* permission notice appear in all copies of the Software and that both the
|
|
* above copyright notice(s) and this permission notice appear in supporting
|
|
* documentation.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
|
|
*/
|
|
|
|
#ifndef FUNCTIONMANAGER_H
|
|
#define FUNCTIONMANAGER_H
|
|
|
|
#include <assert.h>
|
|
#include <boost/shared_ptr.hpp>
|
|
#include <boost/thread/condition_variable.hpp>
|
|
#include <boost/thread/mutex.hpp>
|
|
#include <boost/thread/thread.hpp>
|
|
#include <boost/utility.hpp>
|
|
#include <set>
|
|
#include <stdint.h>
|
|
|
|
#include "const.h"
|
|
#include "JitBool.h"
|
|
#include "lib6502.h"
|
|
|
|
class Function;
|
|
|
|
class FunctionManager : boost::noncopyable
|
|
{
|
|
public:
|
|
FunctionManager(M6502 *mpu);
|
|
~FunctionManager();
|
|
|
|
bool jit_thread_idle();
|
|
|
|
void update_memory_snapshot();
|
|
|
|
// Return a Function object representing the code starting at 'address'; if
|
|
// one does not already exist it will be created. This never returns null.
|
|
Function *get_function(uint16_t address)
|
|
{
|
|
Function *f = function_for_address_[address];
|
|
if (f != 0)
|
|
{
|
|
return f;
|
|
}
|
|
else
|
|
{
|
|
return build_function(address, mpu_->memory);
|
|
}
|
|
}
|
|
|
|
// Return a Function object representing the code starting at 'address',
|
|
// if one is available, otherwise return null. When null is returned
|
|
// a background thread may be used to generate a Function object which
|
|
// can be returned if the request is repeated in the future.
|
|
//
|
|
// This function may only be called if the last call to jit_thread_idle()
|
|
// returned true and no call has been made to get_function_lazy() since
|
|
// jit_thread_idle() was called.
|
|
//
|
|
// Currently a background thread will *always* be invoked if null is
|
|
// returned, but this is not guaranteed. For example, we may wish to
|
|
// refuse to waste time building a Function object which we expect to
|
|
// be invalidated by self-modifying code shortly afterwards.
|
|
Function *get_function_lazy(uint16_t address)
|
|
{
|
|
// This assert() is perfectly correct, but it single-handedly destroys
|
|
// the performance of a debug build; it's just not *that* valuable.
|
|
// assert(jit_thread_idle());
|
|
|
|
Function *f = function_for_address_[address];
|
|
if (f != 0)
|
|
{
|
|
return f;
|
|
}
|
|
else
|
|
{
|
|
build_function_lazy(address);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void code_modified_at(uint16_t address);
|
|
|
|
private:
|
|
void add_function(const boost::shared_ptr<Function> &f);
|
|
|
|
Function *build_function(uint16_t address, const uint8_t *ct_memory);
|
|
Function *build_function_internal(uint16_t address,
|
|
const uint8_t *ct_memory);
|
|
|
|
void build_function_lazy(uint16_t address);
|
|
void build_function_thread();
|
|
|
|
typedef std::set<Function *> FunctionSet;
|
|
void destroy_functions_in_set(FunctionSet &function_set);
|
|
|
|
void destroy_function(Function *f);
|
|
|
|
boost::thread jit_thread_;
|
|
|
|
boost::mutex jit_thread_idle_mutex_;
|
|
bool jit_thread_idle_;
|
|
|
|
boost::mutex jit_thread_cv_mutex_;
|
|
boost::condition_variable jit_thread_cv_;
|
|
bool work_available_;
|
|
uint16_t jit_thread_address_;
|
|
bool quit_;
|
|
|
|
M6502 *mpu_;
|
|
|
|
// A copy of the emulated CPU's memory, used to detect changes to already
|
|
// JITted code which happen in callbacks and to avoid problems with JITting
|
|
// while the interpreter is running (in hybrid mode).
|
|
uint8_t memory_snapshot_[memory_size];
|
|
|
|
// We maintain this array of shared_ptr's which actually own the
|
|
// Function objects.
|
|
boost::shared_ptr<Function> function_for_address_owner_[memory_size];
|
|
|
|
// We maintain a parallel array of raw pointers here so that we have
|
|
// the option to allow JITted code to access it.
|
|
Function *function_for_address_[memory_size];
|
|
|
|
// This tracks the Function objects which contain code generated based on
|
|
// individual addresses, i.e. the Function objects which are invalidated by
|
|
// a store to a given memory location.
|
|
FunctionSet functions_covering_address_[memory_size];
|
|
|
|
// This tracks the Function objects which perform optimistic writes to
|
|
// individual addresses, i.e. the Function objects which are invalidated if
|
|
// it turns out an address is in fact used to hold code.
|
|
FunctionSet optimistic_writers_for_address_[memory_size];
|
|
|
|
// This tracks whether we have ever executed code at a given address;
|
|
// destroying all the functions in the corresponding element of
|
|
// functions_covering_address does *not* mean this is cleared.
|
|
JitBool code_at_address_[memory_size];
|
|
};
|
|
|
|
#endif
|