text: //===---- RemoteMemoryManager.cpp - Recording memory manager --------------===//
  //
  //                     The LLVM37 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 "llvm37/ExecutionEngine/ExecutionEngine.h"
  #include "llvm37/Support/Debug.h"
  #include "llvm37/Support/Format.h"
  #include "llvm37/Support/raw_ostream.h"
  
  using namespace llvm37;
  
  #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;
  }
  