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); |
Andrew Kaylor | e3fd646 | 2013-10-04 20:09:36 +0000 | [diff] [blame] | 39 | // AllocatedSections will own this memory. |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 40 | AllocatedSections.push_back( Allocation(Block, Alignment, true) ); |
Andrew Kaylor | e3fd646 | 2013-10-04 20:09:36 +0000 | [diff] [blame] | 41 | // UnmappedSections has the same information but does not own the memory. |
| 42 | UnmappedSections.push_back( Allocation(Block, Alignment, true) ); |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 43 | return (uint8_t*)Block.base(); |
| 44 | } |
| 45 | |
| 46 | uint8_t *RemoteMemoryManager:: |
| 47 | allocateDataSection(uintptr_t Size, unsigned Alignment, |
| 48 | unsigned SectionID, StringRef SectionName, |
| 49 | bool IsReadOnly) { |
| 50 | // The recording memory manager is just a local copy of the remote target. |
| 51 | // The alignment requirement is just stored here for later use. Regular |
| 52 | // heap storage is sufficient here, but we're using mapped memory to work |
| 53 | // around a bug in MCJIT. |
| 54 | sys::MemoryBlock Block = allocateSection(Size); |
Andrew Kaylor | e3fd646 | 2013-10-04 20:09:36 +0000 | [diff] [blame] | 55 | // AllocatedSections will own this memory. |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 56 | AllocatedSections.push_back( Allocation(Block, Alignment, false) ); |
Andrew Kaylor | e3fd646 | 2013-10-04 20:09:36 +0000 | [diff] [blame] | 57 | // UnmappedSections has the same information but does not own the memory. |
| 58 | UnmappedSections.push_back( Allocation(Block, Alignment, false) ); |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 59 | return (uint8_t*)Block.base(); |
| 60 | } |
| 61 | |
| 62 | sys::MemoryBlock RemoteMemoryManager::allocateSection(uintptr_t Size) { |
| 63 | error_code ec; |
| 64 | sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size, |
| 65 | &Near, |
| 66 | sys::Memory::MF_READ | |
| 67 | sys::Memory::MF_WRITE, |
| 68 | ec); |
| 69 | assert(!ec && MB.base()); |
| 70 | |
| 71 | // FIXME: This is part of a work around to keep sections near one another |
| 72 | // when MCJIT performs relocations after code emission but before |
| 73 | // the generated code is moved to the remote target. |
| 74 | // Save this address as the basis for our next request |
| 75 | Near = MB; |
| 76 | return MB; |
| 77 | } |
| 78 | |
| 79 | void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE, |
| 80 | const ObjectImage *Obj) { |
| 81 | // The client should have called setRemoteTarget() before triggering any |
| 82 | // code generation. |
| 83 | assert(Target); |
| 84 | if (!Target) |
| 85 | return; |
| 86 | |
| 87 | // FIXME: Make this function thread safe. |
| 88 | |
| 89 | // Lay out our sections in order, with all the code sections first, then |
| 90 | // all the data sections. |
| 91 | uint64_t CurOffset = 0; |
| 92 | unsigned MaxAlign = Target->getPageAlignment(); |
Andrew Kaylor | 36ea408 | 2013-10-04 20:53:49 +0000 | [diff] [blame] | 93 | SmallVector<std::pair<Allocation, uint64_t>, 16> Offsets; |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 94 | unsigned NumSections = UnmappedSections.size(); |
| 95 | // We're going to go through the list twice to separate code and data, but |
| 96 | // it's a very small list, so that's OK. |
| 97 | for (size_t i = 0, e = NumSections; i != e; ++i) { |
Andrew Kaylor | e3fd646 | 2013-10-04 20:09:36 +0000 | [diff] [blame] | 98 | Allocation &Section = UnmappedSections[i]; |
| 99 | if (Section.IsCode) { |
| 100 | unsigned Size = Section.MB.size(); |
| 101 | unsigned Align = Section.Alignment; |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 102 | DEBUG(dbgs() << "code region: size " << Size |
| 103 | << ", alignment " << Align << "\n"); |
| 104 | // Align the current offset up to whatever is needed for the next |
| 105 | // section. |
| 106 | CurOffset = (CurOffset + Align - 1) / Align * Align; |
| 107 | // Save off the address of the new section and allocate its space. |
Andrew Kaylor | 36ea408 | 2013-10-04 20:53:49 +0000 | [diff] [blame] | 108 | Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset)); |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 109 | CurOffset += Size; |
| 110 | } |
| 111 | } |
| 112 | // Adjust to keep code and data aligned on seperate pages. |
| 113 | CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign; |
| 114 | for (size_t i = 0, e = NumSections; i != e; ++i) { |
Andrew Kaylor | e3fd646 | 2013-10-04 20:09:36 +0000 | [diff] [blame] | 115 | Allocation &Section = UnmappedSections[i]; |
| 116 | if (!Section.IsCode) { |
| 117 | unsigned Size = Section.MB.size(); |
| 118 | unsigned Align = Section.Alignment; |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 119 | DEBUG(dbgs() << "data region: size " << Size |
| 120 | << ", alignment " << Align << "\n"); |
| 121 | // Align the current offset up to whatever is needed for the next |
| 122 | // section. |
| 123 | CurOffset = (CurOffset + Align - 1) / Align * Align; |
| 124 | // Save off the address of the new section and allocate its space. |
Andrew Kaylor | 36ea408 | 2013-10-04 20:53:49 +0000 | [diff] [blame] | 125 | Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset)); |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 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; |
Andrew Kaylor | e3fd646 | 2013-10-04 20:09:36 +0000 | [diff] [blame] | 139 | EE->mapSectionAddress(const_cast<void*>(Offsets[i].first.MB.base()), Addr); |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 140 | |
Andrew Kaylor | e3fd646 | 2013-10-04 20:09:36 +0000 | [diff] [blame] | 141 | DEBUG(dbgs() << " Mapping local: " << Offsets[i].first.MB.base() |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 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. |
Andrew Kaylor | e3fd646 | 2013-10-04 20:09:36 +0000 | [diff] [blame] | 152 | for (DenseMap<uint64_t, Allocation>::iterator |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 153 | I = MappedSections.begin(), E = MappedSections.end(); |
| 154 | I != E; ++I) { |
| 155 | uint64_t RemoteAddr = I->first; |
Andrew Kaylor | e3fd646 | 2013-10-04 20:09:36 +0000 | [diff] [blame] | 156 | const Allocation &Section = I->second; |
| 157 | if (Section.IsCode) { |
| 158 | Target->loadCode(RemoteAddr, Section.MB.base(), Section.MB.size()); |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 159 | |
Andrew Kaylor | e3fd646 | 2013-10-04 20:09:36 +0000 | [diff] [blame] | 160 | DEBUG(dbgs() << " loading code: " << Section.MB.base() |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 161 | << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); |
| 162 | } else { |
Andrew Kaylor | e3fd646 | 2013-10-04 20:09:36 +0000 | [diff] [blame] | 163 | Target->loadData(RemoteAddr, Section.MB.base(), Section.MB.size()); |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 164 | |
Andrew Kaylor | e3fd646 | 2013-10-04 20:09:36 +0000 | [diff] [blame] | 165 | DEBUG(dbgs() << " loading data: " << Section.MB.base() |
Andrew Kaylor | b868e91 | 2013-10-04 00:49:38 +0000 | [diff] [blame] | 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 | } |