summaryrefslogtreecommitdiff
path: root/tools/lli/RemoteMemoryManager.cpp
diff options
context:
space:
mode:
authorAndrew Kaylor <andrew.kaylor@intel.com>2013-10-04 00:49:38 +0000
committerAndrew Kaylor <andrew.kaylor@intel.com>2013-10-04 00:49:38 +0000
commitb868e9101c138016aad5bd910b67f40a3213d6fc (patch)
treeb05a180526bddc492c2860fc27dfecb3215995c5 /tools/lli/RemoteMemoryManager.cpp
parent7c9659a3b297be6298ffae4656b86797295c5d58 (diff)
downloadllvm-b868e9101c138016aad5bd910b67f40a3213d6fc.tar.gz
llvm-b868e9101c138016aad5bd910b67f40a3213d6fc.tar.bz2
llvm-b868e9101c138016aad5bd910b67f40a3213d6fc.tar.xz
Adding support and tests for multiple module handling in lli
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191938 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/lli/RemoteMemoryManager.cpp')
-rw-r--r--tools/lli/RemoteMemoryManager.cpp230
1 files changed, 230 insertions, 0 deletions
diff --git a/tools/lli/RemoteMemoryManager.cpp b/tools/lli/RemoteMemoryManager.cpp
new file mode 100644
index 0000000000..1f86066051
--- /dev/null
+++ b/tools/lli/RemoteMemoryManager.cpp
@@ -0,0 +1,230 @@
+//===---- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "lli"
+#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;
+
+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.push_back( Allocation(Block, Alignment, true) );
+ UnmappedSections.push_back( &AllocatedSections.back() );
+ 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.push_back( Allocation(Block, Alignment, false) );
+ UnmappedSections.push_back( &AllocatedSections.back() );
+ 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<const 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) {
+ const Allocation *Section = UnmappedSections[i];
+ assert(Section);
+ 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<const Allocation*,uint64_t>(Section,
+ CurOffset));
+ CurOffset += Size;
+ }
+ }
+ // Adjust to keep code and data aligned on seperate pages.
+ CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign;
+ for (size_t i = 0, e = NumSections; i != e; ++i) {
+ const Allocation *Section = UnmappedSections[i];
+ assert(Section);
+ 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<const 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, const Allocation*>::iterator
+ I = MappedSections.begin(), E = MappedSections.end();
+ I != E; ++I) {
+ uint64_t RemoteAddr = I->first;
+ const Allocation *Section = I->second;
+ if (Section->IsCode) {
+ Target->loadCode(RemoteAddr, Section->MB.base(), Section->MB.size());
+
+ DEBUG(dbgs() << " loading code: " << Section->MB.base()
+ << " to remote: 0x" << format("%llx", RemoteAddr) << "\n");
+ } else {
+ Target->loadData(RemoteAddr, Section->MB.base(), Section->MB.size());
+
+ 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 0;
+}
+uint8_t *RemoteMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){
+ llvm_unreachable("Unexpected!");
+ return 0;
+}
+uint8_t *RemoteMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize,
+ unsigned Alignment) {
+ llvm_unreachable("Unexpected!");
+ return 0;
+}
+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 0;
+}
+uint8_t *RemoteMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) {
+ llvm_unreachable("Unexpected!");
+ return 0;
+}
+void RemoteMemoryManager::deallocateFunctionBody(void *Body) {
+ llvm_unreachable("Unexpected!");
+}
+
+static int jit_noop() {
+ return 0;
+}
+
+void *RemoteMemoryManager::getPointerToNamedFunction(const std::string &Name,
+ bool AbortOnFailure) {
+ // We should not invoke parent's ctors/dtors from generated main()!
+ // On Mingw and Cygwin, the symbol __main is resolved to
+ // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors
+ // (and register wrong callee's dtors with atexit(3)).
+ // We expect ExecutionEngine::runStaticConstructorsDestructors()
+ // is called before ExecutionEngine::runFunctionAsMain() is called.
+ if (Name == "__main") return (void*)(intptr_t)&jit_noop;
+
+ // FIXME: Would it be responsible to provide GOT?
+ if (AbortOnFailure) {
+ if (Name == "_GLOBAL_OFFSET_TABLE_")
+ report_fatal_error("Program used external function '" + Name +
+ "' which could not be resolved!");
+ }
+
+ return NULL;
+}