Chris Lattner | bd199fb | 2002-12-24 00:01:05 +0000 | [diff] [blame] | 1 | //===-- Callback.cpp - Trap handler for function resolution ---------------===// |
| 2 | // |
Chris Lattner | 6125fdd | 2003-05-09 03:30:07 +0000 | [diff] [blame] | 3 | // This file defines the handler which is invoked when a reference to a |
| 4 | // non-codegen'd function is found. This file defines target specific code |
| 5 | // which is used by the JIT. |
Chris Lattner | bd199fb | 2002-12-24 00:01:05 +0000 | [diff] [blame] | 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "VM.h" |
| 10 | #include "Support/Statistic.h" |
Chris Lattner | 6125fdd | 2003-05-09 03:30:07 +0000 | [diff] [blame] | 11 | #include "llvm/CodeGen/MachineCodeEmitter.h" |
Chris Lattner | bd199fb | 2002-12-24 00:01:05 +0000 | [diff] [blame] | 12 | #include <iostream> |
| 13 | |
| 14 | static VM *TheVM = 0; |
| 15 | |
Chris Lattner | c309a76 | 2003-05-08 21:34:11 +0000 | [diff] [blame] | 16 | // CompilationCallback - Invoked the first time that a call site is found, |
| 17 | // which causes lazy compilation of the target function. |
| 18 | // |
| 19 | void VM::CompilationCallback() { |
| 20 | #if defined(i386) || defined(__i386__) || defined(__x86__) |
| 21 | unsigned *StackPtr = (unsigned*)__builtin_frame_address(0); |
| 22 | unsigned RetAddr = (unsigned)__builtin_return_address(0); |
Chris Lattner | bd199fb | 2002-12-24 00:01:05 +0000 | [diff] [blame] | 23 | |
Chris Lattner | c309a76 | 2003-05-08 21:34:11 +0000 | [diff] [blame] | 24 | assert(StackPtr[1] == RetAddr && |
| 25 | "Could not find return address on the stack!"); |
Chris Lattner | 6125fdd | 2003-05-09 03:30:07 +0000 | [diff] [blame] | 26 | bool isStub = ((unsigned char*)RetAddr)[0] == 0xCD; // Interrupt marker? |
Chris Lattner | bd199fb | 2002-12-24 00:01:05 +0000 | [diff] [blame] | 27 | |
| 28 | // The call instruction should have pushed the return value onto the stack... |
Chris Lattner | c309a76 | 2003-05-08 21:34:11 +0000 | [diff] [blame] | 29 | RetAddr -= 4; // Backtrack to the reference itself... |
Chris Lattner | bd199fb | 2002-12-24 00:01:05 +0000 | [diff] [blame] | 30 | |
Chris Lattner | c309a76 | 2003-05-08 21:34:11 +0000 | [diff] [blame] | 31 | DEBUG(std::cerr << "In callback! Addr=0x" << std::hex << RetAddr |
| 32 | << " ESP=0x" << (unsigned)StackPtr << std::dec |
Chris Lattner | bd199fb | 2002-12-24 00:01:05 +0000 | [diff] [blame] | 33 | << ": Resolving call to function: " |
Chris Lattner | c309a76 | 2003-05-08 21:34:11 +0000 | [diff] [blame] | 34 | << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n"); |
Chris Lattner | bd199fb | 2002-12-24 00:01:05 +0000 | [diff] [blame] | 35 | |
| 36 | // Sanity check to make sure this really is a call instruction... |
Chris Lattner | c309a76 | 2003-05-08 21:34:11 +0000 | [diff] [blame] | 37 | assert(((unsigned char*)RetAddr)[-1] == 0xE8 && "Not a call instr!"); |
Chris Lattner | bd199fb | 2002-12-24 00:01:05 +0000 | [diff] [blame] | 38 | |
Chris Lattner | c309a76 | 2003-05-08 21:34:11 +0000 | [diff] [blame] | 39 | unsigned NewVal = (unsigned)TheVM->resolveFunctionReference((void*)RetAddr); |
Chris Lattner | bd199fb | 2002-12-24 00:01:05 +0000 | [diff] [blame] | 40 | |
| 41 | // Rewrite the call target... so that we don't fault every time we execute |
| 42 | // the call. |
Chris Lattner | c309a76 | 2003-05-08 21:34:11 +0000 | [diff] [blame] | 43 | *(unsigned*)RetAddr = NewVal-RetAddr-4; |
Chris Lattner | bd199fb | 2002-12-24 00:01:05 +0000 | [diff] [blame] | 44 | |
Chris Lattner | 6125fdd | 2003-05-09 03:30:07 +0000 | [diff] [blame] | 45 | if (isStub) { |
| 46 | // If this is a stub, rewrite the call into an unconditional branch |
| 47 | // instruction so that two return addresses are not pushed onto the stack |
| 48 | // when the requested function finally gets called. This also makes the |
| 49 | // 0xCD byte (interrupt) dead, so the marker doesn't effect anything. |
| 50 | ((unsigned char*)RetAddr)[-1] = 0xE9; |
| 51 | } |
| 52 | |
Chris Lattner | c309a76 | 2003-05-08 21:34:11 +0000 | [diff] [blame] | 53 | // Change the return address to reexecute the call instruction... |
| 54 | StackPtr[1] -= 5; |
| 55 | #else |
| 56 | abort(); |
Chris Lattner | bd199fb | 2002-12-24 00:01:05 +0000 | [diff] [blame] | 57 | #endif |
| 58 | } |
| 59 | |
Chris Lattner | 6125fdd | 2003-05-09 03:30:07 +0000 | [diff] [blame] | 60 | /// emitStubForFunction - This virtual method is used by the JIT when it needs |
| 61 | /// to emit the address of a function for a function whose code has not yet |
| 62 | /// been generated. In order to do this, it generates a stub which jumps to |
| 63 | /// the lazy function compiler, which will eventually get fixed to call the |
| 64 | /// function directly. |
| 65 | /// |
| 66 | void *VM::emitStubForFunction(const Function &F) { |
| 67 | #if defined(i386) || defined(__i386__) || defined(__x86__) |
| 68 | MCE->startFunctionStub(F, 6); |
| 69 | MCE->emitByte(0xE8); // Call with 32 bit pc-rel destination... |
| 70 | MCE->emitGlobalAddress((GlobalValue*)&F, true); |
| 71 | MCE->emitByte(0xCD); // Interrupt - Just a marker identifying the stub! |
| 72 | return MCE->finishFunctionStub(F); |
| 73 | #else |
| 74 | abort(); |
| 75 | #endif |
| 76 | } |
| 77 | |
Chris Lattner | bd199fb | 2002-12-24 00:01:05 +0000 | [diff] [blame] | 78 | void VM::registerCallback() { |
| 79 | TheVM = this; |
Chris Lattner | bd199fb | 2002-12-24 00:01:05 +0000 | [diff] [blame] | 80 | } |
| 81 | |
| 82 | |