mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-25 12:50:00 +00:00
For PR540:
This patch completes the changes for making lli thread-safe. Here's the list of changes: * The Support/ThreadSupport* files were removed and replaced with the MutexGuard.h file since all ThreadSupport* declared was a Mutex Guard. The implementation of MutexGuard.h is now based on sys::Mutex which hides its implementation and makes it unnecessary to have the -NoSupport.h and -PThreads.h versions of ThreadSupport. * All places in ExecutionEngine that previously referred to "Mutex" now refer to sys::Mutex * All places in ExecutionEngine that previously referred to "MutexLocker" now refer to MutexGuard (this is frivolous but I believe the technically correct name for such a class is "Guard" not a "Locker"). These changes passed all of llvm-test. All we need now are some test cases that actually use multiple threads. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22404 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
b2164e5cb5
commit
ee448630bd
@ -606,12 +606,10 @@ dnl===
|
||||
dnl===-----------------------------------------------------------------------===
|
||||
|
||||
dnl Configure header files
|
||||
AC_CONFIG_HEADERS(include/llvm/Config/config.h)
|
||||
|
||||
AC_CONFIG_HEADERS([include/llvm/Config/config.h])
|
||||
AC_CONFIG_HEADERS([include/llvm/Support/DataTypes.h])
|
||||
AC_CONFIG_HEADERS([include/llvm/ADT/hash_map])
|
||||
AC_CONFIG_HEADERS([include/llvm/ADT/hash_set])
|
||||
AC_CONFIG_HEADERS([include/llvm/Support/ThreadSupport.h])
|
||||
AC_CONFIG_HEADERS([include/llvm/ADT/iterator])
|
||||
|
||||
dnl Configure the makefile's configuration data
|
||||
|
4
configure
vendored
4
configure
vendored
@ -30489,15 +30489,12 @@ _ACEOF
|
||||
|
||||
ac_config_headers="$ac_config_headers include/llvm/Config/config.h"
|
||||
|
||||
|
||||
ac_config_headers="$ac_config_headers include/llvm/Support/DataTypes.h"
|
||||
|
||||
ac_config_headers="$ac_config_headers include/llvm/ADT/hash_map"
|
||||
|
||||
ac_config_headers="$ac_config_headers include/llvm/ADT/hash_set"
|
||||
|
||||
ac_config_headers="$ac_config_headers include/llvm/Support/ThreadSupport.h"
|
||||
|
||||
ac_config_headers="$ac_config_headers include/llvm/ADT/iterator"
|
||||
|
||||
|
||||
@ -31106,7 +31103,6 @@ do
|
||||
"include/llvm/Support/DataTypes.h" ) CONFIG_HEADERS="$CONFIG_HEADERS include/llvm/Support/DataTypes.h" ;;
|
||||
"include/llvm/ADT/hash_map" ) CONFIG_HEADERS="$CONFIG_HEADERS include/llvm/ADT/hash_map" ;;
|
||||
"include/llvm/ADT/hash_set" ) CONFIG_HEADERS="$CONFIG_HEADERS include/llvm/ADT/hash_set" ;;
|
||||
"include/llvm/Support/ThreadSupport.h" ) CONFIG_HEADERS="$CONFIG_HEADERS include/llvm/Support/ThreadSupport.h" ;;
|
||||
"include/llvm/ADT/iterator" ) CONFIG_HEADERS="$CONFIG_HEADERS include/llvm/ADT/iterator" ;;
|
||||
*) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
|
||||
echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include "llvm/Support/MutexGuard.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -33,10 +34,9 @@ class TargetData;
|
||||
class Type;
|
||||
class IntrinsicLowering;
|
||||
|
||||
class ExecutionEngine {
|
||||
Module &CurMod;
|
||||
const TargetData *TD;
|
||||
|
||||
class ExecutionEngineState {
|
||||
private:
|
||||
/// GlobalAddressMap - A mapping between LLVM global values and their
|
||||
/// actualized version...
|
||||
std::map<const GlobalValue*, void *> GlobalAddressMap;
|
||||
@ -46,6 +46,24 @@ class ExecutionEngine {
|
||||
/// at the address. This map is not computed unless getGlobalValueAtAddress
|
||||
/// is called at some point.
|
||||
std::map<void *, const GlobalValue*> GlobalAddressReverseMap;
|
||||
|
||||
public:
|
||||
std::map<const GlobalValue*, void *>& getGlobalAddressMap(const MutexGuard& locked) {
|
||||
return GlobalAddressMap;
|
||||
}
|
||||
|
||||
std::map<void *, const GlobalValue*>& getGlobalAddressReverseMap(const MutexGuard& locked) {
|
||||
return GlobalAddressReverseMap;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ExecutionEngine {
|
||||
Module &CurMod;
|
||||
const TargetData *TD;
|
||||
|
||||
ExecutionEngineState state;
|
||||
|
||||
protected:
|
||||
ModuleProvider *MP;
|
||||
|
||||
@ -54,6 +72,10 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
/// lock - This lock is protects the ExecutionEngine, JIT, JITResolver and JITEmitter classes.
|
||||
/// It must be held while changing the internal state of any of those classes.
|
||||
sys::Mutex lock; // Used to make this class and subclasses thread-safe
|
||||
|
||||
ExecutionEngine(ModuleProvider *P);
|
||||
ExecutionEngine(Module *M);
|
||||
virtual ~ExecutionEngine();
|
||||
@ -81,13 +103,15 @@ public:
|
||||
|
||||
|
||||
void addGlobalMapping(const GlobalValue *GV, void *Addr) {
|
||||
void *&CurVal = GlobalAddressMap[GV];
|
||||
MutexGuard locked(lock);
|
||||
|
||||
void *&CurVal = state.getGlobalAddressMap(locked)[GV];
|
||||
assert((CurVal == 0 || Addr == 0) && "GlobalMapping already established!");
|
||||
CurVal = Addr;
|
||||
|
||||
// If we are using the reverse mapping, add it too
|
||||
if (!GlobalAddressReverseMap.empty()) {
|
||||
const GlobalValue *&V = GlobalAddressReverseMap[Addr];
|
||||
if (!state.getGlobalAddressReverseMap(locked).empty()) {
|
||||
const GlobalValue *&V = state.getGlobalAddressReverseMap(locked)[Addr];
|
||||
assert((V == 0 || GV == 0) && "GlobalMapping already established!");
|
||||
V = GV;
|
||||
}
|
||||
@ -96,21 +120,25 @@ public:
|
||||
/// clearAllGlobalMappings - Clear all global mappings and start over again
|
||||
/// use in dynamic compilation scenarios when you want to move globals
|
||||
void clearAllGlobalMappings() {
|
||||
GlobalAddressMap.clear();
|
||||
GlobalAddressReverseMap.clear();
|
||||
MutexGuard locked(lock);
|
||||
|
||||
state.getGlobalAddressMap(locked).clear();
|
||||
state.getGlobalAddressReverseMap(locked).clear();
|
||||
}
|
||||
|
||||
/// updateGlobalMapping - Replace an existing mapping for GV with a new
|
||||
/// address. This updates both maps as required.
|
||||
void updateGlobalMapping(const GlobalValue *GV, void *Addr) {
|
||||
void *&CurVal = GlobalAddressMap[GV];
|
||||
if (CurVal && !GlobalAddressReverseMap.empty())
|
||||
GlobalAddressReverseMap.erase(CurVal);
|
||||
MutexGuard locked(lock);
|
||||
|
||||
void *&CurVal = state.getGlobalAddressMap(locked)[GV];
|
||||
if (CurVal && !state.getGlobalAddressReverseMap(locked).empty())
|
||||
state.getGlobalAddressReverseMap(locked).erase(CurVal);
|
||||
CurVal = Addr;
|
||||
|
||||
// If we are using the reverse mapping, add it too
|
||||
if (!GlobalAddressReverseMap.empty()) {
|
||||
const GlobalValue *&V = GlobalAddressReverseMap[Addr];
|
||||
if (!state.getGlobalAddressReverseMap(locked).empty()) {
|
||||
const GlobalValue *&V = state.getGlobalAddressReverseMap(locked)[Addr];
|
||||
assert((V == 0 || GV == 0) && "GlobalMapping already established!");
|
||||
V = GV;
|
||||
}
|
||||
@ -120,8 +148,10 @@ public:
|
||||
/// global value if it is available, otherwise it returns null.
|
||||
///
|
||||
void *getPointerToGlobalIfAvailable(const GlobalValue *GV) {
|
||||
std::map<const GlobalValue*, void*>::iterator I = GlobalAddressMap.find(GV);
|
||||
return I != GlobalAddressMap.end() ? I->second : 0;
|
||||
MutexGuard locked(lock);
|
||||
|
||||
std::map<const GlobalValue*, void*>::iterator I = state.getGlobalAddressMap(locked).find(GV);
|
||||
return I != state.getGlobalAddressMap(locked).end() ? I->second : 0;
|
||||
}
|
||||
|
||||
/// getPointerToGlobal - This returns the address of the specified global
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- Support/ThreadSupport.h - Generic threading support -----*- C++ -*-===//
|
||||
//===-- Support/MutexGuard.h - Acquire/Release Mutex In Scope ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -7,36 +7,35 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines platform-agnostic interfaces that can be used to write
|
||||
// multi-threaded programs. Autoconf is used to chose the correct
|
||||
// implementation of these interfaces, or default to a non-thread-capable system
|
||||
// if no matching system support is available.
|
||||
// This file defines a guard for a block of code that ensures a Mutex is locked
|
||||
// upon construction and released upon destruction.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_THREADSUPPORT_H
|
||||
#define LLVM_SUPPORT_THREADSUPPORT_H
|
||||
#ifndef LLVM_SUPPORT_MUTEXGUARD_H
|
||||
#define LLVM_SUPPORT_MUTEXGUARD_H
|
||||
|
||||
#undef HAVE_PTHREAD_MUTEX_LOCK
|
||||
|
||||
#ifdef HAVE_PTHREAD_MUTEX_LOCK
|
||||
#include "llvm/Support/ThreadSupport-PThreads.h"
|
||||
#else
|
||||
#include "llvm/Support/ThreadSupport-NoSupport.h"
|
||||
#endif // If no system support is available
|
||||
#include <llvm/System/Mutex.h>
|
||||
|
||||
namespace llvm {
|
||||
/// MutexLocker - Instances of this class acquire a given Lock when
|
||||
/// constructed and hold that lock until destruction.
|
||||
///
|
||||
class MutexLocker {
|
||||
Mutex &M;
|
||||
MutexLocker(const MutexLocker &); // DO NOT IMPLEMENT
|
||||
void operator=(const MutexLocker &); // DO NOT IMPLEMENT
|
||||
/// Instances of this class acquire a given Mutex Lock when constructed and
|
||||
/// hold that lock until destruction. The intention is to instantiate one of
|
||||
/// these on the stack at the top of some scope to be assured that C++
|
||||
/// destruction of the object will always release the Mutex and thus avoid
|
||||
/// a host of nasty multi-threading problems in the face of exceptions, etc.
|
||||
/// @brief Guard a section of code with a Mutex.
|
||||
class MutexGuard {
|
||||
sys::Mutex &M;
|
||||
MutexGuard(const MutexGuard &); // DO NOT IMPLEMENT
|
||||
void operator=(const MutexGuard &); // DO NOT IMPLEMENT
|
||||
public:
|
||||
MutexLocker(Mutex &m) : M(m) { M.acquire(); }
|
||||
~MutexLocker() { M.release(); }
|
||||
MutexGuard(sys::Mutex &m) : M(m) { M.acquire(); }
|
||||
~MutexGuard() { M.release(); }
|
||||
/// holds - Returns true if this locker instance holds the specified lock.
|
||||
/// This is mostly used in assertions to validate that the correct mutex
|
||||
/// is held.
|
||||
bool holds(const sys::Mutex& lock) const { return &M == &lock; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SUPPORT_THREADSUPPORT_H
|
||||
#endif // LLVM_SUPPORT_MUTEXGUARD_H
|
||||
|
@ -1,34 +0,0 @@
|
||||
//===-- llvm/Support/ThreadSupport-NoSupport.h - Generic Impl ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a generic ThreadSupport implementation used when there is
|
||||
// no supported threading mechanism on the current system. Users should never
|
||||
// #include this file directly!
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Users should never #include this file directly! As such, no include guards
|
||||
// are needed.
|
||||
|
||||
#ifndef LLVM_SUPPORT_THREADSUPPORT_H
|
||||
#error "Code should not #include Support/ThreadSupport-NoSupport.h directly!"
|
||||
#endif
|
||||
|
||||
namespace llvm {
|
||||
/// Mutex - This class allows user code to protect variables shared between
|
||||
/// threads. It implements a "recursive" mutex, to simplify user code.
|
||||
///
|
||||
/// Since there is no platform support for _creating threads_, the non-thread
|
||||
/// implementation of this class is a noop.
|
||||
///
|
||||
struct Mutex {
|
||||
void acquire () {}
|
||||
void release () {}
|
||||
};
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
//===-- llvm/Support/ThreadSupport-PThreads.h - PThreads support *- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines pthreads implementations of the generic threading
|
||||
// mechanisms. Users should never #include this file directly!
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Users should never #include this file directly! As such, no include guards
|
||||
// are needed.
|
||||
|
||||
#ifndef LLVM_SUPPORT_THREADSUPPORT_H
|
||||
#error "Code should not #include Support/ThreadSupport/PThreads.h directly!"
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Mutex - This class allows user code to protect variables shared between
|
||||
/// threads. It implements a "recursive" mutex, to simplify user code.
|
||||
///
|
||||
class Mutex {
|
||||
pthread_mutex_t mutex;
|
||||
Mutex(const Mutex &); // DO NOT IMPLEMENT
|
||||
void operator=(const Mutex &); // DO NOT IMPLEMENT
|
||||
public:
|
||||
Mutex() {
|
||||
// Initialize the mutex as a recursive mutex
|
||||
pthread_mutexattr_t Attr;
|
||||
int errorcode = pthread_mutexattr_init(&Attr);
|
||||
assert(errorcode == 0);
|
||||
|
||||
errorcode = pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
assert(errorcode == 0);
|
||||
|
||||
errorcode = pthread_mutex_init(&mutex, &Attr);
|
||||
assert(errorcode == 0);
|
||||
|
||||
errorcode = pthread_mutexattr_destroy(&Attr);
|
||||
assert(errorcode == 0);
|
||||
}
|
||||
|
||||
~Mutex() {
|
||||
int errorcode = pthread_mutex_destroy(&mutex);
|
||||
assert(errorcode == 0);
|
||||
}
|
||||
|
||||
void acquire () {
|
||||
int errorcode = pthread_mutex_lock(&mutex);
|
||||
assert(errorcode == 0);
|
||||
}
|
||||
|
||||
void release () {
|
||||
int errorcode = pthread_mutex_unlock(&mutex);
|
||||
assert(errorcode == 0);
|
||||
}
|
||||
};
|
||||
} // end namespace llvm
|
@ -1,42 +0,0 @@
|
||||
//===-- Support/ThreadSupport.h - Generic threading support -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines platform-agnostic interfaces that can be used to write
|
||||
// multi-threaded programs. Autoconf is used to chose the correct
|
||||
// implementation of these interfaces, or default to a non-thread-capable system
|
||||
// if no matching system support is available.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_THREADSUPPORT_H
|
||||
#define LLVM_SUPPORT_THREADSUPPORT_H
|
||||
|
||||
#undef HAVE_PTHREAD_MUTEX_LOCK
|
||||
|
||||
#ifdef HAVE_PTHREAD_MUTEX_LOCK
|
||||
#include "llvm/Support/ThreadSupport-PThreads.h"
|
||||
#else
|
||||
#include "llvm/Support/ThreadSupport-NoSupport.h"
|
||||
#endif // If no system support is available
|
||||
|
||||
namespace llvm {
|
||||
/// MutexLocker - Instances of this class acquire a given Lock when
|
||||
/// constructed and hold that lock until destruction.
|
||||
///
|
||||
class MutexLocker {
|
||||
Mutex &M;
|
||||
MutexLocker(const MutexLocker &); // DO NOT IMPLEMENT
|
||||
void operator=(const MutexLocker &); // DO NOT IMPLEMENT
|
||||
public:
|
||||
MutexLocker(Mutex &m) : M(m) { M.acquire(); }
|
||||
~MutexLocker() { M.release(); }
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SUPPORT_THREADSUPPORT_H
|
@ -50,16 +50,18 @@ ExecutionEngine::~ExecutionEngine() {
|
||||
/// at the specified address.
|
||||
///
|
||||
const GlobalValue *ExecutionEngine::getGlobalValueAtAddress(void *Addr) {
|
||||
MutexGuard locked(lock);
|
||||
|
||||
// If we haven't computed the reverse mapping yet, do so first.
|
||||
if (GlobalAddressReverseMap.empty()) {
|
||||
if (state.getGlobalAddressReverseMap(locked).empty()) {
|
||||
for (std::map<const GlobalValue*, void *>::iterator I =
|
||||
GlobalAddressMap.begin(), E = GlobalAddressMap.end(); I != E; ++I)
|
||||
GlobalAddressReverseMap.insert(std::make_pair(I->second, I->first));
|
||||
state.getGlobalAddressMap(locked).begin(), E = state.getGlobalAddressMap(locked).end(); I != E; ++I)
|
||||
state.getGlobalAddressReverseMap(locked).insert(std::make_pair(I->second, I->first));
|
||||
}
|
||||
|
||||
std::map<void *, const GlobalValue*>::iterator I =
|
||||
GlobalAddressReverseMap.find(Addr);
|
||||
return I != GlobalAddressReverseMap.end() ? I->second : 0;
|
||||
state.getGlobalAddressReverseMap(locked).find(Addr);
|
||||
return I != state.getGlobalAddressReverseMap(locked).end() ? I->second : 0;
|
||||
}
|
||||
|
||||
// CreateArgv - Turn a vector of strings into a nice argv style array of
|
||||
@ -168,8 +170,9 @@ void *ExecutionEngine::getPointerToGlobal(const GlobalValue *GV) {
|
||||
if (Function *F = const_cast<Function*>(dyn_cast<Function>(GV)))
|
||||
return getPointerToFunction(F);
|
||||
|
||||
assert(GlobalAddressMap[GV] && "Global hasn't had an address allocated yet?");
|
||||
return GlobalAddressMap[GV];
|
||||
MutexGuard locked(lock);
|
||||
assert(state.getGlobalAddressMap(locked)[GV] && "Global hasn't had an address allocated yet?");
|
||||
return state.getGlobalAddressMap(locked)[GV];
|
||||
}
|
||||
|
||||
/// FIXME: document
|
||||
|
@ -30,13 +30,15 @@
|
||||
using namespace llvm;
|
||||
|
||||
JIT::JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji)
|
||||
: ExecutionEngine(MP), TM(tm), TJI(tji), PM(MP) {
|
||||
: ExecutionEngine(MP), TM(tm), TJI(tji), state(MP) {
|
||||
setTargetData(TM.getTargetData());
|
||||
|
||||
// Initialize MCE
|
||||
MCE = createEmitter(*this);
|
||||
|
||||
// Add target data
|
||||
MutexGuard locked(lock);
|
||||
FunctionPassManager& PM = state.getPM(locked);
|
||||
PM.add(new TargetData(TM.getTargetData()));
|
||||
|
||||
// Compile LLVM Code down to machine code in the intermediate representation
|
||||
@ -216,18 +218,20 @@ GenericValue JIT::runFunction(Function *F,
|
||||
void JIT::runJITOnFunction(Function *F) {
|
||||
static bool isAlreadyCodeGenerating = false;
|
||||
assert(!isAlreadyCodeGenerating && "Error: Recursive compilation detected!");
|
||||
|
||||
MutexGuard locked(lock);
|
||||
|
||||
// JIT the function
|
||||
isAlreadyCodeGenerating = true;
|
||||
PM.run(*F);
|
||||
state.getPM(locked).run(*F);
|
||||
isAlreadyCodeGenerating = false;
|
||||
|
||||
// If the function referred to a global variable that had not yet been
|
||||
// emitted, it allocates memory for the global, but doesn't emit it yet. Emit
|
||||
// all of these globals now.
|
||||
while (!PendingGlobals.empty()) {
|
||||
const GlobalVariable *GV = PendingGlobals.back();
|
||||
PendingGlobals.pop_back();
|
||||
while (!state.getPendingGlobals(locked).empty()) {
|
||||
const GlobalVariable *GV = state.getPendingGlobals(locked).back();
|
||||
state.getPendingGlobals(locked).pop_back();
|
||||
EmitGlobalVariable(GV);
|
||||
}
|
||||
}
|
||||
@ -236,6 +240,8 @@ void JIT::runJITOnFunction(Function *F) {
|
||||
/// specified function, compiling it if neccesary.
|
||||
///
|
||||
void *JIT::getPointerToFunction(Function *F) {
|
||||
MutexGuard locked(lock);
|
||||
|
||||
if (void *Addr = getPointerToGlobalIfAvailable(F))
|
||||
return Addr; // Check if function already code gen'd
|
||||
|
||||
@ -270,6 +276,8 @@ void *JIT::getPointerToFunction(Function *F) {
|
||||
/// variable, possibly emitting it to memory if needed. This is used by the
|
||||
/// Emitter.
|
||||
void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
|
||||
MutexGuard locked(lock);
|
||||
|
||||
void *Ptr = getPointerToGlobalIfAvailable(GV);
|
||||
if (Ptr) return Ptr;
|
||||
|
||||
@ -287,7 +295,7 @@ void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
|
||||
// compilation.
|
||||
uint64_t S = getTargetData().getTypeSize(GV->getType()->getElementType());
|
||||
Ptr = new char[(size_t)S];
|
||||
PendingGlobals.push_back(GV);
|
||||
state.getPendingGlobals(locked).push_back(GV);
|
||||
}
|
||||
addGlobalMapping(GV, Ptr);
|
||||
return Ptr;
|
||||
|
@ -27,18 +27,35 @@ class TargetMachine;
|
||||
class TargetJITInfo;
|
||||
class MachineCodeEmitter;
|
||||
|
||||
class JIT : public ExecutionEngine {
|
||||
TargetMachine &TM; // The current target we are compiling to
|
||||
TargetJITInfo &TJI; // The JITInfo for the target we are compiling to
|
||||
|
||||
class JITState {
|
||||
private:
|
||||
FunctionPassManager PM; // Passes to compile a function
|
||||
MachineCodeEmitter *MCE; // MCE object
|
||||
|
||||
/// PendingGlobals - Global variables which have had memory allocated for them
|
||||
/// while a function was code generated, but which have not been initialized
|
||||
/// yet.
|
||||
std::vector<const GlobalVariable*> PendingGlobals;
|
||||
|
||||
public:
|
||||
JITState(ModuleProvider *MP) : PM(MP) {}
|
||||
|
||||
FunctionPassManager& getPM(const MutexGuard& locked) {
|
||||
return PM;
|
||||
}
|
||||
|
||||
std::vector<const GlobalVariable*>& getPendingGlobals(const MutexGuard& locked) {
|
||||
return PendingGlobals;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class JIT : public ExecutionEngine {
|
||||
TargetMachine &TM; // The current target we are compiling to
|
||||
TargetJITInfo &TJI; // The JITInfo for the target we are compiling to
|
||||
MachineCodeEmitter *MCE; // MCE object
|
||||
|
||||
JITState state;
|
||||
|
||||
JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji);
|
||||
public:
|
||||
~JIT();
|
||||
|
@ -120,6 +120,28 @@ void JITMemoryManager::endFunctionBody(unsigned char *FunctionEnd) {
|
||||
// JIT lazy compilation code.
|
||||
//
|
||||
namespace {
|
||||
class JITResolverState {
|
||||
private:
|
||||
/// FunctionToStubMap - Keep track of the stub created for a particular
|
||||
/// function so that we can reuse them if necessary.
|
||||
std::map<Function*, void*> FunctionToStubMap;
|
||||
|
||||
/// StubToFunctionMap - Keep track of the function that each stub
|
||||
/// corresponds to.
|
||||
std::map<void*, Function*> StubToFunctionMap;
|
||||
|
||||
public:
|
||||
std::map<Function*, void*>& getFunctionToStubMap(const MutexGuard& locked) {
|
||||
assert(locked.holds(TheJIT->lock));
|
||||
return FunctionToStubMap;
|
||||
}
|
||||
|
||||
std::map<void*, Function*>& getStubToFunctionMap(const MutexGuard& locked) {
|
||||
assert(locked.holds(TheJIT->lock));
|
||||
return StubToFunctionMap;
|
||||
}
|
||||
};
|
||||
|
||||
/// JITResolver - Keep track of, and resolve, call sites for functions that
|
||||
/// have not yet been compiled.
|
||||
class JITResolver {
|
||||
@ -130,13 +152,7 @@ namespace {
|
||||
/// rewrite instructions to use.
|
||||
TargetJITInfo::LazyResolverFn LazyResolverFn;
|
||||
|
||||
// FunctionToStubMap - Keep track of the stub created for a particular
|
||||
// function so that we can reuse them if necessary.
|
||||
std::map<Function*, void*> FunctionToStubMap;
|
||||
|
||||
// StubToFunctionMap - Keep track of the function that each stub corresponds
|
||||
// to.
|
||||
std::map<void*, Function*> StubToFunctionMap;
|
||||
JITResolverState state;
|
||||
|
||||
/// ExternalFnToStubMap - This is the equivalent of FunctionToStubMap for
|
||||
/// external functions.
|
||||
@ -159,8 +175,9 @@ namespace {
|
||||
/// instruction without the use of a stub, record the location of the use so
|
||||
/// we know which function is being used at the location.
|
||||
void *AddCallbackAtLocation(Function *F, void *Location) {
|
||||
MutexGuard locked(TheJIT->lock);
|
||||
/// Get the target-specific JIT resolver function.
|
||||
StubToFunctionMap[Location] = F;
|
||||
state.getStubToFunctionMap(locked)[Location] = F;
|
||||
return (void*)LazyResolverFn;
|
||||
}
|
||||
|
||||
@ -181,8 +198,10 @@ static JITResolver &getJITResolver(MachineCodeEmitter *MCE = 0) {
|
||||
/// getFunctionStub - This returns a pointer to a function stub, creating
|
||||
/// one on demand as needed.
|
||||
void *JITResolver::getFunctionStub(Function *F) {
|
||||
MutexGuard locked(TheJIT->lock);
|
||||
|
||||
// If we already have a stub for this function, recycle it.
|
||||
void *&Stub = FunctionToStubMap[F];
|
||||
void *&Stub = state.getFunctionToStubMap(locked)[F];
|
||||
if (Stub) return Stub;
|
||||
|
||||
// Call the lazy resolver function unless we already KNOW it is an external
|
||||
@ -207,7 +226,7 @@ void *JITResolver::getFunctionStub(Function *F) {
|
||||
|
||||
// Finally, keep track of the stub-to-Function mapping so that the
|
||||
// JITCompilerFn knows which function to compile!
|
||||
StubToFunctionMap[Stub] = F;
|
||||
state.getStubToFunctionMap(locked)[Stub] = F;
|
||||
return Stub;
|
||||
}
|
||||
|
||||
@ -231,16 +250,21 @@ void *JITResolver::getExternalFunctionStub(void *FnAddr) {
|
||||
void *JITResolver::JITCompilerFn(void *Stub) {
|
||||
JITResolver &JR = getJITResolver();
|
||||
|
||||
MutexGuard locked(TheJIT->lock);
|
||||
|
||||
// The address given to us for the stub may not be exactly right, it might be
|
||||
// a little bit after the stub. As such, use upper_bound to find it.
|
||||
std::map<void*, Function*>::iterator I =
|
||||
JR.StubToFunctionMap.upper_bound(Stub);
|
||||
assert(I != JR.StubToFunctionMap.begin() && "This is not a known stub!");
|
||||
JR.state.getStubToFunctionMap(locked).upper_bound(Stub);
|
||||
assert(I != JR.state.getStubToFunctionMap(locked).begin() && "This is not a known stub!");
|
||||
Function *F = (--I)->second;
|
||||
|
||||
// The target function will rewrite the stub so that the compilation callback
|
||||
// function is no longer called from this stub.
|
||||
JR.StubToFunctionMap.erase(I);
|
||||
// We might like to remove the stub from the StubToFunction map.
|
||||
// We can't do that! Multiple threads could be stuck, waiting to acquire the
|
||||
// lock above. As soon as the 1st function finishes compiling the function,
|
||||
// the next one will be released, and needs to be able to find the function it needs
|
||||
// to call.
|
||||
//JR.state.getStubToFunctionMap(locked).erase(I);
|
||||
|
||||
DEBUG(std::cerr << "JIT: Lazily resolving function '" << F->getName()
|
||||
<< "' In stub ptr = " << Stub << " actual ptr = "
|
||||
@ -249,7 +273,7 @@ void *JITResolver::JITCompilerFn(void *Stub) {
|
||||
void *Result = TheJIT->getPointerToFunction(F);
|
||||
|
||||
// We don't need to reuse this stub in the future, as F is now compiled.
|
||||
JR.FunctionToStubMap.erase(F);
|
||||
JR.state.getFunctionToStubMap(locked).erase(F);
|
||||
|
||||
// FIXME: We could rewrite all references to this stub if we knew them.
|
||||
return Result;
|
||||
|
Loading…
Reference in New Issue
Block a user