-namespace {
- Statistic<>
- NumEmitted("x86-emitter", "Number of machine instructions emitted");
-
- class JITResolver {
- MachineCodeEmitter &MCE;
-
- // LazyCodeGenMap - Keep track of call sites for functions that are to be
- // lazily resolved.
- std::map<unsigned, Function*> LazyCodeGenMap;
-
- // LazyResolverMap - Keep track of the lazy resolver created for a
- // particular function so that we can reuse them if necessary.
- std::map<Function*, unsigned> LazyResolverMap;
- public:
- JITResolver(MachineCodeEmitter &mce) : MCE(mce) {}
- unsigned getLazyResolver(Function *F);
- unsigned addFunctionReference(unsigned Address, Function *F);
-
- private:
- unsigned emitStubForFunction(Function *F);
- static void CompilationCallback();
- unsigned resolveFunctionReference(unsigned RetAddr);
- };
-
- static JITResolver &getResolver(MachineCodeEmitter &MCE) {
- static JITResolver *TheJITResolver = 0;
- if (TheJITResolver == 0)
- TheJITResolver = new JITResolver(MCE);
- return *TheJITResolver;
- }
-}
-
-
-void *X86JITInfo::getJITStubForFunction(Function *F, MachineCodeEmitter &MCE) {
- return (void*)((unsigned long)getResolver(MCE).getLazyResolver(F));
-}
-
-void X86JITInfo::replaceMachineCodeForFunction (void *Old, void *New) {
- char *OldByte = (char *) Old;
- *OldByte++ = 0xE9; // Emit JMP opcode.
- int32_t *OldWord = (int32_t *) OldByte;
- int32_t NewAddr = (intptr_t) New;
- int32_t OldAddr = (intptr_t) OldWord;
- *OldWord = NewAddr - OldAddr - 4; // Emit PC-relative addr of New code.
-}
-
-/// addFunctionReference - This method is called when we need to emit the
-/// address of a function that has not yet been emitted, so we don't know the
-/// address. Instead, we emit a call to the CompilationCallback method, and
-/// keep track of where we are.
-///
-unsigned JITResolver::addFunctionReference(unsigned Address, Function *F) {
- LazyCodeGenMap[Address] = F;
- return (intptr_t)&JITResolver::CompilationCallback;
-}
-
-unsigned JITResolver::resolveFunctionReference(unsigned RetAddr) {
- std::map<unsigned, Function*>::iterator I = LazyCodeGenMap.find(RetAddr);
- assert(I != LazyCodeGenMap.end() && "Not in map!");
- Function *F = I->second;
- LazyCodeGenMap.erase(I);
- return MCE.forceCompilationOf(F);
-}
-
-unsigned JITResolver::getLazyResolver(Function *F) {
- std::map<Function*, unsigned>::iterator I = LazyResolverMap.lower_bound(F);
- if (I != LazyResolverMap.end() && I->first == F) return I->second;
-
-//std::cerr << "Getting lazy resolver for : " << ((Value*)F)->getName() << "\n";
-
- unsigned Stub = emitStubForFunction(F);
- LazyResolverMap.insert(I, std::make_pair(F, Stub));
- return Stub;
-}
-
-void JITResolver::CompilationCallback() {
- unsigned *StackPtr = (unsigned*)__builtin_frame_address(0);
- unsigned RetAddr = (unsigned)(intptr_t)__builtin_return_address(0);
- assert(StackPtr[1] == RetAddr &&
- "Could not find return address on the stack!");
-
- // It's a stub if there is an interrupt marker after the call...
- bool isStub = ((unsigned char*)(intptr_t)RetAddr)[0] == 0xCD;
-
- // FIXME FIXME FIXME FIXME: __builtin_frame_address doesn't work if frame
- // pointer elimination has been performed. Having a variable sized alloca
- // disables frame pointer elimination currently, even if it's dead. This is a
- // gross hack.
- alloca(10+isStub);
- // FIXME FIXME FIXME FIXME
-
- // The call instruction should have pushed the return value onto the stack...
- RetAddr -= 4; // Backtrack to the reference itself...
-
-#if 0
- DEBUG(std::cerr << "In callback! Addr=0x" << std::hex << RetAddr
- << " ESP=0x" << (unsigned)StackPtr << std::dec
- << ": Resolving call to function: "
- << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n");
-#endif
-
- // Sanity check to make sure this really is a call instruction...
- assert(((unsigned char*)(intptr_t)RetAddr)[-1] == 0xE8 &&"Not a call instr!");
-
- JITResolver &JR = getResolver(*(MachineCodeEmitter*)0);
- unsigned NewVal = JR.resolveFunctionReference(RetAddr);
-
- // Rewrite the call target... so that we don't fault every time we execute
- // the call.
- *(unsigned*)(intptr_t)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*)(intptr_t)RetAddr)[-1] = 0xE9;
- }
-
- // Change the return address to reexecute the call instruction...
- StackPtr[1] -= 5;
-}
-
-/// emitStubForFunction - This 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.
-///
-unsigned JITResolver::emitStubForFunction(Function *F) {
- MCE.startFunctionStub(*F, 6);
- MCE.emitByte(0xE8); // Call with 32 bit pc-rel destination...
-
- unsigned Address = addFunctionReference(MCE.getCurrentPCValue(), F);
- MCE.emitWord(Address-MCE.getCurrentPCValue()-4);
-
- MCE.emitByte(0xCD); // Interrupt - Just a marker identifying the stub!
- return (intptr_t)MCE.finishFunctionStub(*F);
-}
-
-