Skip to content

Commit 3b3d270

Browse files
committed
Switch aarch64-darwin codegen to JITLink (ObjectLinkingLayer) and small code model
This fixes #41440, #43285 and similar issues, which stem from CodeModel::Large not being correctly implemented on MachO/ARM64. Requires LLVM 13.x or Git main (tested: 1dd5e6fed5db with patches from the JuliaLang/llvm-project julia-release/13.x branch, available at https://github.com/dnadlinger/llvm-project/commits/julia-main). Requires an LLVM patch to pass through __eh_frame unwind information, without which backtraces silently won't work: llvm/llvm-project#52921 ``` diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp index f2a029d35cd5..4d958b302ff9 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp @@ -705,6 +705,10 @@ void link_MachO_arm64(std::unique_ptr<LinkGraph> G, Config.PrePrunePasses.push_back( CompactUnwindSplitter("__LD,__compact_unwind")); + Config.PrePrunePasses.push_back(EHFrameSplitter("__TEXT,__eh_frame")); + Config.PrePrunePasses.push_back(EHFrameEdgeFixer("__TEXT,__eh_frame", + 8, Delta64, Delta32, NegDelta32)); + // Add an in-place GOT/Stubs pass. Config.PostPrunePasses.push_back( PerGraphGOTAndPLTStubsBuilder_MachO_arm64::asPass); ```
1 parent b8d7024 commit 3b3d270

File tree

4 files changed

+371
-129
lines changed

4 files changed

+371
-129
lines changed

src/codegen.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8103,7 +8103,12 @@ extern "C" void jl_init_llvm(void)
81038103
}
81048104
// Allocate a target...
81058105
Optional<CodeModel::Model> codemodel =
8106-
#ifdef _P64
8106+
#if defined(JL_USE_JITLINK)
8107+
// JITLink can patch up relocations between far objects so we can use the
8108+
// small code model – which is good, as the arge code model is unmaintained
8109+
// on MachO/AArch64.
8110+
CodeModel::Small;
8111+
#elif defined(_P64)
81078112
// Make sure we are using the large code model on 64bit
81088113
// Let LLVM pick a default suitable for jitting on 32bit
81098114
CodeModel::Large;
@@ -8145,13 +8150,15 @@ extern "C" void jl_init_llvm(void)
81458150
}
81468151
#endif
81478152
if (jl_using_gdb_jitevents)
8148-
jl_ExecutionEngine->RegisterJITEventListener(JITEventListener::createGDBRegistrationListener());
8153+
jl_ExecutionEngine->enableJITDebuggingSupport();
81498154

81508155
#if defined(JL_USE_INTEL_JITEVENTS) || \
81518156
defined(JL_USE_OPROFILE_JITEVENTS) || \
81528157
defined(JL_USE_PERF_JITEVENTS)
8158+
#ifdef JL_USE_JITLINK
8159+
#error "JIT profiling support (JL_USE_*_JITEVENTS) not yet available on platforms that use JITLink"
8160+
#else
81538161
const char *jit_profiling = getenv("ENABLE_JITPROFILING");
8154-
#endif
81558162

81568163
#if defined(JL_USE_INTEL_JITEVENTS)
81578164
if (jit_profiling && atoi(jit_profiling)) {
@@ -8184,6 +8191,8 @@ extern "C" void jl_init_llvm(void)
81848191
#ifdef JL_USE_PERF_JITEVENTS
81858192
if (jl_using_perf_jitevents)
81868193
jl_ExecutionEngine->RegisterJITEventListener(JITEventListener::createPerfJITEventListener());
8194+
#endif
8195+
#endif
81878196
#endif
81888197

81898198
cl::PrintOptionValues();

src/debuginfo.cpp

Lines changed: 26 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,6 @@ void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const D
113113
}
114114

115115

116-
#ifdef _OS_WINDOWS_
117-
#if defined(_CPU_X86_64_)
118-
void *lookupWriteAddressFor(RTDyldMemoryManager *memmgr, void *rt_addr);
119-
#endif
120-
#endif
121-
122116
#if defined(_OS_WINDOWS_)
123117
static void create_PRUNTIME_FUNCTION(uint8_t *Code, size_t Size, StringRef fnname,
124118
uint8_t *Section, size_t Allocated, uint8_t *UnwindData)
@@ -177,7 +171,14 @@ struct revcomp {
177171
};
178172

179173

