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"
2020-10-10 21:34:55 +03:00
# include "BackendPasses.h"
2015-02-03 23:32:09 +03:00
# include "IncrementalJIT.h"
2015-03-14 00:03:50 +03:00
# include "Threading.h"
2012-09-05 13:37:39 +04:00
2020-10-11 00:43:37 +03:00
# include "cling/Interpreter/DynamicLibraryManager.h"
Provide __cxa_atexit replacement through custom MemoryManager.
On some platforms, global destructors are registered through a call to
__cxa_atexit(dtor, 0/*args*/, __dso_handle). While __cxa_atexit can be resolved
by the regular MemoryManager, __dso_handle (representing the "current shared
library" such that the corresponding atexit function can be called on its
dlclose) can not be resolved by MCJIT. Instead, we provide our own, poining to
the ExecutionEngine, which in turn holds a "current module" that corresponds in
spirit to the shared library handle.
__cxa_atexit, on the other hand, needs to be re-wired: the interpreter needs to
destruct globals upon its destruction, and those globals from a certain module
when that module is unloaded.
Both is done through a custom MemoryManager, significantly reducing the
complexity of the previous ("JIT without MC") implementation.
The custom MemoryManager also forwards in case of a unknown symbols to the LazyFunctionCreators instead of using the generic
ExecutionEngine::InstallLazyFunctionCreator() which has no effect with MCJIT.
2015-01-08 15:54:22 +03:00
# include "cling/Interpreter/Transaction.h"
2020-10-11 00:43:37 +03:00
# include "cling/Interpreter/Value.h"
2015-02-12 20:23:04 +03:00
# include "cling/Utils/AST.h"
2016-09-10 22:04:39 +03:00
# include "cling/Utils/Output.h"
2016-12-16 21:33:42 +03:00
# include "cling/Utils/Platform.h"
2014-05-26 18:33:43 +04:00
2014-05-28 15:56:16 +04:00
# include "clang/Basic/Diagnostic.h"
2016-11-15 17:12:47 +03:00
# include "clang/Frontend/CompilerInstance.h"
2014-05-28 15:56:16 +04:00
2021-12-17 10:15:46 +03:00
# include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
2014-03-15 02:11:09 +04:00
# include "llvm/IR/Instructions.h"
2013-04-24 20:28:08 +04:00
# include "llvm/IR/Module.h"
2012-11-17 20:28:14 +04:00
# include "llvm/ADT/SmallPtrSet.h"
2012-09-05 13:37:39 +04:00
2019-03-13 10:12:28 +03:00
# include <iostream>
2014-03-07 18:09:02 +04:00
using namespace llvm ;
Provide __cxa_atexit replacement through custom MemoryManager.
On some platforms, global destructors are registered through a call to
__cxa_atexit(dtor, 0/*args*/, __dso_handle). While __cxa_atexit can be resolved
by the regular MemoryManager, __dso_handle (representing the "current shared
library" such that the corresponding atexit function can be called on its
dlclose) can not be resolved by MCJIT. Instead, we provide our own, poining to
the ExecutionEngine, which in turn holds a "current module" that corresponds in
spirit to the shared library handle.
__cxa_atexit, on the other hand, needs to be re-wired: the interpreter needs to
destruct globals upon its destruction, and those globals from a certain module
when that module is unloaded.
Both is done through a custom MemoryManager, significantly reducing the
complexity of the previous ("JIT without MC") implementation.
The custom MemoryManager also forwards in case of a unknown symbols to the LazyFunctionCreators instead of using the generic
ExecutionEngine::InstallLazyFunctionCreator() which has no effect with MCJIT.
2015-01-08 15:54:22 +03:00
2014-03-07 18:09:02 +04:00
namespace cling {
2012-09-05 13:37:39 +04:00
2020-09-30 18:46:22 +03:00
IncrementalExecutor : : IncrementalExecutor ( clang : : DiagnosticsEngine & /*diags*/ ,
2022-07-06 13:58:56 +03:00
const clang : : CompilerInstance & CI ,
2022-09-15 18:59:18 +03:00
void * ExtraLibHandle , bool Verbose ) :
2023-05-30 12:29:59 +03:00
m_Callbacks ( nullptr )
2016-12-20 17:38:19 +03:00
#if 0
: m_Diags ( diags )
# endif
{
2020-10-11 00:43:37 +03:00
m_DyLibManager . initializeDyld ( [ ] ( llvm : : StringRef ) { /*ignore*/ return false ; } ) ;
2016-12-20 17:38:19 +03:00
// MSVC doesn't support m_AtExitFuncsSpinLock=ATOMIC_FLAG_INIT; in the class definition
std : : atomic_flag_clear ( & m_AtExitFuncsSpinLock ) ;
2021-12-17 10:15:46 +03:00
llvm : : Error Err = llvm : : Error : : success ( ) ;
auto EPC = llvm : : cantFail ( llvm : : orc : : SelfExecutorProcessControl : : Create ( ) ) ;
2022-12-21 10:45:57 +03:00
m_JIT . reset ( new IncrementalJIT ( * this , CI , std : : move ( EPC ) , Err ,
2022-09-15 18:59:18 +03:00
ExtraLibHandle , Verbose ) ) ;
2021-12-17 10:15:46 +03:00
if ( Err ) {
llvm : : logAllUnhandledErrors ( std : : move ( Err ) , llvm : : errs ( ) , " Fatal: " ) ;
llvm_unreachable ( " Propagate this error and exit gracefully " ) ;
}
2021-08-05 17:57:09 +03:00
2023-01-12 15:54:23 +03:00
m_BackendPasses . reset ( new BackendPasses ( CI . getCodeGenOpts ( ) , * m_JIT , m_JIT - > getTargetMachine ( ) ) ) ;
2016-12-20 17:38:19 +03:00
}
IncrementalExecutor : : ~ IncrementalExecutor ( ) { }
2012-11-17 16:09:08 +04:00
2023-05-30 12:29:59 +03:00
void IncrementalExecutor : : registerExternalIncrementalExecutor (
IncrementalExecutor & IE ) {
m_JIT - > addGenerator ( IE . m_JIT - > getGenerator ( ) ) ;
}
2019-12-13 12:25:46 +03:00
void IncrementalExecutor : : runAtExitFuncs ( ) {
2017-07-12 22:04:11 +03:00
// It is legal to register an atexit handler from within another atexit
// handler and furthor-more the standard says they need to run in reverse
// order, so this function must be recursion safe.
AtExitFunctions Local ;
{
cling : : internal : : SpinLockGuard slg ( m_AtExitFuncsSpinLock ) ;
// Check this case first, to avoid the swap all-together.
if ( m_AtExitFuncs . empty ( ) )
return ;
Local . swap ( m_AtExitFuncs ) ;
}
2017-08-24 17:22:27 +03:00
for ( auto & & Ordered : llvm : : reverse ( Local . ordered ( ) ) ) {
2017-07-12 22:04:11 +03:00
for ( auto & & AtExit : llvm : : reverse ( Ordered - > second ) )
AtExit ( ) ;
2017-08-24 17:22:27 +03:00
// The standard says that they need to run in reverse order, which means
// anything added from 'AtExit()' must now be run!
2019-12-13 12:25:46 +03:00
runAtExitFuncs ( ) ;
2017-07-12 22:04:11 +03:00
}
2013-09-19 13:24:31 +04:00
}
2012-09-05 13:37:39 +04:00
2017-09-25 14:06:10 +03:00
void IncrementalExecutor : : AddAtExitFunc ( void ( * func ) ( void * ) , void * arg ,
2020-09-05 15:00:40 +03:00
const Transaction * T ) {
2013-09-19 13:24:31 +04:00
// Register a CXAAtExit function
2015-03-14 00:03:50 +03:00
cling : : internal : : SpinLockGuard slg ( m_AtExitFuncsSpinLock ) ;
2020-09-05 15:00:40 +03:00
m_AtExitFuncs [ T ] . emplace_back ( func , arg ) ;
2013-09-19 13:24:31 +04:00
}
2012-09-05 13:37:39 +04:00
void unresolvedSymbol ( )
{
2015-07-03 11:11:50 +03:00
// This might get called recursively, or a billion of times. Do not generate
// useless output; unresolvedSymbol() is always handed out with an error
// message - that's enough.
2016-09-10 22:04:39 +03:00
//cling::errs() << "IncrementalExecutor: calling unresolved symbol, "
2015-07-03 11:11:50 +03:00
// "see previous error message!\n";
// throw exception instead?
2012-09-05 13:37:39 +04:00
}
2019-03-16 12:36:13 +03:00
void *
IncrementalExecutor : : HandleMissingFunction ( const std : : string & mangled_name ) const {
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 ) {
2016-09-10 22:04:39 +03:00
//cling::errs() << "IncrementalExecutor: use of undefined symbol '"
2014-05-28 15:56:16 +04:00
// << mangled_name << "'!\n";
2012-10-07 15:53:16 +04:00
}
2012-09-05 13:37:39 +04:00
2017-01-27 22:35:13 +03:00
return utils : : FunctionToVoidPtr ( & unresolvedSymbol ) ;
2012-09-05 13:37:39 +04:00
}
2015-02-11 11:46:44 +03:00
#if 0
// FIXME: employ to empty module dependencies *within* the *current* module.
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 " ) ;
2015-01-15 17:13:14 +03:00
if ( funcsToFreeUnique . insert ( func ) . second ) {
2012-11-17 20:28:14 +04:00
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 ) ;
}
}
2015-02-11 11:46:44 +03:00
# endif
2012-09-05 13:37:39 +04:00
2020-09-05 15:00:40 +03:00
static bool isPracticallyEmptyModule ( const llvm : : Module * M ) {
return M - > empty ( ) & & M - > global_empty ( ) & & M - > alias_empty ( ) ;
}
2014-02-19 15:49:24 +04:00
IncrementalExecutor : : ExecutionResult
2020-09-05 15:00:40 +03:00
IncrementalExecutor : : runStaticInitializersOnce ( Transaction & T ) {
2020-03-18 19:33:39 +03:00
llvm : : Module * m = T . getModule ( ) ;
assert ( m & & " Module must not be null " ) ;
2012-09-05 13:37:39 +04:00
2020-09-05 15:00:40 +03:00
if ( isPracticallyEmptyModule ( m ) )
return kExeSuccess ;
2022-03-20 16:01:40 +03:00
emitModule ( T ) ;
2020-09-05 15:00:40 +03:00
2015-01-09 11:40:58 +03:00
// We don't care whether something was unresolved before.
m_unresolvedSymbols . clear ( ) ;
// check if there is any unresolved symbol in the list
if ( diagnoseUnresolvedSymbols ( " static initializers " ) )
return kExeUnresolvedSymbols ;
2022-03-20 16:21:38 +03:00
if ( llvm : : Error Err = m_JIT - > runCtors ( ) ) {
llvm : : logAllUnhandledErrors ( std : : move ( Err ) , llvm : : errs ( ) ,
" [runStaticInitializersOnce]: " ) ;
2012-09-05 13:37:39 +04:00
}
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.
2017-07-12 22:04:11 +03:00
AtExitFunctions : : mapped_type Local ;
2015-03-14 00:03:50 +03:00
{
cling : : internal : : SpinLockGuard slg ( m_AtExitFuncsSpinLock ) ;
2020-09-05 15:00:40 +03:00
auto Itr = m_AtExitFuncs . find ( T ) ;
2017-08-24 17:22:27 +03:00
if ( Itr = = m_AtExitFuncs . end ( ) ) return ;
2017-07-12 22:04:11 +03:00
m_AtExitFuncs . erase ( Itr , & Local ) ;
2015-03-14 00:03:50 +03:00
} // end of spin lock lifetime block.
2014-02-27 12:53:42 +04:00
2017-07-12 22:04:11 +03:00
// 'Unload' the cxa_atexit, atexit entities.
for ( auto & & AtExit : llvm : : reverse ( Local ) ) {
2017-07-12 21:40:51 +03:00
AtExit ( ) ;
2017-07-12 22:04:11 +03:00
// Run anything that was just registered in 'AtExit()'
runAndRemoveStaticDestructors ( T ) ;
}
2012-09-05 13:37:39 +04:00
}
2019-03-13 10:12:28 +03:00
static void flushOutBuffers ( ) {
// Force-flush as we might be printing on screen with printf.
std : : cout . flush ( ) ;
fflush ( stdout ) ;
}
IncrementalExecutor : : ExecutionResult
IncrementalExecutor : : executeWrapper ( llvm : : StringRef function ,
2019-03-16 12:36:13 +03:00
Value * returnValue /* =0*/ ) const {
2019-03-13 10:12:28 +03:00
// Set the value to cling::invalid.
if ( returnValue )
* returnValue = Value ( ) ;
typedef void ( * InitFun_t ) ( void * ) ;
InitFun_t fun ;
ExecutionResult res = jitInitOrWrapper ( function , fun ) ;
if ( res ! = kExeSuccess )
return res ;
EnterUserCodeRAII euc ( m_Callbacks ) ;
( * fun ) ( returnValue ) ;
flushOutBuffers ( ) ;
return kExeSuccess ;
}
2020-10-11 00:43:37 +03:00
void IncrementalExecutor : : setCallbacks ( InterpreterCallbacks * callbacks ) {
m_Callbacks = callbacks ;
m_DyLibManager . setCallbacks ( callbacks ) ;
}
2022-07-07 15:02:28 +03:00
void IncrementalExecutor : : addGenerator (
std : : unique_ptr < llvm : : orc : : DefinitionGenerator > G ) {
m_JIT - > addGenerator ( std : : move ( G ) ) ;
2012-09-05 13:37:39 +04:00
}
2022-03-26 01:00:52 +03:00
void IncrementalExecutor : : replaceSymbol ( const char * Name , void * Addr ) const {
assert ( Addr ) ;
// FIXME: Look at the registration of at_quick_exit and uncomment.
// assert(m_JIT->getSymbolAddress(Name, /*IncludeHostSymbols*/true) &&
// "The symbol must exist");
m_JIT - > addOrReplaceDefinition ( Name , llvm : : pointerToJITTargetAddress ( Addr ) ) ;
2012-09-05 13:37:39 +04:00
}
2012-09-24 13:57:43 +04:00
2015-01-12 11:57:30 +03:00
void * IncrementalExecutor : : getAddressOfGlobal ( llvm : : StringRef symbolName ,
2019-03-16 12:36:13 +03:00
bool * fromJIT /*=0*/ ) const {
2022-03-26 01:05:32 +03:00
constexpr bool includeHostSymbols = true ;
void * address = m_JIT - > getSymbolAddress ( symbolName , includeHostSymbols ) ;
// FIXME: If we split the loaded libraries into a separate JITDylib we should
// be able to delete this code and use something like:
// if (IncludeHostSymbols) {
// if (auto Sym = lookup(<HostSymbolsJD>, Name)) {
// fromJIT = false;
// return Sym;
// }
// }
// if (auto Sym = lookup(<REPLJD>, Name)) {
// fromJIT = true;
// return Sym;
// }
// fromJIT = false;
// return nullptr;
if ( fromJIT ) {
// FIXME: See comments on DLSym below.
// We use dlsym to just tell if somethings was from the jit or not.
# if !defined(_WIN32)
void * Addr = llvm : : sys : : DynamicLibrary : : SearchForAddressOfSymbol ( symbolName . str ( ) ) ;
# else
2022-05-17 14:13:07 +03:00
void * Addr = const_cast < void * > ( platform : : DLSym ( symbolName . str ( ) ) ) ;
2022-03-26 01:05:32 +03:00
# endif
* fromJIT = ! Addr ;
2021-12-17 10:15:46 +03:00
}
2015-01-12 11:23:03 +03:00
2022-03-26 01:05:32 +03:00
return address ;
2012-11-19 02:27:00 +04:00
}
2013-12-05 19:22:34 +04:00
void *
2020-09-05 15:00:40 +03:00
IncrementalExecutor : : getPointerToGlobalFromJIT ( llvm : : StringRef name ) const {
// Get the function / variable pointer referenced by name.
2014-10-14 16:11:31 +04:00
// We don't care whether something was unresolved before.
m_unresolvedSymbols . clear ( ) ;
2021-12-17 10:15:46 +03:00
void * addr = m_JIT - > getSymbolAddress ( name , false /*no dlsym*/ ) ;
2013-12-05 19:22:34 +04:00
2020-09-05 15:00:40 +03:00
if ( diagnoseUnresolvedSymbols ( name , " symbol " ) )
2022-09-13 09:34:32 +03:00
return nullptr ;
2015-02-03 23:32:09 +03:00
return addr ;
2013-12-05 19:22:34 +04:00
}
2014-10-14 16:11:31 +04:00
2014-10-16 13:20:04 +04:00
bool IncrementalExecutor : : diagnoseUnresolvedSymbols ( llvm : : StringRef trigger ,
2019-03-16 12:36:13 +03:00
llvm : : StringRef title ) const {
2014-10-14 16:11:31 +04:00
if ( m_unresolvedSymbols . empty ( ) )
return false ;
2022-03-20 16:21:38 +03:00
if ( m_unresolvedSymbols . size ( ) = = 1 & & * m_unresolvedSymbols . begin ( ) = = trigger )
return false ;
2014-10-14 16:11:31 +04:00
2018-11-20 21:55:35 +03:00
// Issue callback to TCling!!
for ( const std : : string & sym : m_unresolvedSymbols ) {
// We emit callback to LibraryLoadingFailed when we get error with error message.
if ( InterpreterCallbacks * C = m_Callbacks )
if ( C - > LibraryLoadingFailed ( sym , " " , false , false ) )
return false ;
}
2014-10-14 16:11:31 +04:00
llvm : : SmallVector < llvm : : Function * , 128 > funcsToFree ;
2017-07-12 21:33:07 +03:00
for ( const std : : string & sym : m_unresolvedSymbols ) {
2014-10-14 16:11:31 +04:00
#if 0
// FIXME: This causes a lot of test failures, for some reason it causes
// the call to HandleMissingFunction to be elided.
unsigned diagID = m_Diags . getCustomDiagID ( clang : : DiagnosticsEngine : : Error ,
" %0 unresolved while jitting %1 " ) ;
( void ) diagID ;
2017-07-12 21:33:07 +03:00
//m_Diags.Report(diagID) << sym << funcname; // TODO: demangle the names.
2014-10-14 16:11:31 +04:00
# endif
2017-07-12 21:33:07 +03:00
cling : : errs ( ) < < " IncrementalExecutor::executeFunction: symbol ' " < < sym
2016-09-10 22:04:39 +03:00
< < " ' unresolved while linking " ;
2015-02-12 20:23:04 +03:00
if ( trigger . find ( utils : : Synthesize : : UniquePrefix ) ! = llvm : : StringRef : : npos )
2016-09-10 22:04:39 +03:00
cling : : errs ( ) < < " [cling interface function] " ;
2015-02-12 20:23:04 +03:00
else {
if ( ! title . empty ( ) )
2016-09-10 22:04:39 +03:00
cling : : errs ( ) < < title < < " ' " ;
cling : : errs ( ) < < trigger ;
2015-02-12 20:23:04 +03:00
if ( ! title . empty ( ) )
2016-09-10 22:04:39 +03:00
cling : : errs ( ) < < " ' " ;
2015-02-12 20:23:04 +03:00
}
2016-09-10 22:04:39 +03:00
cling : : errs ( ) < < " ! \n " ;
2015-02-12 20:23:04 +03:00
// Be helpful, demangle!
2017-07-12 21:33:07 +03:00
std : : string demangledName = platform : : Demangle ( sym ) ;
2015-02-12 20:23:04 +03:00
if ( ! demangledName . empty ( ) ) {
2016-09-10 22:04:39 +03:00
cling : : errs ( )
2015-02-12 20:23:04 +03:00
< < " You are probably missing the definition of "
< < demangledName < < " \n "
< < " Maybe you need to load the corresponding shared library? \n " ;
}
2020-10-11 00:43:37 +03:00
std : : string libName = m_DyLibManager . searchLibrariesForSymbol ( sym ,
/*searchSystem=*/ true ) ;
if ( ! libName . empty ( ) )
cling : : errs ( ) < < " Symbol found in ' " < < libName < < " '; "
< < " did you mean to load it with '.L "
< < libName < < " '? \n " ;
2015-02-03 23:32:09 +03:00
//llvm::Function *ff = m_engine->FindFunctionNamed(i->c_str());
2014-10-14 16:11:31 +04:00
// i could also reference a global variable, in which case ff == 0.
2015-02-03 23:32:09 +03:00
//if (ff)
// funcsToFree.push_back(ff);
2014-10-14 16:11:31 +04:00
}
2015-02-03 23:32:09 +03:00
//freeCallersOfUnresolvedSymbols(funcsToFree, m_engine.get());
2014-10-14 16:11:31 +04:00
m_unresolvedSymbols . clear ( ) ;
return true ;
}
2014-03-07 18:09:02 +04:00
} // end namespace cling