Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch aarch64-darwin codegen to JITLink (ObjectLinkingLayer) and small code model #43664

Merged
merged 3 commits into from
Jan 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,6 @@ extern void _chkstk(void);
#endif
}

// llvm state
extern JITEventListener *CreateJuliaJITEventListener();

// for image reloading
bool imaging_mode = false;

Expand Down Expand Up @@ -8103,7 +8100,12 @@ extern "C" void jl_init_llvm(void)
}
// Allocate a target...
Optional<CodeModel::Model> codemodel =
#ifdef _P64
#if defined(JL_USE_JITLINK)
// JITLink can patch up relocations between far objects so we can use the
// small code model – which is good, as the large code model is unmaintained
// on MachO/AArch64.
CodeModel::Small;
#elif defined(_P64)
// Make sure we are using the large code model on 64bit
// Let LLVM pick a default suitable for jitting on 32bit
CodeModel::Large;
Expand Down Expand Up @@ -8145,13 +8147,15 @@ extern "C" void jl_init_llvm(void)
}
#endif
if (jl_using_gdb_jitevents)
jl_ExecutionEngine->RegisterJITEventListener(JITEventListener::createGDBRegistrationListener());
jl_ExecutionEngine->enableJITDebuggingSupport();

#if defined(JL_USE_INTEL_JITEVENTS) || \
defined(JL_USE_OPROFILE_JITEVENTS) || \
defined(JL_USE_PERF_JITEVENTS)
#ifdef JL_USE_JITLINK
#error "JIT profiling support (JL_USE_*_JITEVENTS) not yet available on platforms that use JITLink"
#else
const char *jit_profiling = getenv("ENABLE_JITPROFILING");
#endif

#if defined(JL_USE_INTEL_JITEVENTS)
if (jit_profiling && atoi(jit_profiling)) {
Expand Down Expand Up @@ -8184,6 +8188,8 @@ extern "C" void jl_init_llvm(void)
#ifdef JL_USE_PERF_JITEVENTS
if (jl_using_perf_jitevents)
jl_ExecutionEngine->RegisterJITEventListener(JITEventListener::createPerfJITEventListener());
#endif
#endif
#endif

cl::PrintOptionValues();
Expand Down
104 changes: 28 additions & 76 deletions src/debuginfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
#include "platform.h"

#include "llvm-version.h"
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/JITEventListener.h>
#include <llvm/DebugInfo/DIContext.h>
#include <llvm/DebugInfo/DWARF/DWARFContext.h>
#include <llvm/Object/SymbolSize.h>
Expand All @@ -15,6 +13,7 @@
#include <llvm/IR/DebugInfo.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/IR/Mangler.h>
#include <llvm/ExecutionEngine/RTDyldMemoryManager.h>
#include <llvm/ExecutionEngine/RuntimeDyld.h>
#include <llvm/BinaryFormat/Magic.h>
#include <llvm/Object/MachO.h>
Expand Down Expand Up @@ -114,12 +113,6 @@ void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const D
}


#ifdef _OS_WINDOWS_
#if defined(_CPU_X86_64_)
void *lookupWriteAddressFor(RTDyldMemoryManager *memmgr, void *rt_addr);
#endif
#endif

#if defined(_OS_WINDOWS_)
static void create_PRUNTIME_FUNCTION(uint8_t *Code, size_t Size, StringRef fnname,
uint8_t *Section, size_t Allocated, uint8_t *UnwindData)
Expand Down Expand Up @@ -177,15 +170,20 @@ struct revcomp {
{ return lhs>rhs; }
};

class JuliaJITEventListener: public JITEventListener

