blob: 0cb612c77f896dabb156ed56fc475311dd20a3cc [file] [log] [blame]
Chris Lattnerbd199fb2002-12-24 00:01:05 +00001//===-- Callback.cpp - Trap handler for function resolution ---------------===//
2//
Chris Lattner6125fdd2003-05-09 03:30:07 +00003// 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 Lattnerbd199fb2002-12-24 00:01:05 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "VM.h"
10#include "Support/Statistic.h"
Chris Lattner6125fdd2003-05-09 03:30:07 +000011#include "llvm/CodeGen/MachineCodeEmitter.h"
Chris Lattnerbd199fb2002-12-24 00:01:05 +000012#include <iostream>
13
14static VM *TheVM = 0;
15
Chris Lattnerc309a762003-05-08 21:34:11 +000016// CompilationCallback - Invoked the first time that a call site is found,
17// which causes lazy compilation of the target function.
18//
19void 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 Lattnerbd199fb2002-12-24 00:01:05 +000023
Chris Lattnerc309a762003-05-08 21:34:11 +000024 assert(StackPtr[1] == RetAddr &&
25 "Could not find return address on the stack!");
Chris Lattner6125fdd2003-05-09 03:30:07 +000026 bool isStub = ((unsigned char*)RetAddr)[0] == 0xCD; // Interrupt marker?
Chris Lattnerbd199fb2002-12-24 00:01:05 +000027
28 // The call instruction should have pushed the return value onto the stack...
Chris Lattnerc309a762003-05-08 21:34:11 +000029 RetAddr -= 4; // Backtrack to the reference itself...
Chris Lattnerbd199fb2002-12-24 00:01:05 +000030
Chris Lattnerc309a762003-05-08 21:34:11 +000031 DEBUG(std::cerr << "In callback! Addr=0x" << std::hex << RetAddr
32 << " ESP=0x" << (unsigned)StackPtr << std::dec
Chris Lattnerbd199fb2002-12-24 00:01:05 +000033 << ": Resolving call to function: "
Chris Lattnerc309a762003-05-08 21:34:11 +000034 << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n");
Chris Lattnerbd199fb2002-12-24 00:01:05 +000035
36 // Sanity check to make sure this really is a call instruction...
Chris Lattnerc309a762003-05-08 21:34:11 +000037 assert(((unsigned char*)RetAddr)[-1] == 0xE8 && "Not a call instr!");
Chris Lattnerbd199fb2002-12-24 00:01:05 +000038
Chris Lattnerc309a762003-05-08 21:34:11 +000039 unsigned NewVal = (unsigned)TheVM->resolveFunctionReference((void*)RetAddr);
Chris Lattnerbd199fb2002-12-24 00:01:05 +000040
41 // Rewrite the call target... so that we don't fault every time we execute
42 // the call.
Chris Lattnerc309a762003-05-08 21:34:11 +000043 *(unsigned*)RetAddr = NewVal-RetAddr-4;
Chris Lattnerbd199fb2002-12-24 00:01:05 +000044
Chris Lattner6125fdd2003-05-09 03:30:07 +000045 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 Lattnerc309a762003-05-08 21:34:11 +000053 // Change the return address to reexecute the call instruction...
54 StackPtr[1] -= 5;
55#else
56 abort();
Chris Lattnerbd199fb2002-12-24 00:01:05 +000057#endif
58}
59
Chris Lattner6125fdd2003-05-09 03:30:07 +000060/// 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///
66void *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 Lattnerbd199fb2002-12-24 00:01:05 +000078void VM::registerCallback() {
79 TheVM = this;
Chris Lattnerbd199fb2002-12-24 00:01:05 +000080}
81
82