summaryrefslogtreecommitdiff
path: root/tools/lli/RemoteMemoryManager.cpp
blob: 200ab75152c22fcd75817bbf3f870683315113f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
//===---- RemoteMemoryManager.cpp - Recording memory manager --------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This memory manager allocates local storage and keeps a record of each
// allocation. Iterators are provided for all data and code allocations.
//
//===----------------------------------------------------------------------===//

#include "RemoteMemoryManager.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/ObjectImage.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"

using namespace llvm;

#define DEBUG_TYPE "lli"

RemoteMemoryManager::~RemoteMemoryManager() {
  for (SmallVector<Allocation, 2>::iterator
         I = AllocatedSections.begin(), E = AllocatedSections.end();
       I != E; ++I)
    sys::Memory::releaseMappedMemory(I->MB);
}

uint8_t *RemoteMemoryManager::
allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID,
                    StringRef SectionName) {
  // The recording memory manager is just a local copy of the remote target.
  // The alignment requirement is just stored here for later use. Regular
  // heap storage is sufficient here, but we're using mapped memory to work
  // around a bug in MCJIT.
  sys::MemoryBlock Block = allocateSection(Size);
  // AllocatedSections will own this memory.
  AllocatedSections.push_back( Allocation(Block, Alignment, true) );
  // UnmappedSections has the same information but does not own the memory.
  UnmappedSections.push_back( Allocation(Block, Alignment, true) );
  return (uint8_t*)Block.base();
}

uint8_t *RemoteMemoryManager::
allocateDataSection(uintptr_t Size, unsigned Alignment,
                    unsigned SectionID, StringRef SectionName,
                    bool IsReadOnly) {
  // The recording memory manager is just a local copy of the remote target.
  // The alignment requirement is just stored here for later use. Regular
  // heap storage is sufficient here, but we're using mapped memory to work
  // around a bug in MCJIT.
  sys::MemoryBlock Block = allocateSection(Size);
  // AllocatedSections will own this memory.
  AllocatedSections.push_back( Allocation(Block, Alignment, false) );
  // UnmappedSections has the same information but does not own the memory.
  UnmappedSections.push_back( Allocation(Block, Alignment, false) );
  return (uint8_t*)Block.base();
}

sys::MemoryBlock RemoteMemoryManager::allocateSection(uintptr_t Size) {
  error_code ec;
  sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size,
                                                          &Near,
                                                          sys::Memory::MF_READ |
                                                          sys::Memory::MF_WRITE,
                                                          ec);
  assert(!ec && MB.base());

  // FIXME: This is part of a work around to keep sections near one another
  // when MCJIT performs relocations after code emission but before
  // the generated code is moved to the remote target.
  // Save this address as the basis for our next request
  Near = MB;
  return MB;
}

void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE,
                                                const ObjectImage *Obj) {
  // The client should have called setRemoteTarget() before triggering any
  // code generation.
  assert(Target);
  if (!Target)
    return;

  // FIXME: Make this function thread safe.

  // Lay out our sections in order, with all the code sections first, then
  // all the data sections.
  uint64_t CurOffset = 0;
  unsigned MaxAlign = Target->getPageAlignment();
  SmallVector<std::pair<Allocation, uint64_t>, 16> Offsets;
  unsigned NumSections = UnmappedSections.size();
  // We're going to go through the list twice to separate code and data, but
  // it's a very small list, so that's OK.
  for (size_t i = 0, e = NumSections; i != e; ++i) {
    Allocation &Section = UnmappedSections[i];
    if (Section.IsCode) {
      unsigned Size = Section.MB.size();
      unsigned Align = Section.Alignment;
      DEBUG(dbgs() << "code region: size " << Size
                  << ", alignment " << Align << "\n");
      // Align the current offset up to whatever is needed for the next
      // section.
      CurOffset = (CurOffset + Align - 1) / Align * Align;
      // Save off the address of the new section and allocate its space.
      Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset));
      CurOffset += Size;
    }
  }
  // Adjust to keep code and data aligned on separate pages.
  CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign;
  for (size_t i = 0, e = NumSections; i != e; ++i) {
    Allocation &Section = UnmappedSections[i];
    if (!Section.IsCode) {
      unsigned Size = Section.MB.size();
      unsigned Align = Section.Alignment;
      DEBUG(dbgs() << "data region: size " << Size
                  << ", alignment " << Align << "\n");
      // Align the current offset up to whatever is needed for the next
      // section.
      CurOffset = (CurOffset + Align - 1) / Align * Align;
      // Save off the address of the new section and allocate its space.
      Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset));
      CurOffset += Size;
    }
  }

  // Allocate space in the remote target.
  uint64_t RemoteAddr;
  if (!Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr))
    report_fatal_error(Target->getErrorMsg());

  // Map the section addresses so relocations will get updated in the local
  // copies of the sections.
  for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {
    uint64_t Addr = RemoteAddr + Offsets[i].second;
    EE->mapSectionAddress(const_cast<void*>(Offsets[i].first.MB.base()), Addr);

    DEBUG(dbgs() << "  Mapping local: " << Offsets[i].first.MB.base()
                 << " to remote: 0x" << format("%llx", Addr) << "\n");

    MappedSections[Addr] = Offsets[i].first;
  }

  UnmappedSections.clear();
}

bool RemoteMemoryManager::finalizeMemory(std::string *ErrMsg) {
  // FIXME: Make this function thread safe.
  for (DenseMap<uint64_t, Allocation>::iterator
         I = MappedSections.begin(), E = MappedSections.end();
       I != E; ++I) {
    uint64_t RemoteAddr = I->first;
    const Allocation &Section = I->second;
    if (Section.IsCode) {
      if (!Target->loadCode(RemoteAddr, Section.MB.base(), Section.MB.size()))
        report_fatal_error(Target->getErrorMsg());
      DEBUG(dbgs() << "  loading code: " << Section.MB.base()
            << " to remote: 0x" << format("%llx", RemoteAddr) << "\n");
    } else {
      if (!Target->loadData(RemoteAddr, Section.MB.base(), Section.MB.size()))
        report_fatal_error(Target->getErrorMsg());
      DEBUG(dbgs() << "  loading data: " << Section.MB.base()
            << " to remote: 0x" << format("%llx", RemoteAddr) << "\n");
    }
  }

  MappedSections.clear();

  return false;
}

void RemoteMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); }
void RemoteMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); }
void RemoteMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); }
void RemoteMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); }
uint8_t *RemoteMemoryManager::getGOTBase() const {
  llvm_unreachable("Unexpected!");
  return nullptr;
}
uint8_t *RemoteMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){
  llvm_unreachable("Unexpected!");
  return nullptr;
}
uint8_t *RemoteMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize,
                                              unsigned Alignment) {
  llvm_unreachable("Unexpected!");
  return nullptr;
}
void RemoteMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart,
                                             uint8_t *FunctionEnd) {
  llvm_unreachable("Unexpected!");
}
uint8_t *RemoteMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) {
  llvm_unreachable("Unexpected!");
  return nullptr;
}
uint8_t *RemoteMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) {
  llvm_unreachable("Unexpected!");
  return nullptr;
}
void RemoteMemoryManager::deallocateFunctionBody(void *Body) {
  llvm_unreachable("Unexpected!");
}