33#include " llvm-version.h"
44#include " platform.h"
55
6+ #include < llvm/ExecutionEngine/JITLink/JITLink.h>
7+ #include < llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h>
8+ #include < llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h>
69#include < llvm/ExecutionEngine/SectionMemoryManager.h>
10+
711#include " julia.h"
812#include " julia_internal.h"
913
@@ -460,26 +464,36 @@ struct Block {
460464 }
461465};
462466
467+ struct Allocation {
468+ // Address to write to (the one returned by the allocation function)
469+ void *wr_addr;
470+ // Runtime address
471+ void *rt_addr;
472+ size_t sz;
473+ bool relocated;
474+ };
475+
463476class RWAllocator {
464477 static constexpr int nblocks = 8 ;
465478 Block blocks[nblocks]{};
466479public:
467480 RWAllocator () JL_NOTSAFEPOINT = default ;
468- void * alloc (size_t size, size_t align) JL_NOTSAFEPOINT
481+ Allocation alloc (size_t size, size_t align) JL_NOTSAFEPOINT
469482 {
470483 size_t min_size = (size_t )-1 ;
471484 int min_id = 0 ;
472485 for (int i = 0 ;i < nblocks && blocks[i].ptr ;i++) {
473486 if (void *ptr = blocks[i].alloc (size, align))
474- return ptr;
487+ return { ptr, ptr, size, false } ;
475488 if (blocks[i].avail < min_size) {
476489 min_size = blocks[i].avail ;
477490 min_id = i;
478491 }
479492 }
480493 size_t block_size = get_block_size (size);
481494 blocks[min_id].reset (map_anon_page (block_size), block_size);
482- return blocks[min_id].alloc (size, align);
495+ void *ptr = blocks[min_id].alloc (size, align);
496+ return {ptr, ptr, size, false };
483497 }
484498};
485499
@@ -519,16 +533,6 @@ struct SplitPtrBlock : public Block {
519533 }
520534};
521535
522- struct Allocation {
523- // Address to write to (the one returned by the allocation function)
524- void *wr_addr;
525- // Runtime address
526- void *rt_addr;
527- size_t sz;
528- bool relocated;
529- };
530-
531- template <bool exec>
532536class ROAllocator {
533537protected:
534538 static constexpr int nblocks = 8 ;
@@ -556,7 +560,7 @@ class ROAllocator {
556560 }
557561 // Allocations that have not been finalized yet.
558562 SmallVector<Allocation, 16 > allocations;
559- void * alloc (size_t size, size_t align) JL_NOTSAFEPOINT
563+ Allocation alloc (size_t size, size_t align) JL_NOTSAFEPOINT
560564 {
561565 size_t min_size = (size_t )-1 ;
562566 int min_id = 0 ;
@@ -572,8 +576,9 @@ class ROAllocator {
572576 wr_ptr = get_wr_ptr (block, ptr, size, align);
573577 }
574578 block.state |= SplitPtrBlock::Alloc;
575- allocations.push_back (Allocation{wr_ptr, ptr, size, false });
576- return wr_ptr;
579+ Allocation a{wr_ptr, ptr, size, false };
580+ allocations.push_back (a);
581+ return a;
577582 }
578583 if (block.avail < min_size) {
579584 min_size = block.avail ;
@@ -594,18 +599,21 @@ class ROAllocator {
594599#ifdef _OS_WINDOWS_
595600 block.state = SplitPtrBlock::Alloc;
596601 void *wr_ptr = get_wr_ptr (block, ptr, size, align);
597- allocations.push_back (Allocation{wr_ptr, ptr, size, false });
602+ Allocation a{wr_ptr, ptr, size, false };
603+ allocations.push_back (a);
598604 ptr = wr_ptr;
599605#else
600606 block.state = SplitPtrBlock::Alloc | SplitPtrBlock::InitAlloc;
601- allocations.push_back (Allocation{ptr, ptr, size, false });
607+ Allocation a{ptr, ptr, size, false };
608+ allocations.push_back (a);
602609#endif
603- return ptr ;
610+ return a ;
604611 }
605612};
606613
607- template <bool exec>
608- class DualMapAllocator : public ROAllocator <exec> {
614+ class DualMapAllocator : public ROAllocator {
615+ bool exec;
616+
609617protected:
610618 void *get_wr_ptr (SplitPtrBlock &block, void *rt_ptr, size_t , size_t ) override JL_NOTSAFEPOINT
611619 {
@@ -666,7 +674,7 @@ class DualMapAllocator : public ROAllocator<exec> {
666674 }
667675 }
668676public:
669- DualMapAllocator () JL_NOTSAFEPOINT
677+ DualMapAllocator (bool exec ) JL_NOTSAFEPOINT : exec(exec)
670678 {
671679 assert (anon_hdl != -1 );
672680 }
@@ -679,13 +687,13 @@ class DualMapAllocator : public ROAllocator<exec> {
679687 finalize_block (block, true );
680688 block.reset (nullptr , 0 );
681689 }
682- ROAllocator<exec> ::finalize ();
690+ ROAllocator::finalize ();
683691 }
684692};
685693
686694#ifdef _OS_LINUX_
687- template < bool exec>
688- class SelfMemAllocator : public ROAllocator <exec> {
695+ class SelfMemAllocator : public ROAllocator {
696+ bool exec;
689697 SmallVector<Block, 16 > temp_buff;
690698protected:
691699 void *get_wr_ptr (SplitPtrBlock &block, void *rt_ptr,
@@ -722,9 +730,7 @@ class SelfMemAllocator : public ROAllocator<exec> {
722730 }
723731 }
724732public:
725- SelfMemAllocator () JL_NOTSAFEPOINT
726- : ROAllocator<exec>(),
727- temp_buff ()
733+ SelfMemAllocator (bool exec) JL_NOTSAFEPOINT : exec(exec), temp_buff()
728734 {
729735 assert (get_self_mem_fd () != -1 );
730736 }
@@ -758,11 +764,25 @@ class SelfMemAllocator : public ROAllocator<exec> {
758764 }
759765 if (cached)
760766 temp_buff.resize (1 );
761- ROAllocator<exec> ::finalize ();
767+ ROAllocator::finalize ();
762768 }
763769};
764770#endif // _OS_LINUX_
765771
772+ std::pair<std::unique_ptr<ROAllocator>, std::unique_ptr<ROAllocator>>
773+ get_preferred_allocators () JL_NOTSAFEPOINT
774+ {
775+ #ifdef _OS_LINUX_
776+ if (get_self_mem_fd () != -1 )
777+ return {std::make_unique<SelfMemAllocator>(false ),
778+ std::make_unique<SelfMemAllocator>(true )};
779+ #endif
780+ if (init_shared_map () != -1 )
781+ return {std::make_unique<DualMapAllocator>(false ),
782+ std::make_unique<DualMapAllocator>(true )};
783+ return {};
784+ }
785+
766786class RTDyldMemoryManagerJL : public SectionMemoryManager {
767787 struct EHFrame {
768788 uint8_t *addr;
@@ -772,29 +792,18 @@ class RTDyldMemoryManagerJL : public SectionMemoryManager {
772792 void operator =(const RTDyldMemoryManagerJL&) = delete ;
773793 SmallVector<EHFrame, 16 > pending_eh;
774794 RWAllocator rw_alloc;
775- std::unique_ptr<ROAllocator< false > > ro_alloc;
776- std::unique_ptr<ROAllocator< true > > exe_alloc;
795+ std::unique_ptr<ROAllocator> ro_alloc;
796+ std::unique_ptr<ROAllocator> exe_alloc;
777797 size_t total_allocated;
778798
779799public:
780800 RTDyldMemoryManagerJL () JL_NOTSAFEPOINT
781801 : SectionMemoryManager(),
782802 pending_eh (),
783803 rw_alloc(),
784- ro_alloc(),
785- exe_alloc(),
786804 total_allocated(0 )
787805 {
788- #ifdef _OS_LINUX_
789- if (!ro_alloc && get_self_mem_fd () != -1 ) {
790- ro_alloc.reset (new SelfMemAllocator<false >());
791- exe_alloc.reset (new SelfMemAllocator<true >());
792- }
793- #endif
794- if (!ro_alloc && init_shared_map () != -1 ) {
795- ro_alloc.reset (new DualMapAllocator<false >());
796- exe_alloc.reset (new DualMapAllocator<true >());
797- }
806+ std::tie (ro_alloc, exe_alloc) = get_preferred_allocators ();
798807 }
799808 ~RTDyldMemoryManagerJL () override JL_NOTSAFEPOINT
800809 {
@@ -847,7 +856,7 @@ uint8_t *RTDyldMemoryManagerJL::allocateCodeSection(uintptr_t Size,
847856 jl_timing_counter_inc (JL_TIMING_COUNTER_JITSize, Size);
848857 jl_timing_counter_inc (JL_TIMING_COUNTER_JITCodeSize, Size);
849858 if (exe_alloc)
850- return (uint8_t *)exe_alloc->alloc (Size, Alignment);
859+ return (uint8_t *)exe_alloc->alloc (Size, Alignment). wr_addr ;
851860 return SectionMemoryManager::allocateCodeSection (Size, Alignment, SectionID,
852861 SectionName);
853862}
@@ -862,9 +871,9 @@ uint8_t *RTDyldMemoryManagerJL::allocateDataSection(uintptr_t Size,
862871 jl_timing_counter_inc (JL_TIMING_COUNTER_JITSize, Size);
863872 jl_timing_counter_inc (JL_TIMING_COUNTER_JITDataSize, Size);
864873 if (!isReadOnly)
865- return (uint8_t *)rw_alloc.alloc (Size, Alignment);
874+ return (uint8_t *)rw_alloc.alloc (Size, Alignment). wr_addr ;
866875 if (ro_alloc)
867- return (uint8_t *)ro_alloc->alloc (Size, Alignment);
876+ return (uint8_t *)ro_alloc->alloc (Size, Alignment). wr_addr ;
868877 return SectionMemoryManager::allocateDataSection (Size, Alignment, SectionID,
869878 SectionName, isReadOnly);
870879}
@@ -919,6 +928,133 @@ void RTDyldMemoryManagerJL::deregisterEHFrames(uint8_t *Addr,
919928}
920929#endif
921930
931+ class JLJITLinkMemoryManager : public jitlink ::JITLinkMemoryManager {
932+ using OnFinalizedFunction =
933+ jitlink::JITLinkMemoryManager::InFlightAlloc::OnFinalizedFunction;
934+
935+ std::mutex Mutex;
936+ RWAllocator RWAlloc;
937+ std::unique_ptr<ROAllocator> ROAlloc;
938+ std::unique_ptr<ROAllocator> ExeAlloc;
939+ SmallVector<OnFinalizedFunction> FinalizedCallbacks;
940+ uint32_t InFlight{0 };
941+
942+ public:
943+ class InFlightAlloc ;
944+
945+ static std::unique_ptr<JITLinkMemoryManager> Create ()
946+ {
947+ auto [ROAlloc, ExeAlloc] = get_preferred_allocators ();
948+ if (ROAlloc && ExeAlloc)
949+ return std::unique_ptr<JLJITLinkMemoryManager>(
950+ new JLJITLinkMemoryManager (std::move (ROAlloc), std::move (ExeAlloc)));
951+
952+ return cantFail (
953+ orc::MapperJITLinkMemoryManager::CreateWithMapper<orc::InProcessMemoryMapper>(
954+ /* Reservation Granularity*/ 16 * 1024 * 1024 ));
955+ }
956+
957+ void allocate (const jitlink::JITLinkDylib *JD, jitlink::LinkGraph &G,
958+ OnAllocatedFunction OnAllocated) override ;
959+
960+ void deallocate (std::vector<FinalizedAlloc> Allocs,
961+ OnDeallocatedFunction OnDeallocated) override
962+ {
963+ jl_unreachable ();
964+ }
965+
966+ protected:
967+ JLJITLinkMemoryManager (std::unique_ptr<ROAllocator> ROAlloc,
968+ std::unique_ptr<ROAllocator> ExeAlloc)
969+ : ROAlloc(std::move(ROAlloc)), ExeAlloc(std::move(ExeAlloc))
970+ {
971+ }
972+
973+ void finalize (OnFinalizedFunction OnFinalized)
974+ {
975+ SmallVector<OnFinalizedFunction> Callbacks;
976+ {
977+ std::unique_lock Lock{Mutex};
978+ FinalizedCallbacks.push_back (std::move (OnFinalized));
979+
980+ if (--InFlight > 0 )
981+ return ;
982+
983+ ROAlloc->finalize ();
984+ ExeAlloc->finalize ();
985+ Callbacks = std::move (FinalizedCallbacks);
986+ }
987+
988+ for (auto &CB : Callbacks)
989+ std::move (CB)(FinalizedAlloc{});
990+ }
991+ };
992+
993+ class JLJITLinkMemoryManager ::InFlightAlloc
994+ : public jitlink::JITLinkMemoryManager::InFlightAlloc {
995+ JLJITLinkMemoryManager &MM;
996+ jitlink::LinkGraph &G;
997+
998+ public:
999+ InFlightAlloc (JLJITLinkMemoryManager &MM, jitlink::LinkGraph &G) : MM(MM), G(G) {}
1000+
1001+ void abandon (OnAbandonedFunction OnAbandoned) override { jl_unreachable (); }
1002+
1003+ void finalize (OnFinalizedFunction OnFinalized) override
1004+ {
1005+ auto *GP = &G;
1006+ MM.finalize ([GP, OnFinalized =
1007+ std::move (OnFinalized)](Expected<FinalizedAlloc> FA) mutable {
1008+ if (!FA)
1009+ return OnFinalized (FA.takeError ());
1010+ // Need to handle dealloc actions when we GC code
1011+ auto E = orc::shared::runFinalizeActions (GP->allocActions ());
1012+ if (!E)
1013+ return OnFinalized (E.takeError ());
1014+ OnFinalized (std::move (FA));
1015+ });
1016+ }
1017+ };
1018+
1019+ using orc::MemProt;
1020+
1021+ void JLJITLinkMemoryManager::allocate (const jitlink::JITLinkDylib *JD,
1022+ jitlink::LinkGraph &G,
1023+ OnAllocatedFunction OnAllocated)
1024+ {
1025+ jitlink::BasicLayout BL{G};
1026+
1027+ {
1028+ std::unique_lock Lock{Mutex};
1029+ for (auto &[AG, Seg] : BL.segments ()) {
1030+ if (AG.getMemLifetime () == orc::MemLifetime::NoAlloc)
1031+ continue ;
1032+ assert (AG.getMemLifetime () == orc::MemLifetime::Standard);
1033+
1034+ auto Prot = AG.getMemProt ();
1035+ uint64_t Alignment = Seg.Alignment .value ();
1036+ uint64_t Size = Seg.ContentSize + Seg.ZeroFillSize ;
1037+ Allocation Alloc;
1038+ if (Prot == (MemProt::Read | MemProt::Write))
1039+ Alloc = RWAlloc.alloc (Size, Alignment);
1040+ else if (Prot == MemProt::Read)
1041+ Alloc = ROAlloc->alloc (Size, Alignment);
1042+ else if (Prot == (MemProt::Read | MemProt::Exec))
1043+ Alloc = ExeAlloc->alloc (Size, Alignment);
1044+ else
1045+ abort ();
1046+
1047+ Seg.Addr = orc::ExecutorAddr::fromPtr (Alloc.rt_addr );
1048+ Seg.WorkingMem = (char *)Alloc.wr_addr ;
1049+ }
1050+ }
1051+
1052+ if (auto Err = BL.apply ())
1053+ return OnAllocated (std::move (Err));
1054+
1055+ ++InFlight;
1056+ OnAllocated (std::make_unique<InFlightAlloc>(*this , G));
1057+ }
9221058}
9231059
9241060RTDyldMemoryManager* createRTDyldMemoryManager () JL_NOTSAFEPOINT
@@ -930,3 +1066,8 @@ size_t getRTDyldMemoryManagerTotalBytes(RTDyldMemoryManager *mm) JL_NOTSAFEPOINT
9301066{
9311067 return ((RTDyldMemoryManagerJL*)mm)->getTotalBytes ();
9321068}
1069+
1070+ std::unique_ptr<jitlink::JITLinkMemoryManager> createJITLinkMemoryManager ()
1071+ {
1072+ return JLJITLinkMemoryManager::Create ();
1073+ }
0 commit comments