diff options
Diffstat (limited to 'llvm/lib/ExecutionEngine/JIT/Callback.cpp')
| -rw-r--r-- | llvm/lib/ExecutionEngine/JIT/Callback.cpp | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/llvm/lib/ExecutionEngine/JIT/Callback.cpp b/llvm/lib/ExecutionEngine/JIT/Callback.cpp index fc13a10855b..0cb612c77f8 100644 --- a/llvm/lib/ExecutionEngine/JIT/Callback.cpp +++ b/llvm/lib/ExecutionEngine/JIT/Callback.cpp @@ -1,12 +1,14 @@ //===-- Callback.cpp - Trap handler for function resolution ---------------===// // -// This file defines the SIGSEGV handler which is invoked when a reference to a -// non-codegen'd function is found. +// This file defines the handler which is invoked when a reference to a +// non-codegen'd function is found. This file defines target specific code +// which is used by the JIT. // //===----------------------------------------------------------------------===// #include "VM.h" #include "Support/Statistic.h" +#include "llvm/CodeGen/MachineCodeEmitter.h" #include <iostream> static VM *TheVM = 0; @@ -21,6 +23,7 @@ void VM::CompilationCallback() { assert(StackPtr[1] == RetAddr && "Could not find return address on the stack!"); + bool isStub = ((unsigned char*)RetAddr)[0] == 0xCD; // Interrupt marker? // The call instruction should have pushed the return value onto the stack... RetAddr -= 4; // Backtrack to the reference itself... @@ -39,6 +42,14 @@ void VM::CompilationCallback() { // the call. *(unsigned*)RetAddr = NewVal-RetAddr-4; + if (isStub) { + // If this is a stub, rewrite the call into an unconditional branch + // instruction so that two return addresses are not pushed onto the stack + // when the requested function finally gets called. This also makes the + // 0xCD byte (interrupt) dead, so the marker doesn't effect anything. + ((unsigned char*)RetAddr)[-1] = 0xE9; + } + // Change the return address to reexecute the call instruction... StackPtr[1] -= 5; #else @@ -46,6 +57,24 @@ void VM::CompilationCallback() { #endif } +/// emitStubForFunction - This virtual method is used by the JIT when it needs +/// to emit the address of a function for a function whose code has not yet +/// been generated. In order to do this, it generates a stub which jumps to +/// the lazy function compiler, which will eventually get fixed to call the +/// function directly. +/// +void *VM::emitStubForFunction(const Function &F) { +#if defined(i386) || defined(__i386__) || defined(__x86__) + MCE->startFunctionStub(F, 6); + MCE->emitByte(0xE8); // Call with 32 bit pc-rel destination... + MCE->emitGlobalAddress((GlobalValue*)&F, true); + MCE->emitByte(0xCD); // Interrupt - Just a marker identifying the stub! + return MCE->finishFunctionStub(F); +#else + abort(); +#endif +} + void VM::registerCallback() { TheVM = this; } |

