forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			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;
 | |
| }
 |