1 //===---- EPCGenericJITLinkMemoryManager.cpp -- Mem management via EPC ----===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h" 10 #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h" 11 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" 12 13 #include <limits> 14 15 namespace llvm { 16 namespace orc { 17 18 class EPCGenericJITLinkMemoryManager::Alloc 19 : public jitlink::JITLinkMemoryManager::Allocation { 20 public: 21 struct SegInfo { 22 char *WorkingMem = nullptr; 23 ExecutorAddr TargetAddr; 24 uint64_t ContentSize = 0; 25 uint64_t ZeroFillSize = 0; 26 }; 27 using SegInfoMap = DenseMap<unsigned, SegInfo>; 28 29 Alloc(EPCGenericJITLinkMemoryManager &Parent, ExecutorAddr TargetAddr, 30 std::unique_ptr<char[]> WorkingBuffer, SegInfoMap Segs) 31 : Parent(Parent), TargetAddr(TargetAddr), 32 WorkingBuffer(std::move(WorkingBuffer)), Segs(std::move(Segs)) {} 33 34 MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override { 35 auto I = Segs.find(Seg); 36 assert(I != Segs.end() && "No allocation for seg"); 37 assert(I->second.ContentSize <= std::numeric_limits<size_t>::max()); 38 return {I->second.WorkingMem, static_cast<size_t>(I->second.ContentSize)}; 39 } 40 41 JITTargetAddress getTargetMemory(ProtectionFlags Seg) override { 42 auto I = Segs.find(Seg); 43 assert(I != Segs.end() && "No allocation for seg"); 44 return I->second.TargetAddr.getValue(); 45 } 46 47 void finalizeAsync(FinalizeContinuation OnFinalize) override { 48 char *WorkingMem = WorkingBuffer.get(); 49 tpctypes::FinalizeRequest FR; 50 for (auto &KV : Segs) { 51 assert(KV.second.ContentSize <= std::numeric_limits<size_t>::max()); 52 FR.Segments.push_back(tpctypes::SegFinalizeRequest{ 53 tpctypes::toWireProtectionFlags( 54 static_cast<sys::Memory::ProtectionFlags>(KV.first)), 55 KV.second.TargetAddr, 56 alignTo(KV.second.ContentSize + KV.second.ZeroFillSize, 57 Parent.EPC.getPageSize()), 58 {WorkingMem, static_cast<size_t>(KV.second.ContentSize)}}); 59 WorkingMem += KV.second.ContentSize; 60 } 61 Parent.EPC.callSPSWrapperAsync< 62 rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>( 63 Parent.SAs.Finalize, 64 [OnFinalize = std::move(OnFinalize)](Error SerializationErr, 65 Error FinalizeErr) { 66 if (SerializationErr) { 67 cantFail(std::move(FinalizeErr)); 68 OnFinalize(std::move(SerializationErr)); 69 } else 70 OnFinalize(std::move(FinalizeErr)); 71 }, 72 Parent.SAs.Allocator, std::move(FR)); 73 } 74 75 Error deallocate() override { 76 Error Err = Error::success(); 77 if (auto E2 = Parent.EPC.callSPSWrapper< 78 rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>( 79 Parent.SAs.Deallocate, Err, Parent.SAs.Allocator, 80 ArrayRef<ExecutorAddr>(TargetAddr))) 81 return E2; 82 return Err; 83 } 84 85 private: 86 EPCGenericJITLinkMemoryManager &Parent; 87 ExecutorAddr TargetAddr; 88 std::unique_ptr<char[]> WorkingBuffer; 89 SegInfoMap Segs; 90 }; 91 92 Expected<std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation>> 93 EPCGenericJITLinkMemoryManager::allocate(const jitlink::JITLinkDylib *JD, 94 const SegmentsRequestMap &Request) { 95 Alloc::SegInfoMap Segs; 96 uint64_t AllocSize = 0; 97 size_t WorkingSize = 0; 98 for (auto &KV : Request) { 99 if (!isPowerOf2_64(KV.second.getAlignment())) 100 return make_error<StringError>("Alignment is not a power of two", 101 inconvertibleErrorCode()); 102 if (KV.second.getAlignment() > EPC.getPageSize()) 103 return make_error<StringError>("Alignment exceeds page size", 104 inconvertibleErrorCode()); 105 106 auto &Seg = Segs[KV.first]; 107 Seg.ContentSize = KV.second.getContentSize(); 108 Seg.ZeroFillSize = KV.second.getZeroFillSize(); 109 AllocSize += alignTo(Seg.ContentSize + Seg.ZeroFillSize, EPC.getPageSize()); 110 WorkingSize += Seg.ContentSize; 111 } 112 113 std::unique_ptr<char[]> WorkingBuffer; 114 if (WorkingSize > 0) 115 WorkingBuffer = std::make_unique<char[]>(WorkingSize); 116 Expected<ExecutorAddr> TargetAllocAddr((ExecutorAddr())); 117 if (auto Err = EPC.callSPSWrapper< 118 rt::SPSSimpleExecutorMemoryManagerReserveSignature>( 119 SAs.Reserve, TargetAllocAddr, SAs.Allocator, AllocSize)) 120 return std::move(Err); 121 if (!TargetAllocAddr) 122 return TargetAllocAddr.takeError(); 123 124 char *WorkingMem = WorkingBuffer.get(); 125 JITTargetAddress SegAddr = TargetAllocAddr->getValue(); 126 for (auto &KV : Segs) { 127 auto &Seg = KV.second; 128 Seg.TargetAddr.setValue(SegAddr); 129 SegAddr += alignTo(Seg.ContentSize + Seg.ZeroFillSize, EPC.getPageSize()); 130 Seg.WorkingMem = WorkingMem; 131 WorkingMem += Seg.ContentSize; 132 } 133 134 return std::make_unique<Alloc>(*this, *TargetAllocAddr, 135 std::move(WorkingBuffer), std::move(Segs)); 136 } 137 138 } // end namespace orc 139 } // end namespace llvm 140