mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-25 20:59:51 +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===-----------------------------------------------------------------------===
|
||||||
|
|
||||||
dnl Configure header files
|
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/Support/DataTypes.h])
|
||||||
AC_CONFIG_HEADERS([include/llvm/ADT/hash_map])
|
AC_CONFIG_HEADERS([include/llvm/ADT/hash_map])
|
||||||
AC_CONFIG_HEADERS([include/llvm/ADT/hash_set])
|
AC_CONFIG_HEADERS([include/llvm/ADT/hash_set])
|
||||||
AC_CONFIG_HEADERS([include/llvm/Support/ThreadSupport.h])
|
|
||||||
AC_CONFIG_HEADERS([include/llvm/ADT/iterator])
|
AC_CONFIG_HEADERS([include/llvm/ADT/iterator])
|
||||||
|
|
||||||
dnl Configure the makefile's configuration data
|
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/Config/config.h"
|
||||||
|
|
||||||
|
|
||||||
ac_config_headers="$ac_config_headers include/llvm/Support/DataTypes.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_map"
|
||||||
|
|
||||||
ac_config_headers="$ac_config_headers include/llvm/ADT/hash_set"
|
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"
|
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/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_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/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" ;;
|
"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:$LINENO: error: invalid argument: $ac_config_target" >&5
|
||||||
echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
|
echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "llvm/Support/MutexGuard.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
@ -33,10 +34,9 @@ class TargetData;
|
|||||||
class Type;
|
class Type;
|
||||||
class IntrinsicLowering;
|
class IntrinsicLowering;
|
||||||
|
|
||||||
class ExecutionEngine {
|
|
||||||
Module &CurMod;
|
|
||||||
const TargetData *TD;
|
|
||||||
|
|
||||||
|
class ExecutionEngineState {
|
||||||
|
private:
|
||||||
/// GlobalAddressMap - A mapping between LLVM global values and their
|
/// GlobalAddressMap - A mapping between LLVM global values and their
|
||||||
/// actualized version...
|
/// actualized version...
|
||||||
std::map<const GlobalValue*, void *> GlobalAddressMap;
|
std::map<const GlobalValue*, void *> GlobalAddressMap;
|
||||||
@ -46,6 +46,24 @@ class ExecutionEngine {
|
|||||||
/// at the address. This map is not computed unless getGlobalValueAtAddress
|
/// at the address. This map is not computed unless getGlobalValueAtAddress
|
||||||
/// is called at some point.
|
/// is called at some point.
|
||||||
std::map<void *, const GlobalValue*> GlobalAddressReverseMap;
|
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:
|
protected:
|
||||||
ModuleProvider *MP;
|
ModuleProvider *MP;
|
||||||
|
|
||||||
@ -54,6 +72,10 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
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(ModuleProvider *P);
|
||||||
ExecutionEngine(Module *M);
|
ExecutionEngine(Module *M);
|
||||||
virtual ~ExecutionEngine();
|
virtual ~ExecutionEngine();
|
||||||
@ -81,13 +103,15 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
void addGlobalMapping(const GlobalValue *GV, void *Addr) {
|
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!");
|
assert((CurVal == 0 || Addr == 0) && "GlobalMapping already established!");
|
||||||
CurVal = Addr;
|
CurVal = Addr;
|
||||||
|
|
||||||
// If we are using the reverse mapping, add it too
|
// If we are using the reverse mapping, add it too
|
||||||
if (!GlobalAddressReverseMap.empty()) {
|
if (!state.getGlobalAddressReverseMap(locked).empty()) {
|
||||||
const GlobalValue *&V = GlobalAddressReverseMap[Addr];
|
const GlobalValue *&V = state.getGlobalAddressReverseMap(locked)[Addr];
|
||||||
assert((V == 0 || GV == 0) && "GlobalMapping already established!");
|
assert((V == 0 || GV == 0) && "GlobalMapping already established!");
|
||||||
V = GV;
|
V = GV;
|
||||||
}
|
}
|
||||||
@ -96,21 +120,25 @@ public:
|
|||||||
/// clearAllGlobalMappings - Clear all global mappings and start over again
|
/// clearAllGlobalMappings - Clear all global mappings and start over again
|
||||||
/// use in dynamic compilation scenarios when you want to move globals
|
/// use in dynamic compilation scenarios when you want to move globals
|
||||||
void clearAllGlobalMappings() {
|
void clearAllGlobalMappings() {
|
||||||
GlobalAddressMap.clear();
|
MutexGuard locked(lock);
|
||||||
GlobalAddressReverseMap.clear();
|
|
||||||
|
state.getGlobalAddressMap(locked).clear();
|
||||||
|
state.getGlobalAddressReverseMap(locked).clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// updateGlobalMapping - Replace an existing mapping for GV with a new
|
/// updateGlobalMapping - Replace an existing mapping for GV with a new
|
||||||
/// address. This updates both maps as required.
|
/// address. This updates both maps as required.
|
||||||
void updateGlobalMapping(const GlobalValue *GV, void *Addr) {
|
void updateGlobalMapping(const GlobalValue *GV, void *Addr) {
|
||||||
void *&CurVal = GlobalAddressMap[GV];
|
MutexGuard locked(lock);
|
||||||
if (CurVal && !GlobalAddressReverseMap.empty())
|
|
||||||
GlobalAddressReverseMap.erase(CurVal);
|
void *&CurVal = state.getGlobalAddressMap(locked)[GV];
|
||||||
|
if (CurVal && !state.getGlobalAddressReverseMap(locked).empty())
|
||||||
|
state.getGlobalAddressReverseMap(locked).erase(CurVal);
|
||||||
CurVal = Addr;
|
CurVal = Addr;
|
||||||
|
|
||||||
// If we are using the reverse mapping, add it too
|
// If we are using the reverse mapping, add it too
|
||||||
if (!GlobalAddressReverseMap.empty()) {
|
if (!state.getGlobalAddressReverseMap(locked).empty()) {
|
||||||
const GlobalValue *&V = GlobalAddressReverseMap[Addr];
|
const GlobalValue *&V = state.getGlobalAddressReverseMap(locked)[Addr];
|
||||||
assert((V == 0 || GV == 0) && "GlobalMapping already established!");
|
assert((V == 0 || GV == 0) && "GlobalMapping already established!");
|
||||||
V = GV;
|
V = GV;
|
||||||
}
|
}
|
||||||
@ -120,8 +148,10 @@ public:
|
|||||||
/// global value if it is available, otherwise it returns null.
|
/// global value if it is available, otherwise it returns null.
|
||||||
///
|
///
|
||||||
void *getPointerToGlobalIfAvailable(const GlobalValue *GV) {
|
void *getPointerToGlobalIfAvailable(const GlobalValue *GV) {
|
||||||
std::map<const GlobalValue*, void*>::iterator I = GlobalAddressMap.find(GV);
|
MutexGuard locked(lock);
|
||||||
return I != GlobalAddressMap.end() ? I->second : 0;
|
|
||||||
|
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
|
/// 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
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -7,36 +7,35 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
//
|
//
|
||||||
// This file defines platform-agnostic interfaces that can be used to write
|
// This file defines a guard for a block of code that ensures a Mutex is locked
|
||||||
// multi-threaded programs. Autoconf is used to chose the correct
|
// upon construction and released upon destruction.
|
||||||
// implementation of these interfaces, or default to a non-thread-capable system
|
|
||||||
// if no matching system support is available.
|
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#ifndef LLVM_SUPPORT_THREADSUPPORT_H
|
#ifndef LLVM_SUPPORT_MUTEXGUARD_H
|
||||||
#define LLVM_SUPPORT_THREADSUPPORT_H
|
#define LLVM_SUPPORT_MUTEXGUARD_H
|
||||||
|
|
||||||
#undef HAVE_PTHREAD_MUTEX_LOCK
|
#include <llvm/System/Mutex.h>
|
||||||
|
|
||||||
#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 {
|
namespace llvm {
|
||||||
/// MutexLocker - Instances of this class acquire a given Lock when
|
/// Instances of this class acquire a given Mutex Lock when constructed and
|
||||||
/// constructed and hold that lock until destruction.
|
/// 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++
|
||||||
class MutexLocker {
|
/// destruction of the object will always release the Mutex and thus avoid
|
||||||
Mutex &M;
|
/// a host of nasty multi-threading problems in the face of exceptions, etc.
|
||||||
MutexLocker(const MutexLocker &); // DO NOT IMPLEMENT
|
/// @brief Guard a section of code with a Mutex.
|
||||||
void operator=(const MutexLocker &); // DO NOT IMPLEMENT
|
class MutexGuard {
|
||||||
|
sys::Mutex &M;
|
||||||
|
MutexGuard(const MutexGuard &); // DO NOT IMPLEMENT
|
||||||
|
void operator=(const MutexGuard &); // DO NOT IMPLEMENT
|
||||||
public:
|
public:
|
||||||
MutexLocker(Mutex &m) : M(m) { M.acquire(); }
|
MutexGuard(sys::Mutex &m) : M(m) { M.acquire(); }
|
||||||
~MutexLocker() { M.release(); }
|
~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.
|
/// at the specified address.
|
||||||
///
|
///
|
||||||
const GlobalValue *ExecutionEngine::getGlobalValueAtAddress(void *Addr) {
|
const GlobalValue *ExecutionEngine::getGlobalValueAtAddress(void *Addr) {
|
||||||
|
MutexGuard locked(lock);
|
||||||
|
|
||||||
// If we haven't computed the reverse mapping yet, do so first.
|
// 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 =
|
for (std::map<const GlobalValue*, void *>::iterator I =
|
||||||
GlobalAddressMap.begin(), E = GlobalAddressMap.end(); I != E; ++I)
|
state.getGlobalAddressMap(locked).begin(), E = state.getGlobalAddressMap(locked).end(); I != E; ++I)
|
||||||
GlobalAddressReverseMap.insert(std::make_pair(I->second, I->first));
|
state.getGlobalAddressReverseMap(locked).insert(std::make_pair(I->second, I->first));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<void *, const GlobalValue*>::iterator I =
|
std::map<void *, const GlobalValue*>::iterator I =
|
||||||
GlobalAddressReverseMap.find(Addr);
|
state.getGlobalAddressReverseMap(locked).find(Addr);
|
||||||
return I != GlobalAddressReverseMap.end() ? I->second : 0;
|
return I != state.getGlobalAddressReverseMap(locked).end() ? I->second : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateArgv - Turn a vector of strings into a nice argv style array of
|
// 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)))
|
if (Function *F = const_cast<Function*>(dyn_cast<Function>(GV)))
|
||||||
return getPointerToFunction(F);
|
return getPointerToFunction(F);
|
||||||
|
|
||||||
assert(GlobalAddressMap[GV] && "Global hasn't had an address allocated yet?");
|
MutexGuard locked(lock);
|
||||||
return GlobalAddressMap[GV];
|
assert(state.getGlobalAddressMap(locked)[GV] && "Global hasn't had an address allocated yet?");
|
||||||
|
return state.getGlobalAddressMap(locked)[GV];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FIXME: document
|
/// FIXME: document
|
||||||
|
@ -30,13 +30,15 @@
|
|||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
JIT::JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji)
|
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());
|
setTargetData(TM.getTargetData());
|
||||||
|
|
||||||
// Initialize MCE
|
// Initialize MCE
|
||||||
MCE = createEmitter(*this);
|
MCE = createEmitter(*this);
|
||||||
|
|
||||||
// Add target data
|
// Add target data
|
||||||
|
MutexGuard locked(lock);
|
||||||
|
FunctionPassManager& PM = state.getPM(locked);
|
||||||
PM.add(new TargetData(TM.getTargetData()));
|
PM.add(new TargetData(TM.getTargetData()));
|
||||||
|
|
||||||
// Compile LLVM Code down to machine code in the intermediate representation
|
// 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) {
|
void JIT::runJITOnFunction(Function *F) {
|
||||||
static bool isAlreadyCodeGenerating = false;
|
static bool isAlreadyCodeGenerating = false;
|
||||||
assert(!isAlreadyCodeGenerating && "Error: Recursive compilation detected!");
|
assert(!isAlreadyCodeGenerating && "Error: Recursive compilation detected!");
|
||||||
|
|
||||||
|
MutexGuard locked(lock);
|
||||||
|
|
||||||
// JIT the function
|
// JIT the function
|
||||||
isAlreadyCodeGenerating = true;
|
isAlreadyCodeGenerating = true;
|
||||||
PM.run(*F);
|
state.getPM(locked).run(*F);
|
||||||
isAlreadyCodeGenerating = false;
|
isAlreadyCodeGenerating = false;
|
||||||
|
|
||||||
// If the function referred to a global variable that had not yet been
|
// 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
|
// emitted, it allocates memory for the global, but doesn't emit it yet. Emit
|
||||||
// all of these globals now.
|
// all of these globals now.
|
||||||
while (!PendingGlobals.empty()) {
|
while (!state.getPendingGlobals(locked).empty()) {
|
||||||
const GlobalVariable *GV = PendingGlobals.back();
|
const GlobalVariable *GV = state.getPendingGlobals(locked).back();
|
||||||
PendingGlobals.pop_back();
|
state.getPendingGlobals(locked).pop_back();
|
||||||
EmitGlobalVariable(GV);
|
EmitGlobalVariable(GV);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,6 +240,8 @@ void JIT::runJITOnFunction(Function *F) {
|
|||||||
/// specified function, compiling it if neccesary.
|
/// specified function, compiling it if neccesary.
|
||||||
///
|
///
|
||||||
void *JIT::getPointerToFunction(Function *F) {
|
void *JIT::getPointerToFunction(Function *F) {
|
||||||
|
MutexGuard locked(lock);
|
||||||
|
|
||||||
if (void *Addr = getPointerToGlobalIfAvailable(F))
|
if (void *Addr = getPointerToGlobalIfAvailable(F))
|
||||||
return Addr; // Check if function already code gen'd
|
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
|
/// variable, possibly emitting it to memory if needed. This is used by the
|
||||||
/// Emitter.
|
/// Emitter.
|
||||||
void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
|
void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
|
||||||
|
MutexGuard locked(lock);
|
||||||
|
|
||||||
void *Ptr = getPointerToGlobalIfAvailable(GV);
|
void *Ptr = getPointerToGlobalIfAvailable(GV);
|
||||||
if (Ptr) return Ptr;
|
if (Ptr) return Ptr;
|
||||||
|
|
||||||
@ -287,7 +295,7 @@ void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
|
|||||||
// compilation.
|
// compilation.
|
||||||
uint64_t S = getTargetData().getTypeSize(GV->getType()->getElementType());
|
uint64_t S = getTargetData().getTypeSize(GV->getType()->getElementType());
|
||||||
Ptr = new char[(size_t)S];
|
Ptr = new char[(size_t)S];
|
||||||
PendingGlobals.push_back(GV);
|
state.getPendingGlobals(locked).push_back(GV);
|
||||||
}
|
}
|
||||||
addGlobalMapping(GV, Ptr);
|
addGlobalMapping(GV, Ptr);
|
||||||
return Ptr;
|
return Ptr;
|
||||||
|
@ -27,18 +27,35 @@ class TargetMachine;
|
|||||||
class TargetJITInfo;
|
class TargetJITInfo;
|
||||||
class MachineCodeEmitter;
|
class MachineCodeEmitter;
|
||||||
|
|
||||||
class JIT : public ExecutionEngine {
|
class JITState {
|
||||||
TargetMachine &TM; // The current target we are compiling to
|
private:
|
||||||
TargetJITInfo &TJI; // The JITInfo for the target we are compiling to
|
|
||||||
|
|
||||||
FunctionPassManager PM; // Passes to compile a function
|
FunctionPassManager PM; // Passes to compile a function
|
||||||
MachineCodeEmitter *MCE; // MCE object
|
|
||||||
|
|
||||||
/// PendingGlobals - Global variables which have had memory allocated for them
|
/// PendingGlobals - Global variables which have had memory allocated for them
|
||||||
/// while a function was code generated, but which have not been initialized
|
/// while a function was code generated, but which have not been initialized
|
||||||
/// yet.
|
/// yet.
|
||||||
std::vector<const GlobalVariable*> PendingGlobals;
|
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);
|
JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji);
|
||||||
public:
|
public:
|
||||||
~JIT();
|
~JIT();
|
||||||
|
@ -120,6 +120,28 @@ void JITMemoryManager::endFunctionBody(unsigned char *FunctionEnd) {
|
|||||||
// JIT lazy compilation code.
|
// JIT lazy compilation code.
|
||||||
//
|
//
|
||||||
namespace {
|
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
|
/// JITResolver - Keep track of, and resolve, call sites for functions that
|
||||||
/// have not yet been compiled.
|
/// have not yet been compiled.
|
||||||
class JITResolver {
|
class JITResolver {
|
||||||
@ -130,13 +152,7 @@ namespace {
|
|||||||
/// rewrite instructions to use.
|
/// rewrite instructions to use.
|
||||||
TargetJITInfo::LazyResolverFn LazyResolverFn;
|
TargetJITInfo::LazyResolverFn LazyResolverFn;
|
||||||
|
|
||||||
// FunctionToStubMap - Keep track of the stub created for a particular
|
JITResolverState state;
|
||||||
// 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;
|
|
||||||
|
|
||||||
/// ExternalFnToStubMap - This is the equivalent of FunctionToStubMap for
|
/// ExternalFnToStubMap - This is the equivalent of FunctionToStubMap for
|
||||||
/// external functions.
|
/// external functions.
|
||||||
@ -159,8 +175,9 @@ namespace {
|
|||||||
/// instruction without the use of a stub, record the location of the use so
|
/// instruction without the use of a stub, record the location of the use so
|
||||||
/// we know which function is being used at the location.
|
/// we know which function is being used at the location.
|
||||||
void *AddCallbackAtLocation(Function *F, void *Location) {
|
void *AddCallbackAtLocation(Function *F, void *Location) {
|
||||||
|
MutexGuard locked(TheJIT->lock);
|
||||||
/// Get the target-specific JIT resolver function.
|
/// Get the target-specific JIT resolver function.
|
||||||
StubToFunctionMap[Location] = F;
|
state.getStubToFunctionMap(locked)[Location] = F;
|
||||||
return (void*)LazyResolverFn;
|
return (void*)LazyResolverFn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,8 +198,10 @@ static JITResolver &getJITResolver(MachineCodeEmitter *MCE = 0) {
|
|||||||
/// getFunctionStub - This returns a pointer to a function stub, creating
|
/// getFunctionStub - This returns a pointer to a function stub, creating
|
||||||
/// one on demand as needed.
|
/// one on demand as needed.
|
||||||
void *JITResolver::getFunctionStub(Function *F) {
|
void *JITResolver::getFunctionStub(Function *F) {
|
||||||
|
MutexGuard locked(TheJIT->lock);
|
||||||
|
|
||||||
// If we already have a stub for this function, recycle it.
|
// 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;
|
if (Stub) return Stub;
|
||||||
|
|
||||||
// Call the lazy resolver function unless we already KNOW it is an external
|
// 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
|
// Finally, keep track of the stub-to-Function mapping so that the
|
||||||
// JITCompilerFn knows which function to compile!
|
// JITCompilerFn knows which function to compile!
|
||||||
StubToFunctionMap[Stub] = F;
|
state.getStubToFunctionMap(locked)[Stub] = F;
|
||||||
return Stub;
|
return Stub;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,16 +250,21 @@ void *JITResolver::getExternalFunctionStub(void *FnAddr) {
|
|||||||
void *JITResolver::JITCompilerFn(void *Stub) {
|
void *JITResolver::JITCompilerFn(void *Stub) {
|
||||||
JITResolver &JR = getJITResolver();
|
JITResolver &JR = getJITResolver();
|
||||||
|
|
||||||
|
MutexGuard locked(TheJIT->lock);
|
||||||
|
|
||||||
// The address given to us for the stub may not be exactly right, it might be
|
// 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.
|
// a little bit after the stub. As such, use upper_bound to find it.
|
||||||
std::map<void*, Function*>::iterator I =
|
std::map<void*, Function*>::iterator I =
|
||||||
JR.StubToFunctionMap.upper_bound(Stub);
|
JR.state.getStubToFunctionMap(locked).upper_bound(Stub);
|
||||||
assert(I != JR.StubToFunctionMap.begin() && "This is not a known stub!");
|
assert(I != JR.state.getStubToFunctionMap(locked).begin() && "This is not a known stub!");
|
||||||
Function *F = (--I)->second;
|
Function *F = (--I)->second;
|
||||||
|
|
||||||
// The target function will rewrite the stub so that the compilation callback
|
// We might like to remove the stub from the StubToFunction map.
|
||||||
// function is no longer called from this stub.
|
// We can't do that! Multiple threads could be stuck, waiting to acquire the
|
||||||
JR.StubToFunctionMap.erase(I);
|
// 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()
|
DEBUG(std::cerr << "JIT: Lazily resolving function '" << F->getName()
|
||||||
<< "' In stub ptr = " << Stub << " actual ptr = "
|
<< "' In stub ptr = " << Stub << " actual ptr = "
|
||||||
@ -249,7 +273,7 @@ void *JITResolver::JITCompilerFn(void *Stub) {
|
|||||||
void *Result = TheJIT->getPointerToFunction(F);
|
void *Result = TheJIT->getPointerToFunction(F);
|
||||||
|
|
||||||
// We don't need to reuse this stub in the future, as F is now compiled.
|
// 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.
|
// FIXME: We could rewrite all references to this stub if we knew them.
|
||||||
return Result;
|
return Result;
|
||||||
|
Loading…
Reference in New Issue
Block a user