diff --git a/lib/ExecutionEngine/JIT/Callback.cpp b/lib/ExecutionEngine/JIT/Callback.cpp index 3b40e2ebe1d..75abf435e6a 100644 --- a/lib/ExecutionEngine/JIT/Callback.cpp +++ b/lib/ExecutionEngine/JIT/Callback.cpp @@ -7,63 +7,48 @@ #include "VM.h" #include "Support/Statistic.h" -#include -#include #include static VM *TheVM = 0; -static void TrapHandler(int TN, siginfo_t *SI, ucontext_t *ucp) { - assert(TN == SIGSEGV && "Should be SIGSEGV!"); +// CompilationCallback - Invoked the first time that a call site is found, +// which causes lazy compilation of the target function. +// +void VM::CompilationCallback() { +#if defined(i386) || defined(__i386__) || defined(__x86__) + unsigned *StackPtr = (unsigned*)__builtin_frame_address(0); + unsigned RetAddr = (unsigned)__builtin_return_address(0); -#ifdef REG_EIP /* this code does not compile on Sparc! */ - if (SI->si_code != SEGV_MAPERR || SI->si_addr != 0 || - ucp->uc_mcontext.gregs[REG_EIP] != 0) { - std::cerr << "Bad SEGV encountered EIP = 0x" << std::hex - << ucp->uc_mcontext.gregs[REG_EIP] << " addr = " - << SI->si_addr << "!\n"; - - struct sigaction SA; // Restore old SEGV handler... - SA.sa_handler = SIG_DFL; - SA.sa_flags = SA_NOMASK; - sigaction(SIGSEGV, &SA, 0); - return; // Should core dump now... - } + assert(StackPtr[1] == RetAddr && + "Could not find return address on the stack!"); // The call instruction should have pushed the return value onto the stack... - unsigned RefAddr = *(unsigned*)ucp->uc_mcontext.gregs[REG_ESP]; - RefAddr -= 4; // Backtrack to the reference itself... + RetAddr -= 4; // Backtrack to the reference itself... - DEBUG(std::cerr << "In SEGV handler! Addr=0x" << std::hex << RefAddr - << " ESP=0x" << ucp->uc_mcontext.gregs[REG_ESP] << std::dec + DEBUG(std::cerr << "In callback! Addr=0x" << std::hex << RetAddr + << " ESP=0x" << (unsigned)StackPtr << std::dec << ": Resolving call to function: " - << TheVM->getFunctionReferencedName((void*)RefAddr) << "\n"); + << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n"); // Sanity check to make sure this really is a call instruction... - assert(((unsigned char*)RefAddr)[-1] == 0xE8 && "Not a call instr!"); + assert(((unsigned char*)RetAddr)[-1] == 0xE8 && "Not a call instr!"); - unsigned NewVal = (unsigned)TheVM->resolveFunctionReference((void*)RefAddr); + unsigned NewVal = (unsigned)TheVM->resolveFunctionReference((void*)RetAddr); // Rewrite the call target... so that we don't fault every time we execute // the call. - *(unsigned*)RefAddr = NewVal-RefAddr-4; - - // Change the instruction pointer to be the real target of the call... - ucp->uc_mcontext.gregs[REG_EIP] = NewVal; + *(unsigned*)RetAddr = NewVal-RetAddr-4; + // Change the return address to reexecute the call instruction... + StackPtr[1] -= 5; +#else + abort(); #endif } void VM::registerCallback() { TheVM = this; - - // Register the signal handler... - struct sigaction SA; - SA.sa_sigaction = (void (*)(int, siginfo_t*, void*))TrapHandler; - sigfillset(&SA.sa_mask); // Block all signals while codegen'ing - SA.sa_flags = SA_NOCLDSTOP|SA_SIGINFO; // Get siginfo - sigaction(SIGSEGV, &SA, 0); // Install the handler } diff --git a/lib/ExecutionEngine/JIT/JIT.h b/lib/ExecutionEngine/JIT/JIT.h index 3b267ed877b..9080b3be045 100644 --- a/lib/ExecutionEngine/JIT/JIT.h +++ b/lib/ExecutionEngine/JIT/JIT.h @@ -50,10 +50,15 @@ public: /// void *getPointerToNamedFunction(const std::string &Name); + // CompilationCallback - Invoked the first time that a call site is found, + // which causes lazy compilation of the target function. + // + static void CompilationCallback(); private: static MachineCodeEmitter *createEmitter(VM &V); void setupPassManager(); void *getPointerToFunction(const Function *F); + void registerCallback(); }; diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index 1c89bdba26b..d6f75c08f76 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -131,8 +131,11 @@ void Emitter::emitAddress(void *Addr, bool isPCRelative) { void Emitter::emitGlobalAddress(GlobalValue *V, bool isPCRelative) { if (isPCRelative) { // must be a call, this is a major hack! + // FIXME: Try looking up the function to see if it is already compiled! TheVM.addFunctionRef(CurByte, cast(V)); - emitAddress(0, isPCRelative); // Delayed resolution... + + // Delayed resolution... + emitAddress((void*)VM::CompilationCallback, isPCRelative); } else { emitAddress(TheVM.getPointerToGlobal(V), isPCRelative); } diff --git a/lib/ExecutionEngine/JIT/VM.h b/lib/ExecutionEngine/JIT/VM.h index 3b267ed877b..9080b3be045 100644 --- a/lib/ExecutionEngine/JIT/VM.h +++ b/lib/ExecutionEngine/JIT/VM.h @@ -50,10 +50,15 @@ public: /// void *getPointerToNamedFunction(const std::string &Name); + // CompilationCallback - Invoked the first time that a call site is found, + // which causes lazy compilation of the target function. + // + static void CompilationCallback(); private: static MachineCodeEmitter *createEmitter(VM &V); void setupPassManager(); void *getPointerToFunction(const Function *F); + void registerCallback(); };