2012-09-05 13:37:39 +04:00
//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author: Axel Naumann <axel@cern.ch>
2014-01-07 14:08:37 +04:00
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
2012-09-05 13:37:39 +04:00
//------------------------------------------------------------------------------
2014-02-19 15:49:24 +04:00
# include "IncrementalExecutor.h"
2012-09-05 13:37:39 +04:00
2014-05-26 18:33:43 +04:00
# include "cling/Interpreter/Value.h"
2013-04-24 20:28:08 +04:00
# include "llvm/IR/Constants.h"
2014-03-15 02:11:09 +04:00
# include "llvm/IR/Instructions.h"
2013-11-01 21:31:18 +04:00
# include "llvm/IR/LLVMContext.h"
2013-04-24 20:28:08 +04:00
# include "llvm/IR/Module.h"
2012-09-05 13:37:39 +04:00
# include "llvm/PassManager.h"
2012-11-17 20:28:14 +04:00
# include "llvm/ADT/SmallPtrSet.h"
2013-02-22 19:59:54 +04:00
# include "llvm/ExecutionEngine/GenericValue.h"
2012-09-05 13:37:39 +04:00
# include "llvm/ExecutionEngine/JIT.h"
# include "llvm/Support/raw_ostream.h"
# include "llvm/Support/DynamicLibrary.h"
2014-04-28 14:32:12 +04:00
namespace {
// From boost/detail/sp_counted_base.hpp.
// JIT cannot handle inline asm, thus compile these symbols and
// inject them when needed.
static int boost__detail__atomic_exchange_and_add ( int * pw , int dv )
{
// int r = *pw;
// *pw += dv;
// return r;
2014-04-28 17:08:03 +04:00
# if defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
2014-04-28 14:32:12 +04:00
int r ;
__asm__ __volatile__
(
" lock \n \t "
" xadd %1, %0 " :
" =m " ( * pw ) , " =r " ( r ) : // outputs (%0, %1)
" m " ( * pw ) , " 1 " ( dv ) : // inputs (%2, %3 == %1)
" memory " , " cc " // clobbers
) ;
# else
int r = * pw ;
* pw + = dv ;
# endif
return r ;
}
}
2014-03-07 18:09:02 +04:00
using namespace llvm ;
namespace cling {
2012-09-05 13:37:39 +04:00
2014-02-19 15:49:24 +04:00
std : : set < std : : string > IncrementalExecutor : : m_unresolvedSymbols ;
std : : vector < IncrementalExecutor : : LazyFunctionCreatorFunc_t >
IncrementalExecutor : : m_lazyFuncCreator ;
2012-09-05 13:37:39 +04:00
2012-11-17 16:09:08 +04:00
// Keep in source: OwningPtr<ExecutionEngine> needs #include ExecutionEngine
2014-02-28 20:30:56 +04:00
IncrementalExecutor : : IncrementalExecutor ( llvm : : Module * m )
2014-04-28 14:32:12 +04:00
{
2013-06-25 11:21:14 +04:00
assert ( m & & " llvm::Module must not be null! " ) ;
2013-09-19 13:24:31 +04:00
m_AtExitFuncs . reserve ( 256 ) ;
2014-02-28 20:30:56 +04:00
2014-04-28 17:50:02 +04:00
// Rewrire __cxa_atexit to ~Interpreter(), thus also global destruction
// coming from the JIT.
m_SymbolsToRemap [ " __cxa_atexit " ]
= std : : make_pair ( ( void * ) 0 , std : : string ( " cling_cxa_atexit " ) ) ;
// Helper to cast a function pointer to a void*:
typedef int ( * p2tfunc_t ) ( ) ;
union {
p2tfunc_t m_func ;
void * m_ptr ;
} p2f ;
// Provide a symbol to common boost functions using inline asm such that the
// JIT does not need to compile it (and fail doing it due to inline asm).
p2f . m_func = ( p2tfunc_t ) & boost__detail__atomic_exchange_and_add ;
m_SymbolsToRemap [ " _ZN5boost6detail23atomic_exchange_and_addEPii " ]
= std : : make_pair ( ( void * ) p2f . m_ptr , std : : string ( ) ) ;
2014-02-28 20:30:56 +04:00
//
// Create an execution engine to use.
//
assert ( m & & " Module cannot be null " ) ;
// Note: Engine takes ownership of the module.
llvm : : EngineBuilder builder ( m ) ;
std : : string errMsg ;
builder . setErrorStr ( & errMsg ) ;
builder . setOptLevel ( llvm : : CodeGenOpt : : Less ) ;
builder . setEngineKind ( llvm : : EngineKind : : JIT ) ;
builder . setAllocateGVsWithCode ( false ) ;
// EngineBuilder uses default c'ted TargetOptions, too:
llvm : : TargetOptions TargetOpts ;
TargetOpts . NoFramePointerElim = 1 ;
TargetOpts . JITEmitDebugInfo = 1 ;
builder . setTargetOptions ( TargetOpts ) ;
m_engine . reset ( builder . create ( ) ) ;
if ( ! m_engine )
llvm : : errs ( ) < < " cling::IncrementalExecutor::IncrementalExecutor(): "
< < errMsg ;
assert ( m_engine & & " Cannot create module! " ) ;
// install lazy function creators
m_engine - > InstallLazyFunctionCreator ( NotifyLazyFunctionCreators ) ;
2013-06-25 11:21:14 +04:00
}
2012-11-17 16:09:08 +04:00
// Keep in source: ~OwningPtr<ExecutionEngine> needs #include ExecutionEngine
2014-02-19 15:49:24 +04:00
IncrementalExecutor : : ~ IncrementalExecutor ( ) { }
2013-10-03 18:58:48 +04:00
2014-02-19 15:49:24 +04:00
void IncrementalExecutor : : shuttingDown ( ) {
2013-09-19 13:24:31 +04:00
for ( size_t I = 0 , N = m_AtExitFuncs . size ( ) ; I < N ; + + I ) {
const CXAAtExitElement & AEE = m_AtExitFuncs [ N - I - 1 ] ;
( * AEE . m_Func ) ( AEE . m_Arg ) ;
}
}
2012-09-05 13:37:39 +04:00
2014-04-28 14:32:12 +04:00
void IncrementalExecutor : : remapSymbols ( ) {
// Note: iteration of ++remapI happens in the body due to invalidation
// of the erased iterator!
for ( auto remapI = std : : begin ( m_SymbolsToRemap ) ,
remapE = std : : end ( m_SymbolsToRemap ) ;
remapI ! = remapE ; ) {
// The function for which the symbol address will be replaced
llvm : : Function * origFunc
= m_engine - > FindFunctionNamed ( remapI - > first . c_str ( ) ) ;
if ( ! origFunc ) {
// Go to next element.
+ + remapI ;
continue ;
}
2013-10-31 02:40:00 +04:00
2014-04-28 14:32:12 +04:00
// The new symbol address, which might be NULL to signal a symbol
// lookup is required
void * replaceAddr = remapI - > second . first ;
if ( ! replaceAddr ) {
// A symbol lookup is required to find the replacement address.
llvm : : Function * interpFunc
= m_engine - > FindFunctionNamed ( remapI - > second . second . c_str ( ) ) ;
assert ( interpFunc & & " replacement function must exist. " ) ;
// Generate the symbol and get its address
replaceAddr = m_engine - > getPointerToFunction ( interpFunc ) ;
}
assert ( replaceAddr & & " cannot find replacement symbol " ) ;
// Replace the mapping of function symbol to new address
m_engine - > updateGlobalMapping ( origFunc , replaceAddr ) ;
// Note that the current entry was successfully remapped.
// Save the current so we can erase it *after* the iterator increment
// or we would increment an invalid iterator.
auto remapErase = remapI ;
+ + remapI ;
m_SymbolsToRemap . erase ( remapErase ) ;
}
2013-10-31 02:40:00 +04:00
}
2014-03-04 21:07:03 +04:00
void IncrementalExecutor : : AddAtExitFunc ( void ( * func ) ( void * ) , void * arg ,
2014-03-05 12:34:03 +04:00
const cling : : Transaction * T ) {
2013-09-19 13:24:31 +04:00
// Register a CXAAtExit function
2014-03-04 21:07:03 +04:00
m_AtExitFuncs . push_back ( CXAAtExitElement ( func , arg , T ) ) ;
2013-09-19 13:24:31 +04:00
}
2012-09-05 13:37:39 +04:00
void unresolvedSymbol ( )
{
// throw exception?
2014-02-19 15:49:24 +04:00
llvm : : errs ( ) < < " IncrementalExecutor: calling unresolved symbol, "
2012-11-17 20:28:14 +04:00
" see previous error message! \n " ;
2012-09-05 13:37:39 +04:00
}
2014-02-19 15:49:24 +04:00
void * IncrementalExecutor : : HandleMissingFunction ( const std : : string & mangled_name )
2012-09-05 13:37:39 +04:00
{
// Not found in the map, add the symbol in the list of unresolved symbols
2012-10-07 15:53:16 +04:00
if ( m_unresolvedSymbols . insert ( mangled_name ) . second ) {
2014-02-19 15:49:24 +04:00
llvm : : errs ( ) < < " IncrementalExecutor: use of undefined symbol ' "
2012-10-07 15:53:16 +04:00
< < mangled_name < < " '! \n " ;
}
2012-09-05 13:37:39 +04:00
// Avoid "ISO C++ forbids casting between pointer-to-function and
// pointer-to-object":
return ( void * ) reinterpret_cast < size_t > ( unresolvedSymbol ) ;
}
void *
2014-02-19 15:49:24 +04:00
IncrementalExecutor : : NotifyLazyFunctionCreators ( const std : : string & mangled_name )
2012-09-05 13:37:39 +04:00
{
for ( std : : vector < LazyFunctionCreatorFunc_t > : : iterator it
= m_lazyFuncCreator . begin ( ) , et = m_lazyFuncCreator . end ( ) ;
it ! = et ; + + it ) {
void * ret = ( void * ) ( ( LazyFunctionCreatorFunc_t ) * it ) ( mangled_name ) ;
2014-02-28 20:23:09 +04:00
if ( ret )
2012-10-25 16:58:50 +04:00
return ret ;
2012-09-05 13:37:39 +04:00
}
2012-10-25 16:58:50 +04:00
2012-09-05 13:37:39 +04:00
return HandleMissingFunction ( mangled_name ) ;
}
2012-11-17 20:28:14 +04:00
static void
freeCallersOfUnresolvedSymbols ( llvm : : SmallVectorImpl < llvm : : Function * > &
funcsToFree , llvm : : ExecutionEngine * engine ) {
llvm : : SmallPtrSet < llvm : : Function * , 40 > funcsToFreeUnique ;
for ( size_t i = 0 ; i < funcsToFree . size ( ) ; + + i ) {
llvm : : Function * func = funcsToFree [ i ] ;
2013-10-02 11:24:32 +04:00
assert ( func & & " Cannot free NULL function " ) ;
2012-11-17 20:28:14 +04:00
if ( funcsToFreeUnique . insert ( func ) ) {
for ( llvm : : Value : : use_iterator IU = func - > use_begin ( ) ,
EU = func - > use_end ( ) ; IU ! = EU ; + + IU ) {
llvm : : Instruction * instUser = llvm : : dyn_cast < llvm : : Instruction > ( * IU ) ;
if ( ! instUser ) continue ;
if ( ! instUser - > getParent ( ) ) continue ;
if ( llvm : : Function * userFunc = instUser - > getParent ( ) - > getParent ( ) )
funcsToFree . push_back ( userFunc ) ;
}
}
}
for ( llvm : : SmallPtrSet < llvm : : Function * , 40 > : : iterator
I = funcsToFreeUnique . begin ( ) , E = funcsToFreeUnique . end ( ) ;
I ! = E ; + + I ) {
// This should force the JIT to recompile the function. But the stubs stay,
// and the JIT reuses the stubs now pointing nowhere, i.e. without updating
// the machine code address. Fix the JIT, or hope that MCJIT helps.
//engine->freeMachineCodeForFunction(*I);
engine - > updateGlobalMapping ( * I , 0 ) ;
}
}
2014-02-19 15:49:24 +04:00
IncrementalExecutor : : ExecutionResult
IncrementalExecutor : : executeFunction ( llvm : : StringRef funcname ,
2014-02-27 01:37:16 +04:00
Value * returnValue ) {
2012-09-05 13:37:39 +04:00
// Call a function without arguments, or with an SRet argument, see SRet below
// We don't care whether something was unresolved before.
m_unresolvedSymbols . clear ( ) ;
2014-05-26 18:33:43 +04:00
// Set the value to cling::invalid.
if ( returnValue ) {
* returnValue = Value ( ) ;
}
2014-04-28 14:32:12 +04:00
remapSymbols ( ) ;
2014-03-04 21:15:14 +04:00
2012-11-17 20:28:14 +04:00
llvm : : Function * f = m_engine - > FindFunctionNamed ( funcname . str ( ) . c_str ( ) ) ;
2012-09-05 13:37:39 +04:00
if ( ! f ) {
2014-02-19 15:49:24 +04:00
llvm : : errs ( ) < < " IncrementalExecutor::executeFunction: "
2012-11-17 20:28:14 +04:00
" could not find function named " < < funcname < < ' \n ' ;
2012-11-16 00:55:43 +04:00
return kExeFunctionNotCompiled ;
2012-09-05 13:37:39 +04:00
}
2014-03-12 18:18:04 +04:00
assert ( f - > getFunctionType ( ) - > getNumParams ( ) = = 1
& & ( * f - > getFunctionType ( ) - > param_begin ( ) ) - > isPtrOrPtrVectorTy ( ) & &
" Wrong signature " ) ;
2014-02-13 12:52:31 +04:00
typedef void ( * PromptWrapper_t ) ( void * ) ;
2014-02-19 13:03:04 +04:00
union {
PromptWrapper_t wrapperFunction ;
void * address ;
} p2f ;
p2f . address = m_engine - > getPointerToFunction ( f ) ;
2012-09-05 13:37:39 +04:00
// check if there is any unresolved symbol in the list
if ( ! m_unresolvedSymbols . empty ( ) ) {
2014-03-12 17:49:23 +04:00
llvm : : SmallVector < llvm : : Function * , 128 > funcsToFree ;
2012-09-05 13:37:39 +04:00
for ( std : : set < std : : string > : : const_iterator i = m_unresolvedSymbols . begin ( ) ,
e = m_unresolvedSymbols . end ( ) ; i ! = e ; + + i ) {
2014-02-19 15:49:24 +04:00
llvm : : errs ( ) < < " IncrementalExecutor::executeFunction: symbol ' " < < * i
2012-11-17 20:28:14 +04:00
< < " ' unresolved while linking function ' " < < funcname
< < " '! \n " ;
2012-09-05 13:37:39 +04:00
llvm : : Function * ff = m_engine - > FindFunctionNamed ( i - > c_str ( ) ) ;
2013-10-02 11:24:32 +04:00
// i could also reference a global variable, in which case ff == 0.
if ( ff )
funcsToFree . push_back ( ff ) ;
2012-09-05 13:37:39 +04:00
}
2012-11-17 20:28:14 +04:00
freeCallersOfUnresolvedSymbols ( funcsToFree , m_engine . get ( ) ) ;
2012-09-05 13:37:39 +04:00
m_unresolvedSymbols . clear ( ) ;
2012-11-16 00:55:43 +04:00
return kExeUnresolvedSymbols ;
2012-09-05 13:37:39 +04:00
}
2014-02-19 13:03:04 +04:00
// Run the function
( * p2f . wrapperFunction ) ( returnValue ) ;
2012-09-05 13:37:39 +04:00
2012-11-16 00:55:43 +04:00
return kExeSuccess ;
2012-09-05 13:37:39 +04:00
}
2014-02-19 15:49:24 +04:00
IncrementalExecutor : : ExecutionResult
IncrementalExecutor : : runStaticInitializersOnce ( llvm : : Module * m ) {
2012-09-05 13:37:39 +04:00
assert ( m & & " Module must not be null " ) ;
assert ( m_engine & & " Code generation did not create an engine! " ) ;
2012-11-20 20:24:02 +04:00
llvm : : GlobalVariable * GV
= m - > getGlobalVariable ( " llvm.global_ctors " , true ) ;
// Nothing to do is good, too.
if ( ! GV ) return kExeSuccess ;
// Close similarity to
// m_engine->runStaticConstructorsDestructors(false) aka
// llvm::ExecutionEngine::runStaticConstructorsDestructors()
// is intentional; we do an extra pass to check whether the JIT
// managed to collect all the symbols needed by the niitializers.
// Should be an array of '{ i32, void ()* }' structs. The first value is
// the init priority, which we ignore.
llvm : : ConstantArray * InitList
= llvm : : dyn_cast < llvm : : ConstantArray > ( GV - > getInitializer ( ) ) ;
2014-01-22 18:07:11 +04:00
2014-03-15 02:09:49 +04:00
// We need to delete it here just in case we have recursive inits, otherwise
// it will call inits multiple times.
2014-01-22 18:07:11 +04:00
GV - > eraseFromParent ( ) ;
2012-11-20 20:24:02 +04:00
if ( InitList = = 0 )
return kExeSuccess ;
2012-09-05 13:37:39 +04:00
2012-11-20 20:24:02 +04:00
// We don't care whether something was unresolved before.
m_unresolvedSymbols . clear ( ) ;
2014-03-12 20:58:34 +04:00
SmallVector < Function * , 2 > initFuncs ;
2012-11-20 20:24:02 +04:00
for ( unsigned i = 0 , e = InitList - > getNumOperands ( ) ; i ! = e ; + + i ) {
llvm : : ConstantStruct * CS
= llvm : : dyn_cast < llvm : : ConstantStruct > ( InitList - > getOperand ( i ) ) ;
if ( CS = = 0 ) continue ;
llvm : : Constant * FP = CS - > getOperand ( 1 ) ;
if ( FP - > isNullValue ( ) )
continue ; // Found a sentinal value, ignore.
// Strip off constant expression casts.
if ( llvm : : ConstantExpr * CE = llvm : : dyn_cast < llvm : : ConstantExpr > ( FP ) )
if ( CE - > isCast ( ) )
FP = CE - > getOperand ( 0 ) ;
// Execute the ctor/dtor function!
if ( llvm : : Function * F = llvm : : dyn_cast < llvm : : Function > ( FP ) ) {
2014-04-28 14:32:12 +04:00
remapSymbols ( ) ;
2012-11-20 20:24:02 +04:00
m_engine - > getPointerToFunction ( F ) ;
// check if there is any unresolved symbol in the list
if ( ! m_unresolvedSymbols . empty ( ) ) {
llvm : : SmallVector < llvm : : Function * , 100 > funcsToFree ;
for ( std : : set < std : : string > : : const_iterator i = m_unresolvedSymbols . begin ( ) ,
e = m_unresolvedSymbols . end ( ) ; i ! = e ; + + i ) {
2014-02-19 15:49:24 +04:00
llvm : : errs ( ) < < " IncrementalExecutor::runStaticInitializersOnce: symbol ' " < < * i
2012-11-20 20:24:02 +04:00
< < " ' unresolved while linking static initializer ' "
< < F - > getName ( ) < < " '! \n " ;
llvm : : Function * ff = m_engine - > FindFunctionNamed ( i - > c_str ( ) ) ;
assert ( ff & & " cannot find function to free " ) ;
funcsToFree . push_back ( ff ) ;
}
freeCallersOfUnresolvedSymbols ( funcsToFree , m_engine . get ( ) ) ;
m_unresolvedSymbols . clear ( ) ;
return kExeUnresolvedSymbols ;
}
2014-03-12 02:37:05 +04:00
//executeFunction(F->getName());
m_engine - > runFunction ( F , std : : vector < llvm : : GenericValue > ( ) ) ;
2014-03-12 20:58:34 +04:00
initFuncs . push_back ( F ) ;
2014-03-15 02:11:09 +04:00
if ( F - > getName ( ) . startswith ( " _GLOBAL__I_a " ) ) {
BasicBlock & BB = F - > getEntryBlock ( ) ;
for ( BasicBlock : : iterator I = BB . begin ( ) , E = BB . end ( ) ; I ! = E ; + + I )
if ( CallInst * call = dyn_cast < CallInst > ( I ) )
initFuncs . push_back ( call - > getCalledFunction ( ) ) ;
}
2012-11-20 20:24:02 +04:00
}
2012-09-05 13:37:39 +04:00
}
2012-11-20 20:24:02 +04:00
2014-03-12 20:58:34 +04:00
for ( SmallVector < Function * , 2 > : : iterator I = initFuncs . begin ( ) ,
E = initFuncs . end ( ) ; I ! = E ; + + I ) {
// Cleanup also the dangling init functions. They are in the form:
// define internal void @_GLOBAL__I_aN() section "..."{
// entry:
// call void @__cxx_global_var_init(N-1)()
2014-03-15 02:10:33 +04:00
// call void @__cxx_global_var_initM()
2014-03-12 20:58:34 +04:00
// ret void
// }
//
// define internal void @__cxx_global_var_init(N-1)() section "..." {
// entry:
// call void @_ZN7MyClassC1Ev(%struct.MyClass* @n)
// ret void
// }
// Erase __cxx_global_var_init(N-1)() first.
2014-03-15 02:11:09 +04:00
( * I ) - > removeDeadConstantUsers ( ) ;
2014-03-12 20:58:34 +04:00
( * I ) - > eraseFromParent ( ) ;
}
2012-11-20 20:24:02 +04:00
return kExeSuccess ;
2012-09-05 13:37:39 +04:00
}
2014-02-27 12:53:42 +04:00
void IncrementalExecutor : : runAndRemoveStaticDestructors ( Transaction * T ) {
assert ( T & & " Must be set " ) ;
// Collect all the dtors bound to this transaction.
AtExitFunctions boundToT ;
for ( AtExitFunctions : : iterator I = m_AtExitFuncs . begin ( ) ;
I ! = m_AtExitFuncs . end ( ) ; )
if ( I - > m_FromT = = T ) {
boundToT . push_back ( * I ) ;
I = m_AtExitFuncs . erase ( I ) ;
}
else
+ + I ;
2013-09-19 13:24:31 +04:00
// 'Unload' the cxa_atexit entities.
2014-02-27 12:53:42 +04:00
for ( AtExitFunctions : : reverse_iterator I = boundToT . rbegin ( ) ,
E = boundToT . rend ( ) ; I ! = E ; + + I ) {
2014-02-26 20:00:13 +04:00
const CXAAtExitElement & AEE = * I ;
2013-09-19 13:24:31 +04:00
( * AEE . m_Func ) ( AEE . m_Arg ) ;
}
2012-09-05 13:37:39 +04:00
}
void
2014-02-19 15:49:24 +04:00
IncrementalExecutor : : installLazyFunctionCreator ( LazyFunctionCreatorFunc_t fp )
2012-09-05 13:37:39 +04:00
{
m_lazyFuncCreator . push_back ( fp ) ;
}
2014-02-19 15:49:24 +04:00
bool
IncrementalExecutor : : addSymbol ( const char * symbolName , void * symbolAddress ) {
2012-09-24 13:57:43 +04:00
void * actualAddress
2012-09-05 13:37:39 +04:00
= llvm : : sys : : DynamicLibrary : : SearchForAddressOfSymbol ( symbolName ) ;
2012-09-24 13:57:43 +04:00
if ( actualAddress )
2012-09-05 13:37:39 +04:00
return false ;
llvm : : sys : : DynamicLibrary : : AddSymbol ( symbolName , symbolAddress ) ;
return true ;
}
2012-09-24 13:57:43 +04:00
2014-02-19 15:49:24 +04:00
void * IncrementalExecutor : : getAddressOfGlobal ( llvm : : Module * m ,
2014-03-03 14:48:16 +04:00
llvm : : StringRef symbolName ,
2014-03-04 21:15:14 +04:00
bool * fromJIT /*=0*/ ) {
2012-11-19 02:27:00 +04:00
// Return a symbol's address, and whether it was jitted.
void * address
= llvm : : sys : : DynamicLibrary : : SearchForAddressOfSymbol ( symbolName ) ;
if ( address ) {
if ( fromJIT ) * fromJIT = false ;
} else {
if ( fromJIT ) * fromJIT = true ;
llvm : : GlobalVariable * gvar = m - > getGlobalVariable ( symbolName , true ) ;
if ( ! gvar )
return 0 ;
2012-10-23 12:46:38 +04:00
2014-04-28 14:32:12 +04:00
remapSymbols ( ) ;
2012-11-19 02:27:00 +04:00
address = m_engine - > getPointerToGlobal ( gvar ) ;
2012-09-24 13:57:43 +04:00
}
2012-11-19 02:27:00 +04:00
return address ;
}
2013-12-05 19:22:34 +04:00
void *
2014-03-04 21:15:14 +04:00
IncrementalExecutor : : getPointerToGlobalFromJIT ( const llvm : : GlobalValue & GV ) {
2014-04-28 14:32:12 +04:00
remapSymbols ( ) ;
2013-12-05 19:22:34 +04:00
if ( void * addr = m_engine - > getPointerToGlobalIfAvailable ( & GV ) )
return addr ;
// Function not yet codegened by the JIT, force this to happen now.
return m_engine - > getPointerToGlobal ( & GV ) ;
}
2014-03-07 18:09:02 +04:00
} // end namespace cling