Go to the documentation of this file.
15 #define DEBUG_TYPE "orc"
22 Expected<std::unique_ptr<EPCGenericRTDyldMemoryManager>>
27 {{SAs.Instance, rt::SimpleExecutorMemoryManagerInstanceName},
28 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
29 {SAs.Finalize, rt::SimpleExecutorMemoryManagerFinalizeWrapperName},
31 rt::SimpleExecutorMemoryManagerDeallocateWrapperName},
32 {SAs.RegisterEHFrame, rt::RegisterEHFrameSectionWrapperName},
33 {SAs.DeregisterEHFrame, rt::DeregisterEHFrameSectionWrapperName}}))
35 return std::make_unique<EPCGenericRTDyldMemoryManager>(EPC,
std::move(SAs));
40 : EPC(EPC), SAs(
std::
move(SAs)) {
41 LLVM_DEBUG(
dbgs() <<
"Created remote allocator " << (
void *)
this <<
"\n");
45 LLVM_DEBUG(
dbgs() <<
"Destroyed remote allocator " << (
void *)
this <<
"\n");
47 errs() <<
"Destroying with existing errors:\n" << ErrMsg <<
"\n";
63 uintptr_t Size,
unsigned Alignment,
unsigned SectionID,
65 std::lock_guard<std::mutex>
Lock(M);
67 dbgs() <<
"Allocator " << (
void *)
this <<
" allocating code section "
69 <<
" bytes, alignment = " << Alignment <<
"\n";
71 auto &Seg = Unmapped.back().CodeAllocs;
72 Seg.emplace_back(Size, Alignment);
73 return reinterpret_cast<uint8_t *
>(
78 uintptr_t Size,
unsigned Alignment,
unsigned SectionID,
80 std::lock_guard<std::mutex>
Lock(M);
82 dbgs() <<
"Allocator " << (
void *)
this <<
" allocating "
83 << (IsReadOnly ?
"ro" :
"rw") <<
"-data section " <<
SectionName
84 <<
": size = " <<
formatv(
"{0:x}", Size) <<
" bytes, alignment "
85 << Alignment <<
")\n";
89 IsReadOnly ? Unmapped.back().RODataAllocs : Unmapped.back().RWDataAllocs;
91 Seg.emplace_back(Size, Alignment);
92 return reinterpret_cast<uint8_t *
>(
97 uintptr_t CodeSize,
uint32_t CodeAlign, uintptr_t RODataSize,
101 std::lock_guard<std::mutex>
Lock(M);
107 ErrMsg =
"Invalid code alignment in reserveAllocationSpace";
111 ErrMsg =
"Invalid ro-data alignment in reserveAllocationSpace";
115 ErrMsg =
"Invalid rw-data alignment in reserveAllocationSpace";
126 dbgs() <<
"Allocator " << (
void *)
this <<
" reserving "
127 <<
formatv(
"{0:x}", TotalSize) <<
" bytes.\n";
134 std::lock_guard<std::mutex>
Lock(M);
138 if (!TargetAllocAddr) {
139 std::lock_guard<std::mutex>
Lock(M);
140 ErrMsg =
toString(TargetAllocAddr.takeError());
144 std::lock_guard<std::mutex>
Lock(M);
145 Unmapped.push_back(AllocGroup());
146 Unmapped.back().RemoteCode = {
148 Unmapped.back().RemoteROData = {
149 Unmapped.back().RemoteCode.End,
151 Unmapped.back().RemoteRWData = {
152 Unmapped.back().RemoteROData.End,
164 dbgs() <<
"Allocator " << (
void *)
this <<
" added unfinalized eh-frame "
165 <<
formatv(
"[ {0:x} {1:x} ]", LoadAddr, LoadAddr + Size) <<
"\n";
167 std::lock_guard<std::mutex>
Lock(M);
174 if (Alloc.RemoteCode.contains(LA) || Alloc.RemoteROData.contains(LA) ||
175 Alloc.RemoteRWData.contains(LA)) {
176 Alloc.UnfinalizedEHFrames.push_back({LA, Size});
180 ErrMsg =
"eh-frame does not lie inside unfinalized alloc";
189 std::lock_guard<std::mutex>
Lock(M);
190 LLVM_DEBUG(
dbgs() <<
"Allocator " << (
void *)
this <<
" applied mappings:\n");
191 for (
auto &ObjAllocs : Unmapped) {
192 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs,
193 ObjAllocs.RemoteCode.Start);
194 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs,
195 ObjAllocs.RemoteROData.Start);
196 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs,
197 ObjAllocs.RemoteRWData.Start);
198 Unfinalized.push_back(
std::move(ObjAllocs));
204 LLVM_DEBUG(
dbgs() <<
"Allocator " << (
void *)
this <<
" finalizing:\n");
207 std::vector<AllocGroup> Allocs;
209 std::lock_guard<std::mutex>
Lock(M);
210 if (ErrMsg && !this->ErrMsg.empty()) {
218 for (
auto &ObjAllocs : Allocs) {
230 &ObjAllocs.RemoteROData,
231 &ObjAllocs.RemoteRWData};
233 std::vector<Alloc> *SegSections[3] = {&ObjAllocs.CodeAllocs,
234 &ObjAllocs.RODataAllocs,
235 &ObjAllocs.RWDataAllocs};
238 std::unique_ptr<char[]> AggregateContents[3];
240 for (
unsigned I = 0;
I != 3; ++
I) {
243 Seg.Prot = SegProts[
I];
244 Seg.Addr = RemoteAddrs[
I]->
Start;
249 AggregateContents[
I] = std::make_unique<char[]>(Seg.Size);
250 size_t SecOffset = 0;
253 memcpy(&AggregateContents[
I][SecOffset],
254 reinterpret_cast<const char *
>(
261 Seg.Content = {AggregateContents[
I].get(), SecOffset};
264 for (
auto &Frame : ObjAllocs.UnfinalizedEHFrames)
279 std::lock_guard<std::mutex>
Lock(M);
281 dbgs() <<
"Serialization error: " << this->ErrMsg <<
"\n";
283 *ErrMsg = this->ErrMsg;
287 std::lock_guard<std::mutex>
Lock(M);
289 dbgs() <<
"Finalization error: " << this->ErrMsg <<
"\n";
291 *ErrMsg = this->ErrMsg;
299 void EPCGenericRTDyldMemoryManager::mapAllocsToRemoteAddrs(
301 for (
auto &Alloc : Allocs) {
304 dbgs() <<
" " <<
static_cast<void *
>(Alloc.Contents.get()) <<
" -> "
308 Alloc.Contents.get(),
Align(Alloc.Align))),
310 Alloc.RemoteAddr = NextAddr;
Represents an address in the executor process.
WireProtectionFlags toWireProtectionFlags(sys::Memory::ProtectionFlags PF)
Convert from sys::Memory::ProtectionFlags.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
void deregisterEHFrames() override
This is an optimization pass for GlobalISel generic memory operations.
ExecutorAddr DeregisterEHFrame
Error getBootstrapSymbols(ArrayRef< std::pair< ExecutorAddr &, StringRef >> Pairs) const
For each (ExecutorAddr&, StringRef) pair, looks up the string in the bootstrap symbols map and writes...
static ErrorSuccess success()
Create a success value.
void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign, uintptr_t RODataSize, uint32_t RODataAlign, uintptr_t RWDataSize, uint32_t RWDataAlign) override
Inform the memory manager about the total amount of memory required to allocate all sections to be lo...
uintptr_t alignAddr(const void *Addr, Align Alignment)
Aligns Addr to Alignment bytes, rounding up.
uint64_t getValue() const
uint8_t * allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName) override
Allocate a memory block of (at least) the given size suitable for executable code.
auto reverse(ContainerTy &&C, std::enable_if_t< has_rbegin< ContainerTy >::value > *=nullptr)
ExecutorProcessControl supports interaction with a JIT target process.
shared::SPSError(shared::SPSExecutorAddr, shared::SPSFinalizeRequest) SPSSimpleExecutorMemoryManagerFinalizeSignature
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
Tagged union holding either a T or a Error.
void notifyObjectLoaded(RuntimeDyld &Dyld, const object::ObjectFile &Obj) override
This method is called after an object has been loaded into memory but before relocations are applied ...
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
shared::AllocActions Actions
static Expected< std::unique_ptr< EPCGenericRTDyldMemoryManager > > CreateWithDefaultBootstrapSymbols(ExecutorProcessControl &EPC)
Create an EPCGenericRTDyldMemoryManager using the given EPC, looking up the default symbol names in t...
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
Symbol addresses for memory access.
shared::SPSExpected< shared::SPSExecutorAddr >(shared::SPSExecutorAddr, uint64_t) SPSSimpleExecutorMemoryManagerReserveSignature
uint8_t * allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName, bool IsReadOnly) override
Allocate a memory block of (at least) the given size suitable for data.
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override
Register the EH frames with the runtime so that c++ exceptions work.
uint64_t ExecutorAddrDiff
Represents an address range in the exceutor process.
void setValue(uint64_t Addr)
bool needsToReserveAllocationSpace() override
Override to return true to enable the reserveAllocationSpace callback.
This struct is a compact representation of a valid (non-zero power of two) alignment.
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
<%struct.s * > cast struct s *S to sbyte *< sbyte * > sbyte uint cast struct s *agg result to sbyte *< sbyte * > sbyte uint cast struct s *memtmp to sbyte *< sbyte * > sbyte uint ret void llc ends up issuing two memcpy or custom lower memcpy(of small size) to be ldmia/stmia. I think option 2 is better but the current register allocator cannot allocate a chunk of registers at a time. A feasible temporary solution is to use specific physical registers at the lowering time for small(<
std::vector< SegFinalizeRequest > Segments
StringRef - Represent a constant reference to a string, i.e.
This class is the base class for all object file types.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
EPCGenericRTDyldMemoryManager(ExecutorProcessControl &EPC, SymbolAddrs SAs)
Create an EPCGenericRTDyldMemoryManager using the given EPC and symbol addrs.
Error callSPSWrapper(ExecutorAddr WrapperFnAddr, WrapperCallArgTs &&...WrapperCallArgs)
Run a wrapper function using SPS to serialize the arguments and deserialize the results.
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})
Log all errors (if any) in E to OS.
const char * toString(DWARFSectionKind Kind)
Lightweight error class with error context and mandatory checking.
unsigned getPageSize() const
Get the page size for the target process.
ExecutorAddr RegisterEHFrame
~EPCGenericRTDyldMemoryManager()
bool finalizeMemory(std::string *ErrMsg=nullptr) override
This method is called when object loading is complete and section page permissions can be applied.
void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress)
Map a section to its target address space value.
shared::SPSError(shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSSimpleExecutorMemoryManagerDeallocateSignature
A utility class for serializing to a blob from a variadic list.