diff --git a/include/llvm/CodeGen/JITCodeEmitter.h b/include/llvm/CodeGen/JITCodeEmitter.h index ea3e59beab0..9c4e5b96707 100644 --- a/include/llvm/CodeGen/JITCodeEmitter.h +++ b/include/llvm/CodeGen/JITCodeEmitter.h @@ -68,29 +68,11 @@ public: /// virtual bool finishFunction(MachineFunction &F) = 0; - /// startGVStub - This callback is invoked when the JIT needs the address of a - /// GV (e.g. function) that has not been code generated yet. The StubSize - /// specifies the total size required by the stub. The BufferState must be - /// passed to finishGVStub, and start/finish pairs with the same BufferState - /// must be properly nested. - /// - virtual void startGVStub(BufferState &BS, const GlobalValue* GV, - unsigned StubSize, unsigned Alignment = 1) = 0; - - /// startGVStub - This callback is invoked when the JIT needs the address of a - /// GV (e.g. function) that has not been code generated yet. Buffer points to - /// memory already allocated for this stub. The BufferState must be passed to - /// finishGVStub, and start/finish pairs with the same BufferState must be - /// properly nested. - /// - virtual void startGVStub(BufferState &BS, void *Buffer, - unsigned StubSize) = 0; - - /// finishGVStub - This callback is invoked to terminate a GV stub and returns - /// the start address of the stub. The BufferState must first have been - /// passed to startGVStub. - /// - virtual void *finishGVStub(BufferState &BS) = 0; + /// allocIndirectGV - Allocates and fills storage for an indirect + /// GlobalValue, and returns the address. + virtual void *allocIndirectGV(const GlobalValue *GV, + const uint8_t *Buffer, size_t Size, + unsigned Alignment) = 0; /// emitByte - This callback is invoked when a byte needs to be written to the /// output stream. diff --git a/include/llvm/CodeGen/MachineCodeEmitter.h b/include/llvm/CodeGen/MachineCodeEmitter.h index 791db003ead..d598a9387ae 100644 --- a/include/llvm/CodeGen/MachineCodeEmitter.h +++ b/include/llvm/CodeGen/MachineCodeEmitter.h @@ -48,41 +48,16 @@ class Function; /// occurred, more memory is allocated, and we reemit the code into it. /// class MachineCodeEmitter { -public: - class BufferState { - friend class MachineCodeEmitter; - /// BufferBegin/BufferEnd - Pointers to the start and end of the memory - /// allocated for this code buffer. - uint8_t *BufferBegin, *BufferEnd; - - /// CurBufferPtr - Pointer to the next byte of memory to fill when emitting - /// code. This is guranteed to be in the range [BufferBegin,BufferEnd]. If - /// this pointer is at BufferEnd, it will never move due to code emission, - /// and all code emission requests will be ignored (this is the buffer - /// overflow condition). - uint8_t *CurBufferPtr; - public: - BufferState() : BufferBegin(NULL), BufferEnd(NULL), CurBufferPtr(NULL) {} - }; - protected: - /// These have the same meanings as the fields in BufferState - uint8_t *BufferBegin, *BufferEnd, *CurBufferPtr; - - /// Save or restore the current buffer state. The BufferState objects must be - /// used as a stack. - void SaveStateTo(BufferState &BS) { - assert(BS.BufferBegin == NULL && - "Can't save state into the same BufferState twice."); - BS.BufferBegin = BufferBegin; - BS.BufferEnd = BufferEnd; - BS.CurBufferPtr = CurBufferPtr; - } - void RestoreStateFrom(BufferState &BS) { - BufferBegin = BS.BufferBegin; - BufferEnd = BS.BufferEnd; - CurBufferPtr = BS.CurBufferPtr; - } + /// BufferBegin/BufferEnd - Pointers to the start and end of the memory + /// allocated for this code buffer. + uint8_t *BufferBegin, *BufferEnd; + /// CurBufferPtr - Pointer to the next byte of memory to fill when emitting + /// code. This is guranteed to be in the range [BufferBegin,BufferEnd]. If + /// this pointer is at BufferEnd, it will never move due to code emission, and + /// all code emission requests will be ignored (this is the buffer overflow + /// condition). + uint8_t *CurBufferPtr; public: virtual ~MachineCodeEmitter() {} @@ -113,15 +88,23 @@ public: /// void emitWordLE(uint32_t W) { if (4 <= BufferEnd-CurBufferPtr) { - *CurBufferPtr++ = (uint8_t)(W >> 0); - *CurBufferPtr++ = (uint8_t)(W >> 8); - *CurBufferPtr++ = (uint8_t)(W >> 16); - *CurBufferPtr++ = (uint8_t)(W >> 24); + emitWordLEInto(CurBufferPtr, W); } else { CurBufferPtr = BufferEnd; } } - + + /// emitWordLEInto - This callback is invoked when a 32-bit word needs to be + /// written to an arbitrary buffer in little-endian format. Buf must have at + /// least 4 bytes of available space. + /// + static void emitWordLEInto(uint8_t *&Buf, uint32_t W) { + *Buf++ = (uint8_t)(W >> 0); + *Buf++ = (uint8_t)(W >> 8); + *Buf++ = (uint8_t)(W >> 16); + *Buf++ = (uint8_t)(W >> 24); + } + /// emitWordBE - This callback is invoked when a 32-bit word needs to be /// written to the output stream in big-endian format. /// diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index bbac762b459..a670772b06d 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -271,6 +271,10 @@ namespace { class JITEmitter : public JITCodeEmitter { JITMemoryManager *MemMgr; + // When outputting a function stub in the context of some other function, we + // save BufferBegin/BufferEnd/CurBufferPtr here. + uint8_t *SavedBufferBegin, *SavedBufferEnd, *SavedCurBufferPtr; + // When reattempting to JIT a function after running out of space, we store // the estimated size of the function we're trying to JIT here, so we can // ask the memory manager for at least this much space. When we @@ -396,11 +400,13 @@ namespace { void initJumpTableInfo(MachineJumpTableInfo *MJTI); void emitJumpTableInfo(MachineJumpTableInfo *MJTI); - virtual void startGVStub(BufferState &BS, const GlobalValue* GV, - unsigned StubSize, unsigned Alignment = 1); - virtual void startGVStub(BufferState &BS, void *Buffer, - unsigned StubSize); - virtual void* finishGVStub(BufferState &BS); + void startGVStub(const GlobalValue* GV, + unsigned StubSize, unsigned Alignment = 1); + void startGVStub(void *Buffer, unsigned StubSize); + void finishGVStub(); + virtual void *allocIndirectGV(const GlobalValue *GV, + const uint8_t *Buffer, size_t Size, + unsigned Alignment); /// allocateSpace - Reserves space in the current block if any, or /// allocate a new one of the given size. @@ -521,13 +527,12 @@ void *JITResolver::getLazyFunctionStub(Function *F) { if (!Actual) return 0; } - MachineCodeEmitter::BufferState BS; TargetJITInfo::StubLayout SL = TheJIT->getJITInfo().getStubLayout(); - JE.startGVStub(BS, F, SL.Size, SL.Alignment); + JE.startGVStub(F, SL.Size, SL.Alignment); // Codegen a new stub, calling the lazy resolver or the actual address of the // external function, if it was resolved. Stub = TheJIT->getJITInfo().emitFunctionStub(F, Actual, JE); - JE.finishGVStub(BS); + JE.finishGVStub(); if (Actual != (void*)(intptr_t)LazyResolverFn) { // If we are getting the stub for an external function, we really want the @@ -579,11 +584,10 @@ void *JITResolver::getExternalFunctionStub(void *FnAddr) { void *&Stub = ExternalFnToStubMap[FnAddr]; if (Stub) return Stub; - MachineCodeEmitter::BufferState BS; TargetJITInfo::StubLayout SL = TheJIT->getJITInfo().getStubLayout(); - JE.startGVStub(BS, 0, SL.Size, SL.Alignment); + JE.startGVStub(0, SL.Size, SL.Alignment); Stub = TheJIT->getJITInfo().emitFunctionStub(0, FnAddr, JE); - JE.finishGVStub(BS); + JE.finishGVStub(); DEBUG(errs() << "JIT: Stub emitted at [" << Stub << "] for external function at '" << FnAddr << "'\n"); @@ -1215,8 +1219,9 @@ bool JITEmitter::finishFunction(MachineFunction &F) { if (DwarfExceptionHandling || JITEmitDebugInfo) { uintptr_t ActualSize = 0; - BufferState BS; - SaveStateTo(BS); + SavedBufferBegin = BufferBegin; + SavedBufferEnd = BufferEnd; + SavedCurBufferPtr = CurBufferPtr; if (MemMgr->NeedsExactSize()) { ActualSize = DE->GetDwarfTableSizeInBytes(F, *this, FnStart, FnEnd); @@ -1232,7 +1237,9 @@ bool JITEmitter::finishFunction(MachineFunction &F) { MemMgr->endExceptionTable(F.getFunction(), BufferBegin, CurBufferPtr, FrameRegister); uint8_t *EhEnd = CurBufferPtr; - RestoreStateFrom(BS); + BufferBegin = SavedBufferBegin; + BufferEnd = SavedBufferEnd; + CurBufferPtr = SavedCurBufferPtr; if (DwarfExceptionHandling) { TheJIT->RegisterTable(FrameRegister); @@ -1438,27 +1445,39 @@ void JITEmitter::emitJumpTableInfo(MachineJumpTableInfo *MJTI) { } } -void JITEmitter::startGVStub(BufferState &BS, const GlobalValue* GV, +void JITEmitter::startGVStub(const GlobalValue* GV, unsigned StubSize, unsigned Alignment) { - SaveStateTo(BS); + SavedBufferBegin = BufferBegin; + SavedBufferEnd = BufferEnd; + SavedCurBufferPtr = CurBufferPtr; BufferBegin = CurBufferPtr = MemMgr->allocateStub(GV, StubSize, Alignment); BufferEnd = BufferBegin+StubSize+1; } -void JITEmitter::startGVStub(BufferState &BS, void *Buffer, unsigned StubSize) { - SaveStateTo(BS); +void JITEmitter::startGVStub(void *Buffer, unsigned StubSize) { + SavedBufferBegin = BufferBegin; + SavedBufferEnd = BufferEnd; + SavedCurBufferPtr = CurBufferPtr; BufferBegin = CurBufferPtr = (uint8_t *)Buffer; BufferEnd = BufferBegin+StubSize+1; } -void *JITEmitter::finishGVStub(BufferState &BS) { +void JITEmitter::finishGVStub() { assert(CurBufferPtr != BufferEnd && "Stub overflowed allocated space."); NumBytes += getCurrentPCOffset(); - void *Result = BufferBegin; - RestoreStateFrom(BS); - return Result; + BufferBegin = SavedBufferBegin; + BufferEnd = SavedBufferEnd; + CurBufferPtr = SavedCurBufferPtr; +} + +void *JITEmitter::allocIndirectGV(const GlobalValue *GV, + const uint8_t *Buffer, size_t Size, + unsigned Alignment) { + uint8_t *IndGV = MemMgr->allocateStub(GV, Size, Alignment); + memcpy(IndGV, Buffer, Size); + return IndGV; } // getConstantPoolEntryAddress - Return the address of the 'ConstantNum' entry @@ -1546,11 +1565,10 @@ void JIT::updateFunctionStub(Function *F) { // Tell the target jit info to rewrite the stub at the specified address, // rather than creating a new one. - MachineCodeEmitter::BufferState BS; TargetJITInfo::StubLayout layout = getJITInfo().getStubLayout(); - JE->startGVStub(BS, Stub, layout.Size); + JE->startGVStub(Stub, layout.Size); getJITInfo().emitFunctionStub(F, Addr, *getCodeEmitter()); - JE->finishGVStub(BS); + JE->finishGVStub(); } /// freeMachineCodeForFunction - release machine code memory for given Function. diff --git a/lib/Target/ARM/ARMJITInfo.cpp b/lib/Target/ARM/ARMJITInfo.cpp index aa50cfd3074..bef5a0612f4 100644 --- a/lib/Target/ARM/ARMJITInfo.cpp +++ b/lib/Target/ARM/ARMJITInfo.cpp @@ -139,17 +139,11 @@ ARMJITInfo::getLazyResolverFunction(JITCompilerFn F) { void *ARMJITInfo::emitGlobalValueIndirectSym(const GlobalValue *GV, void *Ptr, JITCodeEmitter &JCE) { - MachineCodeEmitter::BufferState BS; - JCE.startGVStub(BS, GV, 4, 4); - intptr_t Addr = (intptr_t)JCE.getCurrentPCValue(); - if (!sys::Memory::setRangeWritable((void*)Addr, 4)) { - llvm_unreachable("ERROR: Unable to mark indirect symbol writable"); - } - JCE.emitWordLE((intptr_t)Ptr); - if (!sys::Memory::setRangeExecutable((void*)Addr, 4)) { - llvm_unreachable("ERROR: Unable to mark indirect symbol executable"); - } - void *PtrAddr = JCE.finishGVStub(BS); + uint8_t Buffer[4]; + uint8_t *Cur = Buffer; + MachineCodeEmitter::emitWordLEInto(Cur, (intptr_t)Ptr); + void *PtrAddr = JCE.allocIndirectGV( + GV, Buffer, sizeof(Buffer), /*Alignment=*/4); addIndirectSymAddr(Ptr, (intptr_t)PtrAddr); return PtrAddr; } diff --git a/lib/Target/Alpha/AlphaJITInfo.cpp b/lib/Target/Alpha/AlphaJITInfo.cpp index b3b711eea98..cb8eb514656 100644 --- a/lib/Target/Alpha/AlphaJITInfo.cpp +++ b/lib/Target/Alpha/AlphaJITInfo.cpp @@ -202,7 +202,6 @@ TargetJITInfo::StubLayout AlphaJITInfo::getStubLayout() { void *AlphaJITInfo::emitFunctionStub(const Function* F, void *Fn, JITCodeEmitter &JCE) { - MachineCodeEmitter::BufferState BS; //assert(Fn == AlphaCompilationCallback && "Where are you going?\n"); //Do things in a stupid slow way! void* Addr = (void*)(intptr_t)JCE.getCurrentPCValue(); diff --git a/lib/Target/PowerPC/PPCJITInfo.cpp b/lib/Target/PowerPC/PPCJITInfo.cpp index c679bcdf58b..be6e51e0ddb 100644 --- a/lib/Target/PowerPC/PPCJITInfo.cpp +++ b/lib/Target/PowerPC/PPCJITInfo.cpp @@ -339,7 +339,6 @@ extern "C" void sys_icache_invalidate(const void *Addr, size_t len); void *PPCJITInfo::emitFunctionStub(const Function* F, void *Fn, JITCodeEmitter &JCE) { - MachineCodeEmitter::BufferState BS; // If this is just a call to an external function, emit a branch instead of a // call. The code is the same except for one bit of the last instruction. if (Fn != (void*)(intptr_t)PPC32CompilationCallback && diff --git a/lib/Target/X86/X86JITInfo.cpp b/lib/Target/X86/X86JITInfo.cpp index ce06f0fdebe..c69cc83df6b 100644 --- a/lib/Target/X86/X86JITInfo.cpp +++ b/lib/Target/X86/X86JITInfo.cpp @@ -426,16 +426,19 @@ X86JITInfo::X86JITInfo(X86TargetMachine &tm) : TM(tm) { void *X86JITInfo::emitGlobalValueIndirectSym(const GlobalValue* GV, void *ptr, JITCodeEmitter &JCE) { - MachineCodeEmitter::BufferState BS; #if defined (X86_64_JIT) - JCE.startGVStub(BS, GV, 8, 8); - JCE.emitWordLE((unsigned)(intptr_t)ptr); - JCE.emitWordLE((unsigned)(((intptr_t)ptr) >> 32)); + const unsigned Alignment = 8; + uint8_t Buffer[8]; + uint8_t *Cur = Buffer; + MachineCodeEmitter::emitWordLEInto(Cur, (unsigned)(intptr_t)ptr); + MachineCodeEmitter::emitWordLEInto(Cur, (unsigned)(((intptr_t)ptr) >> 32)); #else - JCE.startGVStub(BS, GV, 4, 4); - JCE.emitWordLE((intptr_t)ptr); + const unsigned Alignment = 4; + uint8_t Buffer[4]; + uint8_t *Cur = Buffer; + MachineCodeEmitter::emitWordLEInto(Cur, (intptr_t)ptr); #endif - return JCE.finishGVStub(BS); + return JCE.allocIndirectGV(GV, Buffer, sizeof(Buffer), Alignment); } TargetJITInfo::StubLayout X86JITInfo::getStubLayout() { @@ -451,7 +454,6 @@ TargetJITInfo::StubLayout X86JITInfo::getStubLayout() { void *X86JITInfo::emitFunctionStub(const Function* F, void *Target, JITCodeEmitter &JCE) { - MachineCodeEmitter::BufferState BS; // Note, we cast to intptr_t here to silence a -pedantic warning that // complains about casting a function pointer to a normal pointer. #if defined (X86_32_JIT) && !defined (_MSC_VER)