180-
class JuliaJITEventListener
174+
// Central registry for resolving function addresses to `jl_method_instance_t`s and
175+
// originating `ObjectFile`s (for the DWARF debug info).
176+
//
177+
// A global singleton instance is notified by the JIT whenever a new object is emitted,
178+
// and later queried by the various function info APIs. We also use the chance to handle
179+
// some platform-specific unwind info registration (which is unrelated to the query
180+
// functionality).
181+
class JITObjectRegistry
181182
{
182183
std::map<size_t, ObjectInfo, revcomp> objectmap;
183184
std::map<size_t, std::pair<size_t, jl_method_instance_t *>, revcomp> linfomap;
@@ -194,44 +195,16 @@ class JuliaJITEventListener
194195
return linfo;
195196
}
196197

197-
void NotifyObjectEmitted(const object::ObjectFile &Object,
198-
const RuntimeDyld::LoadedObjectInfo &L,
199-
RTDyldMemoryManager *memmgr)
198+
void registerJITObject(const object::ObjectFile &Object,
199+
std::function<uint64_t(const StringRef &)> getLoadAddress,
200+
std::function<void*(void*)> lookupWriteAddress)
200201
{
201202
jl_ptls_t ptls = jl_current_task->ptls;
202203
// This function modify codeinst->fptr in GC safe region.
203204
// This should be fine since the GC won't scan this field.
204205
int8_t gc_state = jl_gc_safe_enter(ptls);
205206

206-
auto SavedObject = L.getObjectForDebug(Object).takeBinary();
207-
// If the debug object is unavailable, save (a copy of) the original object
208-
// for our backtraces.
209-
// This copy seems unfortunate, but there doesn't seem to be a way to take
210-
// ownership of the original buffer.
211-
if (!SavedObject.first) {
212-
auto NewBuffer = MemoryBuffer::getMemBufferCopy(
213-
Object.getData(), Object.getFileName());
214-
auto NewObj = cantFail(object::ObjectFile::createObjectFile(NewBuffer->getMemBufferRef()));
215-
SavedObject = std::make_pair(std::move(NewObj), std::move(NewBuffer));
216-
}
217-
const object::ObjectFile &debugObj = *SavedObject.first.release();
218-
SavedObject.second.release();
219-
220-
object::section_iterator EndSection = debugObj.section_end();
221-
StringMap<object::SectionRef> loadedSections;
222-
for (const object::SectionRef &lSection: Object.sections()) {
223-
auto sName = lSection.getName();
224-
if (sName) {
225-
bool inserted = loadedSections.insert(std::make_pair(*sName, lSection)).second;
226-
assert(inserted); (void)inserted;
227-
}
228-
}
229-
auto getLoadAddress = [&] (const StringRef &sName) -> uint64_t {
230-
auto search = loadedSections.find(sName);
231-
if (search == loadedSections.end())
232-
return 0;
233-
return L.getSectionLoadAddress(search->second);
234-
};
207+
object::section_iterator EndSection = Object.section_end();
235208

236209
#ifdef _CPU_ARM_
237210
// ARM does not have/use .eh_frame
@@ -290,7 +263,7 @@ class JuliaJITEventListener
290263
uint8_t *UnwindData = NULL;
291264
#if defined(_CPU_X86_64_)
292265
uint8_t *catchjmp = NULL;
293-
for (const object::SymbolRef &sym_iter : debugObj.symbols()) {
266+
for (const object::SymbolRef &sym_iter : Object.symbols()) {
294267
StringRef sName = cantFail(sym_iter.getName());
295268
uint8_t **pAddr = NULL;
296269
if (sName.equals("__UnwindData")) {
@@ -313,9 +286,8 @@ class JuliaJITEventListener
313286
SectionAddrCheck = SectionAddr;
314287
SectionLoadCheck = SectionLoadAddr;
315288
SectionWriteCheck = SectionLoadAddr;
316-
if (memmgr)
317-
SectionWriteCheck = (uintptr_t)lookupWriteAddressFor(memmgr,
318-
(void*)SectionLoadAddr);
289+
if (lookupWriteAddress)
290+
SectionWriteCheck = (uintptr_t)lookupWriteAddress((void*)SectionLoadAddr);
319291
Addr += SectionWriteCheck - SectionLoadAddr;
320292
*pAddr = (uint8_t*)Addr;
321293
}
@@ -343,7 +315,7 @@ class JuliaJITEventListener
343315
#endif // defined(_OS_X86_64_)
344316
#endif // defined(_OS_WINDOWS_)
345317

346-
auto symbols = object::computeSymbolSizes(debugObj);
318+
auto symbols = object::computeSymbolSizes(Object);
347319
bool first = true;
348320
for (const auto &sym_size : symbols) {
349321
const object::SymbolRef &sym_iter = sym_size.first;
@@ -380,7 +352,7 @@ class JuliaJITEventListener
380352
if (codeinst)
381353
linfomap[Addr] = std::make_pair(Size, codeinst->def);
382354
if (first) {
383-
ObjectInfo tmp = {&debugObj,
355+
ObjectInfo tmp = {&Object,
384356
(size_t)SectionSize,
385357
(ptrdiff_t)(SectionAddr - SectionLoadAddr),
386358
*Section,
@@ -394,22 +366,18 @@ class JuliaJITEventListener
394366
jl_gc_safe_leave(ptls, gc_state);
395367
}
396368

397-
// must implement if we ever start freeing code
398-
// virtual void NotifyFreeingObject(const ObjectImage &Object) {}
399-
// virtual void NotifyFreeingObject(const object::ObjectFile &Obj) {}
400-
401369
std::map<size_t, ObjectInfo, revcomp>& getObjectMap() JL_NOTSAFEPOINT
402370
{
403371
return objectmap;
404372
}
405373
};
406374

407-
static JuliaJITEventListener jl_jit_events;
408-
JL_DLLEXPORT void ORCNotifyObjectEmitted(const object::ObjectFile &Object,
409-
const RuntimeDyld::LoadedObjectInfo &L,
410-
RTDyldMemoryManager *memmgr)
375+
static JITObjectRegistry jl_jit_object_registry;
376+
void jl_register_jit_object(const object::ObjectFile &Object,
377+
std::function<uint64_t(const StringRef &)> getLoadAddress,
378+
std::function<void *(void *)> lookupWriteAddress)
411379
{
412-
jl_jit_events.NotifyObjectEmitted(Object, L, memmgr);
380+
jl_jit_object_registry.registerJITObject(Object, getLoadAddress, lookupWriteAddress);
413381
}
414382

415383
// TODO: convert the safe names from aotcomile.cpp:makeSafeName back into symbols
@@ -1178,7 +1146,7 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide,
11781146
{
11791147
int found = 0;
11801148
uv_rwlock_wrlock(&threadsafe);
1181-
std::map<size_t, ObjectInfo, revcomp> &objmap = jl_jit_events.getObjectMap();
1149+
std::map<size_t, ObjectInfo, revcomp> &objmap = jl_jit_object_registry.getObjectMap();
11821150
std::map<size_t, ObjectInfo, revcomp>::iterator fit = objmap.lower_bound(fptr);
11831151

11841152
if (symsize)
@@ -1212,7 +1180,7 @@ extern "C" JL_DLLEXPORT int jl_getFunctionInfo_impl(jl_frame_t **frames_out, siz
12121180
int64_t slide;
12131181
uint64_t symsize;
12141182
if (jl_DI_for_fptr(pointer, &symsize, &slide, &Section, &context)) {
1215-
frames[0].linfo = jl_jit_events.lookupLinfo(pointer);
1183+
frames[0].linfo = jl_jit_object_registry.lookupLinfo(pointer);
12161184
int nf = lookup_pointer(Section, context, frames_out, pointer, slide, true, noInline);
12171185
return nf;
12181186
}
@@ -1221,7 +1189,7 @@ extern "C" JL_DLLEXPORT int jl_getFunctionInfo_impl(jl_frame_t **frames_out, siz
12211189

12221190
extern "C" jl_method_instance_t *jl_gdblookuplinfo(void *p) JL_NOTSAFEPOINT
12231191
{
1224-
return jl_jit_events.lookupLinfo((size_t)p);
1192+
return jl_jit_object_registry.lookupLinfo((size_t)p);
12251193
}
12261194

12271195
#if (defined(_OS_LINUX_) || defined(_OS_FREEBSD_) || (defined(_OS_DARWIN_) && defined(LLVM_SHLIB)))
@@ -1643,7 +1611,7 @@ uint64_t jl_getUnwindInfo_impl(uint64_t dwAddr)
16431611
{
16441612
// Might be called from unmanaged thread
16451613
uv_rwlock_rdlock(&threadsafe);
1646-
std::map<size_t, ObjectInfo, revcomp> &objmap = jl_jit_events.getObjectMap();
1614+
std::map<size_t, ObjectInfo, revcomp> &objmap = jl_jit_object_registry.getObjectMap();
16471615
std::map<size_t, ObjectInfo, revcomp>::iterator it = objmap.lower_bound(dwAddr);
16481616
uint64_t ipstart = 0; // ip of the start of the section (if found)
16491617
if (it != objmap.end() && dwAddr < it->first + it->second.SectionSize) {

0 commit comments

Comments
 (0)