// Central registry for resolving function addresses to `jl_method_instance_t`s and
// originating `ObjectFile`s (for the DWARF debug info).
//
// A global singleton instance is notified by the JIT whenever a new object is emitted,
// and later queried by the various function info APIs. We also use the chance to handle
// some platform-specific unwind info registration (which is unrelated to the query
// functionality).
class JITObjectRegistry
{
std::map<size_t, ObjectInfo, revcomp> objectmap;
std::map<size_t, std::pair<size_t, jl_method_instance_t *>, revcomp> linfomap;

public:
JuliaJITEventListener(){}
virtual ~JuliaJITEventListener() {}

jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT
{
uv_rwlock_rdlock(&threadsafe);
Expand All @@ -197,50 +195,16 @@ class JuliaJITEventListener: public JITEventListener
return linfo;
}

virtual void NotifyObjectEmitted(const object::ObjectFile &Object,
const RuntimeDyld::LoadedObjectInfo &L)
{
return _NotifyObjectEmitted(Object, L, nullptr);
}

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

auto SavedObject = L.getObjectForDebug(Object).takeBinary();
// If the debug object is unavailable, save (a copy of) the original object
// for our backtraces.
// This copy seems unfortunate, but there doesn't seem to be a way to take
// ownership of the original buffer.
if (!SavedObject.first) {
auto NewBuffer = MemoryBuffer::getMemBufferCopy(
Object.getData(), Object.getFileName());
auto NewObj = cantFail(object::ObjectFile::createObjectFile(NewBuffer->getMemBufferRef()));
SavedObject = std::make_pair(std::move(NewObj), std::move(NewBuffer));
}
const object::ObjectFile &debugObj = *SavedObject.first.release();
SavedObject.second.release();

object::section_iterator EndSection = debugObj.section_end();
StringMap<object::SectionRef> loadedSections;
for (const object::SectionRef &lSection: Object.sections()) {
auto sName = lSection.getName();
if (sName) {
bool inserted = loadedSections.insert(std::make_pair(*sName, lSection)).second;
assert(inserted); (void)inserted;
}
}
auto getLoadAddress = [&] (const StringRef &sName) -> uint64_t {
auto search = loadedSections.find(sName);
if (search == loadedSections.end())
return 0;
return L.getSectionLoadAddress(search->second);
};
object::section_iterator EndSection = Object.section_end();

#ifdef _CPU_ARM_
// ARM does not have/use .eh_frame
Expand Down Expand Up @@ -299,7 +263,7 @@ class JuliaJITEventListener: public JITEventListener
uint8_t *UnwindData = NULL;
#if defined(_CPU_X86_64_)
uint8_t *catchjmp = NULL;
for (const object::SymbolRef &sym_iter : debugObj.symbols()) {
for (const object::SymbolRef &sym_iter : Object.symbols()) {
StringRef sName = cantFail(sym_iter.getName());
uint8_t **pAddr = NULL;
if (sName.equals("__UnwindData")) {
Expand All @@ -322,9 +286,8 @@ class JuliaJITEventListener: public JITEventListener
SectionAddrCheck = SectionAddr;
SectionLoadCheck = SectionLoadAddr;
SectionWriteCheck = SectionLoadAddr;
if (memmgr)
SectionWriteCheck = (uintptr_t)lookupWriteAddressFor(memmgr,
(void*)SectionLoadAddr);
if (lookupWriteAddress)
SectionWriteCheck = (uintptr_t)lookupWriteAddress((void*)SectionLoadAddr);
Addr += SectionWriteCheck - SectionLoadAddr;
*pAddr = (uint8_t*)Addr;
}
Expand Down Expand Up @@ -352,7 +315,7 @@ class JuliaJITEventListener: public JITEventListener
#endif // defined(_OS_X86_64_)
#endif // defined(_OS_WINDOWS_)

auto symbols = object::computeSymbolSizes(debugObj);
auto symbols = object::computeSymbolSizes(Object);
bool first = true;
for (const auto &sym_size : symbols) {
const object::SymbolRef &sym_iter = sym_size.first;
Expand Down Expand Up @@ -389,7 +352,7 @@ class JuliaJITEventListener: public JITEventListener
if (codeinst)
linfomap[Addr] = std::make_pair(Size, codeinst->def);
if (first) {
ObjectInfo tmp = {&debugObj,
ObjectInfo tmp = {&Object,
(size_t)SectionSize,
(ptrdiff_t)(SectionAddr - SectionLoadAddr),
*Section,
Expand All @@ -403,22 +366,18 @@ class JuliaJITEventListener: public JITEventListener
jl_gc_safe_leave(ptls, gc_state);
}

// must implement if we ever start freeing code
// virtual void NotifyFreeingObject(const ObjectImage &Object) {}
// virtual void NotifyFreeingObject(const object::ObjectFile &Obj) {}

std::map<size_t, ObjectInfo, revcomp>& getObjectMap() JL_NOTSAFEPOINT
{
return objectmap;
}
};

JL_DLLEXPORT void ORCNotifyObjectEmitted(JITEventListener *Listener,
const object::ObjectFile &Object,
const RuntimeDyld::LoadedObjectInfo &L,
RTDyldMemoryManager *memmgr)
static JITObjectRegistry jl_jit_object_registry;
void jl_register_jit_object(const object::ObjectFile &Object,
std::function<uint64_t(const StringRef &)> getLoadAddress,
std::function<void *(void *)> lookupWriteAddress)
{
((JuliaJITEventListener*)Listener)->_NotifyObjectEmitted(Object, L, memmgr);
jl_jit_object_registry.registerJITObject(Object, getLoadAddress, lookupWriteAddress);
}

// TODO: convert the safe names from aotcomile.cpp:makeSafeName back into symbols
Expand Down Expand Up @@ -454,13 +413,6 @@ static std::pair<char *, bool> jl_demangle(const char *name) JL_NOTSAFEPOINT
return std::make_pair(strdup(name), false);
}

static JuliaJITEventListener *jl_jit_events;
JITEventListener *CreateJuliaJITEventListener(void)
{
jl_jit_events = new JuliaJITEventListener();
return jl_jit_events;
}

// *frames is a one element array containing whatever we could come up
// with for the current frame. here we'll try to expand it using debug info
// func_name and file_name are either NULL or malloc'd pointers
Expand Down Expand Up @@ -1194,7 +1146,7 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide,
{
int found = 0;
uv_rwlock_wrlock(&threadsafe);
std::map<size_t, ObjectInfo, revcomp> &objmap = jl_jit_events->getObjectMap();
std::map<size_t, ObjectInfo, revcomp> &objmap = jl_jit_object_registry.getObjectMap();
std::map<size_t, ObjectInfo, revcomp>::iterator fit = objmap.lower_bound(fptr);

if (symsize)
Expand Down Expand Up @@ -1228,7 +1180,7 @@ extern "C" JL_DLLEXPORT int jl_getFunctionInfo_impl(jl_frame_t **frames_out, siz
int64_t slide;
uint64_t symsize;
if (jl_DI_for_fptr(pointer, &symsize, &slide, &Section, &context)) {
frames[0].linfo = jl_jit_events->lookupLinfo(pointer);
frames[0].linfo = jl_jit_object_registry.lookupLinfo(pointer);
int nf = lookup_pointer(Section, context, frames_out, pointer, slide, true, noInline);
return nf;
}
Expand All @@ -1237,7 +1189,7 @@ extern "C" JL_DLLEXPORT int jl_getFunctionInfo_impl(jl_frame_t **frames_out, siz

extern "C" jl_method_instance_t *jl_gdblookuplinfo(void *p) JL_NOTSAFEPOINT
{
return jl_jit_events->lookupLinfo((size_t)p);
return jl_jit_object_registry.lookupLinfo((size_t)p);
}

#if (defined(_OS_LINUX_) || defined(_OS_FREEBSD_) || (defined(_OS_DARWIN_) && defined(LLVM_SHLIB)))
Expand Down Expand Up @@ -1659,7 +1611,7 @@ uint64_t jl_getUnwindInfo_impl(uint64_t dwAddr)
{
// Might be called from unmanaged thread
uv_rwlock_rdlock(&threadsafe);
std::map<size_t, ObjectInfo, revcomp> &objmap = jl_jit_events->getObjectMap();
std::map<size_t, ObjectInfo, revcomp> &objmap = jl_jit_object_registry.getObjectMap();
std::map<size_t, ObjectInfo, revcomp>::iterator it = objmap.lower_bound(dwAddr);
uint64_t ipstart = 0; // ip of the start of the section (if found)
if (it != objmap.end() && dwAddr < it->first + it->second.SectionSize) {
Expand Down
1 change: 0 additions & 1 deletion src/disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
#include <llvm/BinaryFormat/MachO.h>
#include <llvm/DebugInfo/DIContext.h>
#include <llvm/DebugInfo/DWARF/DWARFContext.h>
#include <llvm/ExecutionEngine/JITEventListener.h>
#include <llvm/IR/AssemblyAnnotationWriter.h>
#include <llvm/IR/DebugInfo.h>
#include <llvm/IR/Function.h>
Expand Down
Loading