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 #include "RemoteMemoryManager.h"
16 #include "llvm/ExecutionEngine/ExecutionEngine.h"
17 #include "llvm/Support/Debug.h"
18 #include "llvm/Support/Format.h"
19 #include "llvm/Support/raw_ostream.h"
20
21 using namespace llvm;
22
23 #define DEBUG_TYPE "lli"
24
~RemoteMemoryManager()25 RemoteMemoryManager::~RemoteMemoryManager() {
26 for (SmallVector<Allocation, 2>::iterator
27 I = AllocatedSections.begin(), E = AllocatedSections.end();
28 I != E; ++I)
29 sys::Memory::releaseMappedMemory(I->MB);
30 }
31
32 uint8_t *RemoteMemoryManager::
allocateCodeSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName)33 allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID,
34 StringRef SectionName) {
35 // The recording memory manager is just a local copy of the remote target.
36 // The alignment requirement is just stored here for later use. Regular
37 // heap storage is sufficient here, but we're using mapped memory to work
38 // around a bug in MCJIT.
39 sys::MemoryBlock Block = allocateSection(Size);
40 // AllocatedSections will own this memory.
41 AllocatedSections.push_back( Allocation(Block, Alignment, true) );
42 // UnmappedSections has the same information but does not own the memory.
43 UnmappedSections.push_back( Allocation(Block, Alignment, true) );
44 return (uint8_t*)Block.base();
45 }
46
47 uint8_t *RemoteMemoryManager::
allocateDataSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName,bool IsReadOnly)48 allocateDataSection(uintptr_t Size, unsigned Alignment,
49 unsigned SectionID, StringRef SectionName,
50 bool IsReadOnly) {
51 // The recording memory manager is just a local copy of the remote target.
52 // The alignment requirement is just stored here for later use. Regular
53 // heap storage is sufficient here, but we're using mapped memory to work
54 // around a bug in MCJIT.
55 sys::MemoryBlock Block = allocateSection(Size);
56 // AllocatedSections will own this memory.
57 AllocatedSections.push_back( Allocation(Block, Alignment, false) );
58 // UnmappedSections has the same information but does not own the memory.
59 UnmappedSections.push_back( Allocation(Block, Alignment, false) );
60 return (uint8_t*)Block.base();
61 }
62
allocateSection(uintptr_t Size)63 sys::MemoryBlock RemoteMemoryManager::allocateSection(uintptr_t Size) {
64 std::error_code ec;
65 sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size,
66 &Near,
67 sys::Memory::MF_READ |
68 sys::Memory::MF_WRITE,
69 ec);
70 assert(!ec && MB.base());
71
72 // FIXME: This is part of a work around to keep sections near one another
73 // when MCJIT performs relocations after code emission but before
74 // the generated code is moved to the remote target.
75 // Save this address as the basis for our next request
76 Near = MB;
77 return MB;
78 }
79
notifyObjectLoaded(ExecutionEngine * EE,const object::ObjectFile & Obj)80 void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE,
81 const object::ObjectFile &Obj) {
82 // The client should have called setRemoteTarget() before triggering any
83 // code generation.
84 assert(Target);
85 if (!Target)
86 return;
87
88 // FIXME: Make this function thread safe.
89
90 // Lay out our sections in order, with all the code sections first, then
91 // all the data sections.
92 uint64_t CurOffset = 0;
93 unsigned MaxAlign = Target->getPageAlignment();
94 SmallVector<std::pair<Allocation, uint64_t>, 16> Offsets;
95 unsigned NumSections = UnmappedSections.size();
96 // We're going to go through the list twice to separate code and data, but
97 // it's a very small list, so that's OK.
98 for (size_t i = 0, e = NumSections; i != e; ++i) {
99 Allocation &Section = UnmappedSections[i];
100 if (Section.IsCode) {
101 unsigned Size = Section.MB.size();
102 unsigned Align = Section.Alignment;
103 DEBUG(dbgs() << "code region: size " << Size
104 << ", alignment " << Align << "\n");
105 // Align the current offset up to whatever is needed for the next
106 // section.
107 CurOffset = (CurOffset + Align - 1) / Align * Align;
108 // Save off the address of the new section and allocate its space.
109 Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset));
110 CurOffset += Size;
111 }
112 }
113 // Adjust to keep code and data aligned on separate pages.
114 CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign;
115 for (size_t i = 0, e = NumSections; i != e; ++i) {
116 Allocation &Section = UnmappedSections[i];
117 if (!Section.IsCode) {
118 unsigned Size = Section.MB.size();
119 unsigned Align = Section.Alignment;
120 DEBUG(dbgs() << "data region: size " << Size
121 << ", alignment " << Align << "\n");
122 // Align the current offset up to whatever is needed for the next
123 // section.
124 CurOffset = (CurOffset + Align - 1) / Align * Align;
125 // Save off the address of the new section and allocate its space.
126 Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset));
127 CurOffset += Size;
128 }
129 }
130
131 // Allocate space in the remote target.
132 uint64_t RemoteAddr;
133 if (!Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr))
134 report_fatal_error(Target->getErrorMsg());
135
136 // Map the section addresses so relocations will get updated in the local
137 // copies of the sections.
138 for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {
139 uint64_t Addr = RemoteAddr + Offsets[i].second;
140 EE->mapSectionAddress(const_cast<void*>(Offsets[i].first.MB.base()), Addr);
141
142 DEBUG(dbgs() << " Mapping local: " << Offsets[i].first.MB.base()
143 << " to remote: 0x" << format("%llx", Addr) << "\n");
144
145 MappedSections[Addr] = Offsets[i].first;
146 }
147
148 UnmappedSections.clear();
149 }
150
finalizeMemory(std::string * ErrMsg)151 bool RemoteMemoryManager::finalizeMemory(std::string *ErrMsg) {
152 // FIXME: Make this function thread safe.
153 for (DenseMap<uint64_t, Allocation>::iterator
154 I = MappedSections.begin(), E = MappedSections.end();
155 I != E; ++I) {
156 uint64_t RemoteAddr = I->first;
157 const Allocation &Section = I->second;
158 if (Section.IsCode) {
159 if (!Target->loadCode(RemoteAddr, Section.MB.base(), Section.MB.size()))
160 report_fatal_error(Target->getErrorMsg());
161 DEBUG(dbgs() << " loading code: " << Section.MB.base()
162 << " to remote: 0x" << format("%llx", RemoteAddr) << "\n");
163 } else {
164 if (!Target->loadData(RemoteAddr, Section.MB.base(), Section.MB.size()))
165 report_fatal_error(Target->getErrorMsg());
166 DEBUG(dbgs() << " loading data: " << Section.MB.base()
167 << " to remote: 0x" << format("%llx", RemoteAddr) << "\n");
168 }
169 }
170
171 MappedSections.clear();
172
173 return false;
174 }
175