[llvm-commits] CVS: llvm/tools/lli/JIT/Callback.cpp Emitter.cpp VM.cpp VM.h

Chris Lattner lattner at cs.uiuc.edu
Thu May 8 22:31:01 PDT 2003


Changes in directory llvm/tools/lli/JIT:

Callback.cpp updated: 1.4 -> 1.5
Emitter.cpp updated: 1.5 -> 1.6
VM.cpp updated: 1.3 -> 1.4
VM.h updated: 1.3 -> 1.4

---
Log message:

Add support for function stubs, which allow calling functions which need to
have an address available, but have not yet been code generated.


---
Diffs of the changes:

Index: llvm/tools/lli/JIT/Callback.cpp
diff -u llvm/tools/lli/JIT/Callback.cpp:1.4 llvm/tools/lli/JIT/Callback.cpp:1.5
--- llvm/tools/lli/JIT/Callback.cpp:1.4	Thu May  8 16:44:21 2003
+++ llvm/tools/lli/JIT/Callback.cpp	Thu May  8 22:30:07 2003
@@ -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 @@
 
   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,8 +42,34 @@
   // 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
+  abort();
+#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


Index: llvm/tools/lli/JIT/Emitter.cpp
diff -u llvm/tools/lli/JIT/Emitter.cpp:1.5 llvm/tools/lli/JIT/Emitter.cpp:1.6
--- llvm/tools/lli/JIT/Emitter.cpp:1.5	Thu May  8 16:44:21 2003
+++ llvm/tools/lli/JIT/Emitter.cpp	Thu May  8 22:30:07 2003
@@ -19,8 +19,11 @@
   class Emitter : public MachineCodeEmitter {
     VM &TheVM;
 
-    unsigned char *CurBlock;
-    unsigned char *CurByte;
+    unsigned char *CurBlock, *CurByte;
+
+    // When outputting a function stub in the context of some other function, we
+    // save CurBlock and CurByte here.
+    unsigned char *SavedCurBlock, *SavedCurByte;
     
     std::vector<std::pair<BasicBlock*, unsigned *> > BBRefs;
     std::map<BasicBlock*, unsigned> BBLocations;
@@ -32,6 +35,8 @@
     virtual void finishFunction(MachineFunction &F);
     virtual void emitConstantPool(MachineConstantPool *MCP);
     virtual void startBasicBlock(MachineBasicBlock &BB);
+    virtual void startFunctionStub(const Function &F, unsigned StubSize);
+    virtual void* finishFunctionStub(const Function &F);
     virtual void emitByte(unsigned char B);
     virtual void emitPCRelativeDisp(Value *V);
     virtual void emitGlobalAddress(GlobalValue *V, bool isPCRelative);
@@ -52,14 +57,16 @@
 #include <unistd.h>
 #include <sys/mman.h>
 
-static void *getMemory() {
-  return mmap(0, 4096*8, PROT_READ|PROT_WRITE|PROT_EXEC,
+// FIXME: This should be rewritten to support a real memory manager for
+// executable memory pages!
+static void *getMemory(unsigned NumPages) {
+  return mmap(0, 4096*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC,
               MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
 }
 
 
 void Emitter::startFunction(MachineFunction &F) {
-  CurBlock = (unsigned char *)getMemory();
+  CurBlock = (unsigned char *)getMemory(8);
   CurByte = CurBlock;  // Start writing at the beginning of the fn.
   TheVM.addGlobalMapping(F.getFunction(), CurBlock);
 }
@@ -99,6 +106,24 @@
   BBLocations[BB.getBasicBlock()] = (unsigned)(intptr_t)CurByte;
 }
 
+
+void Emitter::startFunctionStub(const Function &F, unsigned StubSize) {
+  SavedCurBlock = CurBlock;  SavedCurByte = CurByte;
+  // FIXME: this is a huge waste of memory.
+  CurBlock = (unsigned char *)getMemory((StubSize+4095)/4096);
+  CurByte = CurBlock;  // Start writing at the beginning of the fn.
+}
+
+void *Emitter::finishFunctionStub(const Function &F) {
+  NumBytes += CurByte-CurBlock;
+  DEBUG(std::cerr << "Finished CodeGen of [0x" << std::hex
+                  << (unsigned)(intptr_t)CurBlock
+                  << std::dec << "] Function stub for: " << F.getName()
+                  << ": " << CurByte-CurBlock << " bytes of text\n");
+  std::swap(CurBlock, SavedCurBlock);
+  CurByte = SavedCurByte;
+  return SavedCurBlock;
+}
 
 void Emitter::emitByte(unsigned char B) {
   *CurByte++ = B;   // Write the byte to memory


Index: llvm/tools/lli/JIT/VM.cpp
diff -u llvm/tools/lli/JIT/VM.cpp:1.3 llvm/tools/lli/JIT/VM.cpp:1.4
--- llvm/tools/lli/JIT/VM.cpp:1.3	Thu May  8 16:08:43 2003
+++ llvm/tools/lli/JIT/VM.cpp	Thu May  8 22:30:07 2003
@@ -83,7 +83,10 @@
 
   static bool isAlreadyCodeGenerating = false;
   if (isAlreadyCodeGenerating) {
-    assert(0 && "Recursive function stubs not handled yet!");
+    // Generate a function stub instead of reentering...
+    void *SAddr = emitStubForFunction(*F);
+    assert(SAddr && "Target machine doesn't support function stub generation!");
+    return SAddr;
   }
 
   // FIXME: JIT all of the functions in the module.  Eventually this will JIT


Index: llvm/tools/lli/JIT/VM.h
diff -u llvm/tools/lli/JIT/VM.h:1.3 llvm/tools/lli/JIT/VM.h:1.4
--- llvm/tools/lli/JIT/VM.h:1.3	Thu May  8 16:34:11 2003
+++ llvm/tools/lli/JIT/VM.h	Thu May  8 22:30:07 2003
@@ -60,6 +60,14 @@
   void *getPointerToFunction(const Function *F);
 
   void registerCallback();
+
+  /// 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.
+  ///
+  void *emitStubForFunction(const Function &F);
 };
 
 #endif





More information about the llvm-commits mailing list