ff0cc061ec
preserve our customizations, where necessary.
175 lines
7.0 KiB
C++
175 lines
7.0 KiB
C++
//===---- 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/Support/Debug.h"
|
|
#include "llvm/Support/Format.h"
|
|
#include "llvm/Support/raw_ostream.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) {
|
|
std::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 object::ObjectFile &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;
|
|
}
|