Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame^] | 1 | //===---- RemoteMemoryManager.cpp - Recording memory manager --------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This memory manager allocates local storage and keeps a record of each |
| 11 | // allocation. Iterators are provided for all data and code allocations. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #define DEBUG_TYPE "lli" |
| 16 | #include "RemoteMemoryManager.h" |
| 17 | #include "llvm/ExecutionEngine/ExecutionEngine.h" |
| 18 | #include "llvm/ExecutionEngine/ObjectImage.h" |
| 19 | #include "llvm/Support/Debug.h" |
| 20 | #include "llvm/Support/Format.h" |
| 21 | |
| 22 | using namespace llvm; |
| 23 | |
| 24 | RemoteMemoryManager::~RemoteMemoryManager() { |
| 25 | for (SmallVector<Allocation, 2>::iterator |
| 26 | I = AllocatedSections.begin(), E = AllocatedSections.end(); |
| 27 | I != E; ++I) |
| 28 | sys::Memory::releaseMappedMemory(I->MB); |
| 29 | } |
| 30 | |
| 31 | uint8_t *RemoteMemoryManager:: |
| 32 | allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, |
| 33 | StringRef SectionName) { |
| 34 | // The recording memory manager is just a local copy of the remote target. |
| 35 | // The alignment requirement is just stored here for later use. Regular |
| 36 | // heap storage is sufficient here, but we're using mapped memory to work |
| 37 | // around a bug in MCJIT. |
| 38 | sys::MemoryBlock Block = allocateSection(Size); |
| 39 | AllocatedSections.push_back( Allocation(Block, Alignment, true) ); |
| 40 | UnmappedSections.push_back( &AllocatedSections.back() ); |
| 41 | return (uint8_t*)Block.base(); |
| 42 | } |
| 43 | |
| 44 | uint8_t *RemoteMemoryManager:: |
| 45 | allocateDataSection(uintptr_t Size, unsigned Alignment, |
| 46 | unsigned SectionID, StringRef SectionName, |
| 47 | bool IsReadOnly) { |
| 48 | // The recording memory manager is just a local copy of the remote target. |
| 49 | // The alignment requirement is just stored here for later use. Regular |
| 50 | // heap storage is sufficient here, but we're using mapped memory to work |
| 51 | // around a bug in MCJIT. |
| 52 | sys::MemoryBlock Block = allocateSection(Size); |
| 53 | AllocatedSections.push_back( Allocation(Block, Alignment, false) ); |
| 54 | UnmappedSections.push_back( &AllocatedSections.back() ); |
| 55 | return (uint8_t*)Block.base(); |
| 56 | } |
| 57 | |
| 58 | sys::MemoryBlock RemoteMemoryManager::allocateSection(uintptr_t Size) { |
| 59 | error_code ec; |
| 60 | sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size, |
| 61 | &Near, |
| 62 | sys::Memory::MF_READ | |
| 63 | sys::Memory::MF_WRITE, |
| 64 | ec); |
| 65 | assert(!ec && MB.base()); |
| 66 | |
| 67 | // FIXME: This is part of a work around to keep sections near one another |
| 68 | // when MCJIT performs relocations after code emission but before |
| 69 | // the generated code is moved to the remote target. |
| 70 | // Save this address as the basis for our next request |
| 71 | Near = MB; |
| 72 | return MB; |
| 73 | } |
| 74 | |
| 75 | void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE, |
| 76 | const ObjectImage *Obj) { |
| 77 | // The client should have called setRemoteTarget() before triggering any |
| 78 | // code generation. |
| 79 | assert(Target); |
| 80 | if (!Target) |
| 81 | return; |
| 82 | |
| 83 | // FIXME: Make this function thread safe. |
| 84 | |
| 85 | // Lay out our sections in order, with all the code sections first, then |
| 86 | // all the data sections. |
| 87 | uint64_t CurOffset = 0; |
| 88 | unsigned MaxAlign = Target->getPageAlignment(); |
| 89 | SmallVector<std::pair<const Allocation*, uint64_t>, 16> Offsets; |
| 90 | unsigned NumSections = UnmappedSections.size(); |
| 91 | // We're going to go through the list twice to separate code and data, but |
| 92 | // it's a very small list, so that's OK. |
| 93 | for (size_t i = 0, e = NumSections; i != e; ++i) { |
| 94 | const Allocation *Section = UnmappedSections[i]; |
| 95 | assert(Section); |
| 96 | if (Section->IsCode) { |
| 97 | unsigned Size = Section->MB.size(); |
| 98 | unsigned Align = Section->Alignment; |
| 99 | DEBUG(dbgs() << "code region: size " << Size |
| 100 | << ", alignment " << Align << "\n"); |
| 101 | // Align the current offset up to whatever is needed for the next |
| 102 | // section. |
| 103 | CurOffset = (CurOffset + Align - 1) / Align * Align; |
| 104 | // Save off the address of the new section and allocate its space. |
| 105 | Offsets.push_back(std::pair<const Allocation*,uint64_t>(Section, |
| 106 | CurOffset)); |
| 107 | CurOffset += Size; |
| 108 | } |
| 109 | } |
| 110 | // Adjust to keep code and data aligned on seperate pages. |
| 111 | CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign; |
| 112 | for (size_t i = 0, e = NumSections; i != e; ++i) { |
| 113 | const Allocation *Section = UnmappedSections[i]; |
| 114 | assert(Section); |
| 115 | if (!Section->IsCode) { |
| 116 | unsigned Size = Section->MB.size(); |
| 117 | unsigned Align = Section->Alignment; |
| 118 | DEBUG(dbgs() << "data region: size " << Size |
| 119 | << ", alignment " << Align << "\n"); |
| 120 | // Align the current offset up to whatever is needed for the next |
| 121 | // section. |
| 122 | CurOffset = (CurOffset + Align - 1) / Align * Align; |
| 123 | // Save off the address of the new section and allocate its space. |
| 124 | Offsets.push_back(std::pair<const Allocation*,uint64_t>(Section, |
| 125 | CurOffset)); |
| 126 | CurOffset += Size; |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | // Allocate space in the remote target. |
| 131 | uint64_t RemoteAddr; |
| 132 | if (Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr)) |
| 133 | report_fatal_error(Target->getErrorMsg()); |
| 134 | |
| 135 | // Map the section addresses so relocations will get updated in the local |
| 136 | // copies of the sections. |
| 137 | for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { |
| 138 | uint64_t Addr = RemoteAddr + Offsets[i].second; |
| 139 | EE->mapSectionAddress(const_cast<void*>(Offsets[i].first->MB.base()), Addr); |
| 140 | |
| 141 | DEBUG(dbgs() << " Mapping local: " << Offsets[i].first->MB.base() |
| 142 | << " to remote: 0x" << format("%llx", Addr) << "\n"); |
| 143 | |
| 144 | MappedSections[Addr] = Offsets[i].first; |
| 145 | } |
| 146 | |
| 147 | UnmappedSections.clear(); |
| 148 | } |
| 149 | |
| 150 | bool RemoteMemoryManager::finalizeMemory(std::string *ErrMsg) { |
| 151 | // FIXME: Make this function thread safe. |
| 152 | for (DenseMap<uint64_t, const Allocation*>::iterator |
| 153 | I = MappedSections.begin(), E = MappedSections.end(); |
| 154 | I != E; ++I) { |
| 155 | uint64_t RemoteAddr = I->first; |
| 156 | const Allocation *Section = I->second; |
| 157 | if (Section->IsCode) { |
| 158 | Target->loadCode(RemoteAddr, Section->MB.base(), Section->MB.size()); |
| 159 | |
| 160 | DEBUG(dbgs() << " loading code: " << Section->MB.base() |
| 161 | << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); |
| 162 | } else { |
| 163 | Target->loadData(RemoteAddr, Section->MB.base(), Section->MB.size()); |
| 164 | |
| 165 | DEBUG(dbgs() << " loading data: " << Section->MB.base() |
| 166 | << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | MappedSections.clear(); |
| 171 | |
| 172 | return false; |
| 173 | } |
| 174 | |
| 175 | void RemoteMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); } |
| 176 | void RemoteMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); } |
| 177 | void RemoteMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); } |
| 178 | void RemoteMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); } |
| 179 | uint8_t *RemoteMemoryManager::getGOTBase() const { |
| 180 | llvm_unreachable("Unexpected!"); |
| 181 | return 0; |
| 182 | } |
| 183 | uint8_t *RemoteMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){ |
| 184 | llvm_unreachable("Unexpected!"); |
| 185 | return 0; |
| 186 | } |
| 187 | uint8_t *RemoteMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize, |
| 188 | unsigned Alignment) { |
| 189 | llvm_unreachable("Unexpected!"); |
| 190 | return 0; |
| 191 | } |
| 192 | void RemoteMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart, |
| 193 | uint8_t *FunctionEnd) { |
| 194 | llvm_unreachable("Unexpected!"); |
| 195 | } |
| 196 | uint8_t *RemoteMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) { |
| 197 | llvm_unreachable("Unexpected!"); |
| 198 | return 0; |
| 199 | } |
| 200 | uint8_t *RemoteMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) { |
| 201 | llvm_unreachable("Unexpected!"); |
| 202 | return 0; |
| 203 | } |
| 204 | void RemoteMemoryManager::deallocateFunctionBody(void *Body) { |
| 205 | llvm_unreachable("Unexpected!"); |
| 206 | } |
| 207 | |
| 208 | static int jit_noop() { |
| 209 | return 0; |
| 210 | } |
| 211 | |
| 212 | void *RemoteMemoryManager::getPointerToNamedFunction(const std::string &Name, |
| 213 | bool AbortOnFailure) { |
| 214 | // We should not invoke parent's ctors/dtors from generated main()! |
| 215 | // On Mingw and Cygwin, the symbol __main is resolved to |
| 216 | // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors |
| 217 | // (and register wrong callee's dtors with atexit(3)). |
| 218 | // We expect ExecutionEngine::runStaticConstructorsDestructors() |
| 219 | // is called before ExecutionEngine::runFunctionAsMain() is called. |
| 220 | if (Name == "__main") return (void*)(intptr_t)&jit_noop; |
| 221 | |
| 222 | // FIXME: Would it be responsible to provide GOT? |
| 223 | if (AbortOnFailure) { |
| 224 | if (Name == "_GLOBAL_OFFSET_TABLE_") |
| 225 | report_fatal_error("Program used external function '" + Name + |
| 226 | "' which could not be resolved!"); |
| 227 | } |
| 228 | |
| 229 | return NULL; |
| 230 | } |