From 6ef22f931e850ee28d092d4c21fa77b8e1ec7d1d Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Thu, 5 Dec 2024 11:05:59 +1100 Subject: [PATCH 1/4] [ORC] Introduce LazyReexportsManager, JITLinkTrampolines, ORC-RT based reentry. These utilities provide new, more generic and easier to use support for lazy compilation in ORC. LazyReexportsManager is an alternative to LazyCallThroughManager. It takes requests for lazy re-entry points in the form of an alias map: lazy-reexports = { ( , ), ( , ), ... ( , ) } LazyReexportsManager then: 1. binds the entry points to the implementation names in an internal table. 2. creates a JIT re-entry trampoline for each entry point. 3. creates a redirectable symbol for each of the entry point name and binds redirectable symbol to the corresponding reentry trampoline. When an entry point symbol is first called at runtime (which may be on any thread of the JIT'd program) it will re-enter the JIT via the trampoline and trigger a lookup for the implementation symbol stored in LazyReexportsManager's internal table. When the lookup completes the entry point symbol will be updated (via the RedirectableSymbolManager) to point at the implementation symbol, and execution will proceed to the implementation symbol. Actual construction of the re-entry trampolines and redirectable symbols is delegated to an EmitTrampolines functor and the RedirectableSymbolsManager respectively. JITLinkReentryTrampolines.h provides a JITLink-based implementation of the EmitTrampolines functor. (AArch64 only in this patch, but other architectures will be added in the near future). Register state save and reentry functionality is added to the ORC runtime in the __orc_rt_sysv_resolve and __orc_rt_resolve_implementation functions (the latter is generic, the former will need custom implementations for each ABI and architecture to be supported, however this should be much less effort than the existing OrcABISupport approach, since the ORC runtime allows this code to be written as native assembly). The resulting system: 1. Works equally well for in-process and out-of-process JIT'd code. 2. Requires less boilerplate to set up. Given an ObjectLinkingLayer and PlatformJD (JITDylib containing the ORC runtime), setup is just: ```c++ auto RSMgr = JITLinkRedirectableSymbolManager::Create(OLL); if (!RSMgr) return RSMgr.takeError(); auto LRMgr = createJITLinkLazyReexportsManager(OLL, **RSMgr, PlatformJD); if (!LRMgr) return LRMgr.takeError(); ``` after which lazy reexports can be introduced with: ```c++ JD.define(lazyReexports(LRMgr, )); ``` LazyObectLinkingLayer is updated to use this new method, but the LLVM-IR level CompileOnDemandLayer will continue to use LazyCallThroughManager and OrcABISupport until the new system supports a wider range of architectures and ABIs. The llvm-jitlink utility's -lazy option now uses the new scheme. Since it depends on the ORC runtime, the lazy-link.ll testcase and associated helpers are moved to the ORC runtime. --- compiler-rt/lib/orc/CMakeLists.txt | 2 + compiler-rt/lib/orc/sysv_reentry.arm64.S | 102 ++++++++++ compiler-rt/lib/orc/sysv_resolve.cpp | 49 +++++ .../TestCases}/Generic/Inputs/foo-ret-42.ll | 0 .../orc/TestCases}/Generic/Inputs/var-x-42.ll | 0 .../test/orc/TestCases}/Generic/lazy-link.ll | 11 +- .../Generic/orc-rt-executor-usage.test | 2 + compiler-rt/test/orc/lit.cfg.py | 5 + .../llvm/ExecutionEngine/JITLink/aarch64.h | 26 +++ llvm/include/llvm/ExecutionEngine/Orc/Core.h | 27 +++ .../Orc/JITLinkLazyCallThroughManager.h | 26 +++ .../Orc/JITLinkRedirectableSymbolManager.h | 14 +- .../Orc/JITLinkReentryTrampolines.h | 72 +++++++ .../Orc/LazyObjectLinkingLayer.h | 8 +- .../llvm/ExecutionEngine/Orc/LazyReexports.h | 64 ++++++ .../llvm/ExecutionEngine/Orc/MachOPlatform.h | 5 + .../ExecutionEngine/Orc/RedirectionManager.h | 1 + llvm/lib/ExecutionEngine/JITLink/aarch64.cpp | 5 + llvm/lib/ExecutionEngine/Orc/CMakeLists.txt | 1 + llvm/lib/ExecutionEngine/Orc/Core.cpp | 21 ++ .../Orc/JITLinkReentryTrampolines.cpp | 184 ++++++++++++++++++ .../Orc/LazyObjectLinkingLayer.cpp | 8 +- .../lib/ExecutionEngine/Orc/LazyReexports.cpp | 164 ++++++++++++++++ .../lib/ExecutionEngine/Orc/MachOPlatform.cpp | 12 ++ llvm/tools/llvm-jitlink/llvm-jitlink.cpp | 56 ++---- llvm/tools/llvm-jitlink/llvm-jitlink.h | 20 +- 26 files changed, 816 insertions(+), 69 deletions(-) create mode 100644 compiler-rt/lib/orc/sysv_reentry.arm64.S create mode 100644 compiler-rt/lib/orc/sysv_resolve.cpp rename {llvm/test/ExecutionEngine/JITLink => compiler-rt/test/orc/TestCases}/Generic/Inputs/foo-ret-42.ll (100%) rename {llvm/test/ExecutionEngine/JITLink => compiler-rt/test/orc/TestCases}/Generic/Inputs/var-x-42.ll (100%) rename {llvm/test/ExecutionEngine/JITLink => compiler-rt/test/orc/TestCases}/Generic/lazy-link.ll (70%) create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/JITLinkLazyCallThroughManager.h create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/JITLinkReentryTrampolines.h create mode 100644 llvm/lib/ExecutionEngine/Orc/JITLinkReentryTrampolines.cpp diff --git a/compiler-rt/lib/orc/CMakeLists.txt b/compiler-rt/lib/orc/CMakeLists.txt index 36f4349a240e3..f1ddf91bd8d1d 100644 --- a/compiler-rt/lib/orc/CMakeLists.txt +++ b/compiler-rt/lib/orc/CMakeLists.txt @@ -51,6 +51,7 @@ if (APPLE) set(ORC_ASM_SOURCES macho_tlv.x86-64.S macho_tlv.arm64.S + sysv_reentry.arm64.S ) set(ORC_IMPL_HEADERS @@ -61,6 +62,7 @@ if (APPLE) set(ORC_SOURCES ${ORC_COMMON_SOURCES} macho_platform.cpp + sysv_resolve.cpp ) add_compiler_rt_object_libraries(RTOrc diff --git a/compiler-rt/lib/orc/sysv_reentry.arm64.S b/compiler-rt/lib/orc/sysv_reentry.arm64.S new file mode 100644 index 0000000000000..b831adec09b24 --- /dev/null +++ b/compiler-rt/lib/orc/sysv_reentry.arm64.S @@ -0,0 +1,102 @@ +//===-- sysv_reentry.arm64.s ------------------------------------*- ASM -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of the ORC runtime support library. +// +//===----------------------------------------------------------------------===// + +// The content of this file is arm64-only +#if defined(__arm64__) || defined(__aarch64__) + + .text + + // Saves GPRs, calls __orc_rt_sysv_resolve + .globl __orc_rt_sysv_reentry +__orc_rt_sysv_reentry: + // Save register state, set up new stack frome. + stp x27, x28, [sp, #-16]! + stp x25, x26, [sp, #-16]! + stp x23, x24, [sp, #-16]! + stp x21, x22, [sp, #-16]! + stp x19, x20, [sp, #-16]! + stp x14, x15, [sp, #-16]! + stp x12, x13, [sp, #-16]! + stp x10, x11, [sp, #-16]! + stp x8, x9, [sp, #-16]! + stp x6, x7, [sp, #-16]! + stp x4, x5, [sp, #-16]! + stp x2, x3, [sp, #-16]! + stp x0, x1, [sp, #-16]! + stp q30, q31, [sp, #-32]! + stp q28, q29, [sp, #-32]! + stp q26, q27, [sp, #-32]! + stp q24, q25, [sp, #-32]! + stp q22, q23, [sp, #-32]! + stp q20, q21, [sp, #-32]! + stp q18, q19, [sp, #-32]! + stp q16, q17, [sp, #-32]! + stp q14, q15, [sp, #-32]! + stp q12, q13, [sp, #-32]! + stp q10, q11, [sp, #-32]! + stp q8, q9, [sp, #-32]! + stp q6, q7, [sp, #-32]! + stp q4, q5, [sp, #-32]! + stp q2, q3, [sp, #-32]! + stp q0, q1, [sp, #-32]! + + // Look up the return address and subtract 8 from it (on the + // assumption that it's a standard arm64 reentry trampoline) to get + // back the trampoline's address. + sub x0, x30, #8 + + // Call __orc_rt_sysv_resolve to look up the implementation + // corresponding to the calling stub, then store this in x17 (which + // we'll return to below. +#if !defined(__APPLE__) + bl __orc_rt_sysv_resolve +#else + bl ___orc_rt_sysv_resolve +#endif + mov x17, x0 + + // Restore the register state. + ldp q0, q1, [sp], #32 + ldp q2, q3, [sp], #32 + ldp q4, q5, [sp], #32 + ldp q6, q7, [sp], #32 + ldp q8, q9, [sp], #32 + ldp q10, q11, [sp], #32 + ldp q12, q13, [sp], #32 + ldp q14, q15, [sp], #32 + ldp q16, q17, [sp], #32 + ldp q18, q19, [sp], #32 + ldp q20, q21, [sp], #32 + ldp q22, q23, [sp], #32 + ldp q24, q25, [sp], #32 + ldp q26, q27, [sp], #32 + ldp q28, q29, [sp], #32 + ldp q30, q31, [sp], #32 + ldp x0, x1, [sp], #16 + ldp x2, x3, [sp], #16 + ldp x4, x5, [sp], #16 + ldp x6, x7, [sp], #16 + ldp x8, x9, [sp], #16 + ldp x10, x11, [sp], #16 + ldp x12, x13, [sp], #16 + ldp x14, x15, [sp], #16 + ldp x19, x20, [sp], #16 + ldp x21, x22, [sp], #16 + ldp x23, x24, [sp], #16 + ldp x25, x26, [sp], #16 + ldp x27, x28, [sp], #16 + ldp x29, x30, [sp], #16 + + // Return to the function implementation (rather than the stub). + ret x17 + +#endif // defined(__arm64__) || defined(__aarch64__) diff --git a/compiler-rt/lib/orc/sysv_resolve.cpp b/compiler-rt/lib/orc/sysv_resolve.cpp new file mode 100644 index 0000000000000..8e3c2ca750d75 --- /dev/null +++ b/compiler-rt/lib/orc/sysv_resolve.cpp @@ -0,0 +1,49 @@ +//===- sysv_resolve.cpp ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains a generic "resolver" function compatible with the SysV +// ABI. +// +//===----------------------------------------------------------------------===// + +#include "executor_symbol_def.h" +#include "jit_dispatch.h" +#include "wrapper_function_utils.h" + +#include + +#define DEBUG_TYPE "sysv_resolve" + +using namespace orc_rt; + +// Declare function tags for functions in the JIT process. +ORC_RT_JIT_DISPATCH_TAG(__orc_rt_resolve_tag) + +// FIXME: Make this configurable via an alias. +static void __orc_rt_sysv_fail(void *Caller, const char *ErrMsg) { + fprintf(stderr, "error resolving implementation for stub %p: %s\n", Caller, + ErrMsg); + abort(); +} + +extern "C" ORC_RT_HIDDEN void *__orc_rt_sysv_resolve(void *Caller) { + Expected Result((ExecutorSymbolDef())); + if (auto Err = WrapperFunction( + SPSExecutorAddr)>::call(JITDispatch(&__orc_rt_resolve_tag), Result, + ExecutorAddr::fromPtr(Caller))) { + __orc_rt_sysv_fail(Caller, toString(std::move(Err)).c_str()); + return nullptr; // Unreachable. + } + + if (!Result) { + __orc_rt_sysv_fail(Caller, toString(Result.takeError()).c_str()); + return nullptr; // Unreachable. + } + + return Result->getAddress().toPtr(); +} diff --git a/llvm/test/ExecutionEngine/JITLink/Generic/Inputs/foo-ret-42.ll b/compiler-rt/test/orc/TestCases/Generic/Inputs/foo-ret-42.ll similarity index 100% rename from llvm/test/ExecutionEngine/JITLink/Generic/Inputs/foo-ret-42.ll rename to compiler-rt/test/orc/TestCases/Generic/Inputs/foo-ret-42.ll diff --git a/llvm/test/ExecutionEngine/JITLink/Generic/Inputs/var-x-42.ll b/compiler-rt/test/orc/TestCases/Generic/Inputs/var-x-42.ll similarity index 100% rename from llvm/test/ExecutionEngine/JITLink/Generic/Inputs/var-x-42.ll rename to compiler-rt/test/orc/TestCases/Generic/Inputs/var-x-42.ll diff --git a/llvm/test/ExecutionEngine/JITLink/Generic/lazy-link.ll b/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll similarity index 70% rename from llvm/test/ExecutionEngine/JITLink/Generic/lazy-link.ll rename to compiler-rt/test/orc/TestCases/Generic/lazy-link.ll index 72325e198721b..a8a569a21ce85 100644 --- a/llvm/test/ExecutionEngine/JITLink/Generic/lazy-link.ll +++ b/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll @@ -4,13 +4,14 @@ ; referenced by main, should be linked (despite being passed with -lazy). ; ; RUN: rm -rf %t && mkdir -p %t -; RUN: llc -filetype=obj -o %t/foo.o %S/Inputs/foo-ret-42.ll -; RUN: llc -filetype=obj -o %t/x.o %S/Inputs/var-x-42.ll -; RUN: llc -filetype=obj -o %t/main.o %s -; RUN: llvm-jitlink -noexec -show-linked-files %t/main.o -lazy %t/foo.o \ +; RUN: %clang -c -o %t/foo.o %S/Inputs/foo-ret-42.ll +; RUN: %clang -c -o %t/x.o %S/Inputs/var-x-42.ll +; RUN: %clang -c -o %t/main.o %s +; RUN: %llvm_jitlink -noexec -show-linked-files %t/main.o -lazy %t/foo.o \ ; RUN: -lazy %t/x.o | FileCheck %s ; -; UNSUPPORTED: system-windows, target={{arm[^6][^4].*}}, target=powerpc64{{.*}} +; UNSUPPORTED: system-windows +; REQUIRE: target={{(arm|aarch)64{.*}}} ; ; CHECK: Linking {{.*}}main.o ; CHECK-DAG: Linking diff --git a/compiler-rt/test/orc/TestCases/Generic/orc-rt-executor-usage.test b/compiler-rt/test/orc/TestCases/Generic/orc-rt-executor-usage.test index 951688d7961d4..e756477131d06 100644 --- a/compiler-rt/test/orc/TestCases/Generic/orc-rt-executor-usage.test +++ b/compiler-rt/test/orc/TestCases/Generic/orc-rt-executor-usage.test @@ -3,4 +3,6 @@ // // RUN: not %orc_rt_executor 2>&1 | FileCheck %s +// REQUIRES: system-linux + // CHECK: usage: orc-rt-executor [help] [] ... diff --git a/compiler-rt/test/orc/lit.cfg.py b/compiler-rt/test/orc/lit.cfg.py index 6dfa94b11cc9d..7a6eb4e7de325 100644 --- a/compiler-rt/test/orc/lit.cfg.py +++ b/compiler-rt/test/orc/lit.cfg.py @@ -16,6 +16,11 @@ host_arch_compatible = True if host_arch_compatible: config.available_features.add("host-arch-compatible") + +# If the target OS hasn't been set then assume host. +if not config.target_os: + config.target_os = config.host_os + config.test_target_is_host_executable = ( config.target_os == config.host_os and host_arch_compatible ) diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h index db440c378d24f..1fa957178a122 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h @@ -755,6 +755,32 @@ inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G, sizeof(PointerJumpStubContent), true, false); } +/// AArch64 reentry trampoline. +/// +/// Contains the instruction sequence for a trampoline that stores its return +/// address on the stack and passes its own address in x0: +/// STP x29, x30, [sp, #-16]! +/// BL +extern const char ReentryTrampolineContent[8]; + +/// Create a block of N reentry trampolines. +inline Block &createReentryTrampolineBlock(LinkGraph &G, + Section &TrampolineSection, + Symbol &ReentrySymbol) { + auto &B = G.createContentBlock(TrampolineSection, ReentryTrampolineContent, + orc::ExecutorAddr(~uint64_t(7)), 4, 0); + B.addEdge(Branch26PCRel, 4, ReentrySymbol, 0); + return B; +} + +inline Symbol &createAnonymousReentryTrampoline(LinkGraph &G, + Section &TrampolineSection, + Symbol &ReentrySymbol) { + return G.addAnonymousSymbol( + createReentryTrampolineBlock(G, TrampolineSection, ReentrySymbol), 0, + sizeof(ReentryTrampolineContent), true, false); +} + /// Global Offset Table Builder. class GOTTableManager : public TableManager { public: diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Core.h b/llvm/include/llvm/ExecutionEngine/Orc/Core.h index e892005c53d8e..9e3e46285c408 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Core.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Core.h @@ -51,6 +51,26 @@ enum class SymbolState : uint8_t; using ResourceTrackerSP = IntrusiveRefCntPtr; using JITDylibSP = IntrusiveRefCntPtr; +/// A definition of a Symbol within a JITDylib. +class SymbolInstance { +public: + using LookupAsyncOnCompleteFn = + unique_function)>; + + SymbolInstance(JITDylibSP JD, SymbolStringPtr Name) + : JD(std::move(JD)), Name(std::move(Name)) {} + + const JITDylib &getJITDylib() const { return *JD; } + const SymbolStringPtr &getName() const { return Name; } + + Expected lookup() const; + void lookupAsync(LookupAsyncOnCompleteFn OnComplete) const; + +private: + JITDylibSP JD; + SymbolStringPtr Name; +}; + using ResourceKey = uintptr_t; /// API to remove / transfer ownership of JIT resources. @@ -550,6 +570,9 @@ class MaterializationResponsibility { /// emitted or notified of an error. ~MaterializationResponsibility(); + /// Return the ResourceTracker associated with this instance. + const ResourceTrackerSP &getResourceTracker() const { return RT; } + /// Runs the given callback under the session lock, passing in the associated /// ResourceKey. This is the safe way to associate resources with trackers. template Error withResourceKeyDo(Func &&F) const { @@ -1748,6 +1771,10 @@ class ExecutionSession { JITDispatchHandlers; }; +inline Expected SymbolInstance::lookup() const { + return JD->getExecutionSession().lookup({JD.get()}, Name); +} + template Error ResourceTracker::withResourceKeyDo(Func &&F) { return getJITDylib().getExecutionSession().runSessionLocked([&]() -> Error { if (isDefunct()) diff --git a/llvm/include/llvm/ExecutionEngine/Orc/JITLinkLazyCallThroughManager.h b/llvm/include/llvm/ExecutionEngine/Orc/JITLinkLazyCallThroughManager.h new file mode 100644 index 0000000000000..19075c76a6073 --- /dev/null +++ b/llvm/include/llvm/ExecutionEngine/Orc/JITLinkLazyCallThroughManager.h @@ -0,0 +1,26 @@ +//===- JITLinkLazyCallThroughManager.h - JITLink based laziness -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Redirectable Symbol Manager implementation using JITLink +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_JITLINKLAZYCALLTHROUGHMANAGER_H +#define LLVM_EXECUTIONENGINE_ORC_JITLINKLAZYCALLTHROUGHMANAGER_H + +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/Orc/RedirectionManager.h" +#include "llvm/Support/StringSaver.h" + +#include + +namespace llvm { +namespace orc {} // namespace orc +} // namespace llvm + +#endif // LLVM_EXECUTIONENGINE_ORC_JITLINKLAZYCALLTHROUGHMANAGER_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.h b/llvm/include/llvm/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.h index 81d1d154d5600..83339e56cfa5f 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.h @@ -39,12 +39,6 @@ class JITLinkRedirectableSymbolManager : public RedirectableSymbolManager { ObjLinkingLayer, AnonymousPtrCreator, PtrJumpStubCreator)); } - void emitRedirectableSymbols(std::unique_ptr R, - SymbolMap InitialDests) override; - - Error redirect(JITDylib &JD, const SymbolMap &NewDests) override; - -private: JITLinkRedirectableSymbolManager( ObjectLinkingLayer &ObjLinkingLayer, jitlink::AnonymousPointerCreator &AnonymousPtrCreator, @@ -53,6 +47,14 @@ class JITLinkRedirectableSymbolManager : public RedirectableSymbolManager { AnonymousPtrCreator(std::move(AnonymousPtrCreator)), PtrJumpStubCreator(std::move(PtrJumpStubCreator)) {} + ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; } + + void emitRedirectableSymbols(std::unique_ptr R, + SymbolMap InitialDests) override; + + Error redirect(JITDylib &JD, const SymbolMap &NewDests) override; + +private: ObjectLinkingLayer &ObjLinkingLayer; jitlink::AnonymousPointerCreator AnonymousPtrCreator; jitlink::PointerJumpStubCreator PtrJumpStubCreator; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/JITLinkReentryTrampolines.h b/llvm/include/llvm/ExecutionEngine/Orc/JITLinkReentryTrampolines.h new file mode 100644 index 0000000000000..673019b748b3b --- /dev/null +++ b/llvm/include/llvm/ExecutionEngine/Orc/JITLinkReentryTrampolines.h @@ -0,0 +1,72 @@ +//===- JITLinkReentryTrampolines.h -- JITLink-based trampolines -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Emit reentry trampolines via JITLink. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_JITLINKREENTRYTRAMPOLINES_H +#define LLVM_EXECUTIONENGINE_ORC_JITLINKREENTRYTRAMPOLINES_H + +#include "llvm/ADT/FunctionExtras.h" +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/LazyReexports.h" +#include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h" +#include "llvm/Support/Error.h" + +namespace llvm::jitlink { +class Block; +class LinkGraph; +class Section; +class Symbol; +} // namespace llvm::jitlink + +namespace llvm::orc { + +class ObjectLinkingLayer; +class RedirectableSymbolManager; + +/// Produces trampolines on request using JITLink. +class JITLinkReentryTrampolines { +public: + using EmitTrampolineFn = unique_function; + using OnTrampolinesReadyFn = unique_function> EntryAddrs)>; + + /// Create trampolines using the default reentry trampoline function for + /// the session triple. + static Expected> + Create(ObjectLinkingLayer &ObjLinkingLayer); + + JITLinkReentryTrampolines(ObjectLinkingLayer &ObjLinkingLayer, + EmitTrampolineFn EmitTrampoline); + JITLinkReentryTrampolines(JITLinkReentryTrampolines &&) = delete; + JITLinkReentryTrampolines &operator=(JITLinkReentryTrampolines &&) = delete; + + void emit(ResourceTrackerSP RT, size_t NumTrampolines, + OnTrampolinesReadyFn OnTrampolinesReady); + +private: + class TrampolineAddrScraperPlugin; + + ObjectLinkingLayer &ObjLinkingLayer; + TrampolineAddrScraperPlugin *TrampolineAddrScraper = nullptr; + EmitTrampolineFn EmitTrampoline; + std::atomic ReentryGraphIdx{0}; +}; + +Expected> +createJITLinkLazyReexportsManager(ObjectLinkingLayer &ObjLinkingLayer, + RedirectableSymbolManager &RSMgr, + JITDylib &PlatformJD); + +} // namespace llvm::orc + +#endif // LLVM_EXECUTIONENGINE_ORC_JITLINKREENTRYTRAMPOLINES_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/LazyObjectLinkingLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/LazyObjectLinkingLayer.h index 800f6773f16f5..96223d71e4f6a 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/LazyObjectLinkingLayer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/LazyObjectLinkingLayer.h @@ -18,14 +18,13 @@ namespace llvm::orc { class ObjectLinkingLayer; -class LazyCallThroughManager; +class LazyReexportsManager; class RedirectableSymbolManager; class LazyObjectLinkingLayer : public ObjectLayer { public: LazyObjectLinkingLayer(ObjectLinkingLayer &BaseLayer, - LazyCallThroughManager &LCTMgr, - RedirectableSymbolManager &RSMgr); + LazyReexportsManager &LRMgr); llvm::Error add(llvm::orc::ResourceTrackerSP RT, std::unique_ptr O, @@ -38,8 +37,7 @@ class LazyObjectLinkingLayer : public ObjectLayer { class RenamerPlugin; ObjectLinkingLayer &BaseLayer; - LazyCallThroughManager &LCTMgr; - RedirectableSymbolManager &RSMgr; + LazyReexportsManager &LRMgr; }; } // namespace llvm::orc diff --git a/llvm/include/llvm/ExecutionEngine/Orc/LazyReexports.h b/llvm/include/llvm/ExecutionEngine/Orc/LazyReexports.h index 6a43cb6fb6ca9..0dcf646b12dd8 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/LazyReexports.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/LazyReexports.h @@ -173,6 +173,70 @@ lazyReexports(LazyCallThroughManager &LCTManager, LCTManager, RSManager, SourceJD, std::move(CallableAliases), SrcJDLoc); } +class LazyReexportsManager { + + friend std::unique_ptr + lazyReexports(LazyReexportsManager &, SymbolAliasMap); + +public: + using OnTrampolinesReadyFn = unique_function> EntryAddrs)>; + using EmitTrampolinesFn = + unique_function; + + /// Create a LazyReexportsManager that uses the ORC runtime for reentry. + /// This will work both in-process and out-of-process. + static Expected> + Create(EmitTrampolinesFn EmitTrampolines, RedirectableSymbolManager &RSMgr, + JITDylib &PlatformJD); + + LazyReexportsManager(LazyReexportsManager &&) = delete; + LazyReexportsManager &operator=(LazyReexportsManager &&) = delete; + +private: + struct CallThroughInfo { + SymbolStringPtr Name; + SymbolStringPtr BodyName; + JITDylibSP JD; + }; + + class MU; + class Plugin; + + using ResolveSendResultFn = + unique_function)>; + + LazyReexportsManager(EmitTrampolinesFn EmitTrampolines, + RedirectableSymbolManager &RSMgr, JITDylib &PlatformJD, + Error &Err); + + std::unique_ptr + createLazyReexports(SymbolAliasMap Reexports); + + void emitReentryTrampolines(std::unique_ptr MR, + SymbolAliasMap Reexports); + void emitRedirectableSymbols( + std::unique_ptr MR, + SymbolAliasMap Reexports, + Expected> ReentryPoints); + void resolve(ResolveSendResultFn SendResult, ExecutorAddr ReentryStubAddr); + + EmitTrampolinesFn EmitTrampolines; + RedirectableSymbolManager &RSMgr; + + std::mutex M; + DenseMap CallThroughs; +}; + +/// Define lazy-reexports based on the given SymbolAliasMap. Each lazy re-export +/// is a callable symbol that will look up and dispatch to the given aliasee on +/// first call. All subsequent calls will go directly to the aliasee. +inline std::unique_ptr +lazyReexports(LazyReexportsManager &LRM, SymbolAliasMap Reexports) { + return LRM.createLazyReexports(std::move(Reexports)); +} + } // End namespace orc } // End namespace llvm diff --git a/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h b/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h index 19f935d665823..1f11d9f61f6a1 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h @@ -176,6 +176,11 @@ class MachOPlatform : public Platform { static ArrayRef> standardRuntimeUtilityAliases(); + /// Returns a list of aliases required to enable lazy compilation via the + /// ORC runtime. + static ArrayRef> + standardLazyCompilationAliases(); + private: using SymbolTableVector = SmallVector< std::tuple>; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/RedirectionManager.h b/llvm/include/llvm/ExecutionEngine/Orc/RedirectionManager.h index a1a5ffcf34066..f3d4c76938778 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/RedirectionManager.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/RedirectionManager.h @@ -23,6 +23,7 @@ namespace orc { class RedirectionManager { public: virtual ~RedirectionManager() = default; + /// Change the redirection destination of given symbols to new destination /// symbols. virtual Error redirect(JITDylib &JD, const SymbolMap &NewDests) = 0; diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp index a79dbd5e4494f..968ed217d8a96 100644 --- a/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp @@ -29,6 +29,11 @@ const char PointerJumpStubContent[12] = { 0x00, 0x02, 0x1f, (char)0xd6u // BR x16 }; +const char ReentryTrampolineContent[8] = { + (char)0xfd, 0x7b, (char)0xbf, (char)0xa9, // STP x30, [sp, #-8] + 0x00, 0x00, 0x00, (char)0x94 // BL +}; + const char *getEdgeKindName(Edge::Kind R) { switch (R) { case Pointer64: diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt index ebfbeb990180f..5615ad94006d3 100644 --- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt @@ -29,6 +29,7 @@ add_llvm_component_library(LLVMOrcJIT IRTransformLayer.cpp IRPartitionLayer.cpp JITTargetMachineBuilder.cpp + JITLinkReentryTrampolines.cpp LazyObjectLinkingLayer.cpp LazyReexports.cpp Layer.cpp diff --git a/llvm/lib/ExecutionEngine/Orc/Core.cpp b/llvm/lib/ExecutionEngine/Orc/Core.cpp index 3547eabdd0ae7..e48548a8a7e49 100644 --- a/llvm/lib/ExecutionEngine/Orc/Core.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Core.cpp @@ -178,6 +178,27 @@ void UnexpectedSymbolDefinitions::log(raw_ostream &OS) const { << ": " << Symbols; } +void SymbolInstance::lookupAsync(LookupAsyncOnCompleteFn OnComplete) const { + JD->getExecutionSession().lookup( + LookupKind::Static, {{JD.get(), JITDylibLookupFlags::MatchAllSymbols}}, + SymbolLookupSet(Name), SymbolState::Ready, + [OnComplete = std::move(OnComplete) +#ifndef NDEBUG + , + Name = this->Name // Captured for the assert below only. +#endif // NDEBUG + ](Expected Result) mutable { + if (Result) { + assert(Result->size() == 1 && "Unexpected number of results"); + assert(Result->count(Name) && + "Result does not contain expected symbol"); + OnComplete(Result->begin()->second); + } else + OnComplete(Result.takeError()); + }, + NoDependenciesToRegister); +} + AsynchronousSymbolQuery::AsynchronousSymbolQuery( const SymbolLookupSet &Symbols, SymbolState RequiredState, SymbolsResolvedCallback NotifyComplete) diff --git a/llvm/lib/ExecutionEngine/Orc/JITLinkReentryTrampolines.cpp b/llvm/lib/ExecutionEngine/Orc/JITLinkReentryTrampolines.cpp new file mode 100644 index 0000000000000..90d2b857f1a4a --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/JITLinkReentryTrampolines.cpp @@ -0,0 +1,184 @@ +//===----- JITLinkReentryTrampolines.cpp -- JITLink-based trampoline- -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/Orc/JITLinkReentryTrampolines.h" + +#include "llvm/ExecutionEngine/JITLink/aarch64.h" +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" + +#include + +#define DEBUG_TYPE "orc" + +using namespace llvm; +using namespace llvm::jitlink; + +namespace { +constexpr StringRef ReentryFnName = "__orc_rt_reentry"; +constexpr StringRef ReentrySectionName = "__orc_stubs"; +} // namespace + +namespace llvm::orc { + +class JITLinkReentryTrampolines::TrampolineAddrScraperPlugin + : public ObjectLinkingLayer::Plugin { +public: + void modifyPassConfig(MaterializationResponsibility &MR, + jitlink::LinkGraph &G, + jitlink::PassConfiguration &Config) override { + Config.PreFixupPasses.push_back( + [this](LinkGraph &G) { return recordTrampolineAddrs(G); }); + } + + Error notifyFailed(MaterializationResponsibility &MR) override { + return Error::success(); + } + + Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override { + return Error::success(); + } + + void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, + ResourceKey SrcKey) override {} + + void registerGraph(LinkGraph &G, + std::shared_ptr> Addrs) { + std::lock_guard Lock(M); + assert(!PendingAddrs.count(&G) && "Duplicate registration"); + PendingAddrs[&G] = std::move(Addrs); + } + + Error recordTrampolineAddrs(LinkGraph &G) { + std::shared_ptr> Addrs; + { + std::lock_guard Lock(M); + auto I = PendingAddrs.find(&G); + if (I == PendingAddrs.end()) + return Error::success(); + Addrs = std::move(I->second); + PendingAddrs.erase(I); + } + + auto *Sec = G.findSectionByName(ReentrySectionName); + assert(Sec && "Reentry graph missing reentry section"); + assert(!Sec->empty() && "Reentry graph is empty"); + + for (auto *Sym : Sec->symbols()) + if (!Sym->hasName()) + Addrs->push_back({Sym->getAddress(), JITSymbolFlags()}); + + return Error::success(); + } + +private: + std::mutex M; + DenseMap>> + PendingAddrs; +}; + +Expected> +JITLinkReentryTrampolines::Create(ObjectLinkingLayer &ObjLinkingLayer) { + + EmitTrampolineFn EmitTrampoline; + + switch (ObjLinkingLayer.getExecutionSession().getTargetTriple().getArch()) { + case Triple::aarch64: + EmitTrampoline = aarch64::createAnonymousReentryTrampoline; + break; + default: + return make_error("Architecture not supported", + inconvertibleErrorCode()); + } + + return std::make_unique(ObjLinkingLayer, + std::move(EmitTrampoline)); +} + +JITLinkReentryTrampolines::JITLinkReentryTrampolines( + ObjectLinkingLayer &ObjLinkingLayer, EmitTrampolineFn EmitTrampoline) + : ObjLinkingLayer(ObjLinkingLayer), + EmitTrampoline(std::move(EmitTrampoline)) { + auto TAS = std::make_shared(); + TrampolineAddrScraper = TAS.get(); + ObjLinkingLayer.addPlugin(std::move(TAS)); +} + +void JITLinkReentryTrampolines::emit(ResourceTrackerSP RT, + size_t NumTrampolines, + OnTrampolinesReadyFn OnTrampolinesReady) { + + if (NumTrampolines == 0) + return OnTrampolinesReady(std::vector()); + + JITDylibSP JD(&RT->getJITDylib()); + auto &ES = ObjLinkingLayer.getExecutionSession(); + Triple TT = ES.getTargetTriple(); + + auto ReentryGraphSym = + ES.intern(("__orc_reentry_graph_#" + Twine(++ReentryGraphIdx)).str()); + + auto G = std::make_unique( + (*ReentryGraphSym).str(), ES.getSymbolStringPool(), TT, + TT.isArch64Bit() ? 8 : 4, + TT.isLittleEndian() ? endianness::little : endianness::big, + jitlink::getGenericEdgeKindName); + + auto &ReentryFnSym = G->addExternalSymbol(ReentryFnName, 0, false); + + auto &ReentrySection = + G->createSection(ReentrySectionName, MemProt::Exec | MemProt::Read); + + for (size_t I = 0; I != NumTrampolines; ++I) + EmitTrampoline(*G, ReentrySection, ReentryFnSym).setLive(true); + + auto &FirstBlock = **ReentrySection.blocks().begin(); + G->addDefinedSymbol(FirstBlock, 0, *ReentryGraphSym, FirstBlock.getSize(), + Linkage::Strong, Scope::SideEffectsOnly, true, true); + + auto TrampolineAddrs = std::make_shared>(); + TrampolineAddrScraper->registerGraph(*G, TrampolineAddrs); + + // Add Graph via object linking layer. + if (auto Err = ObjLinkingLayer.add(std::move(RT), std::move(G))) + return OnTrampolinesReady(std::move(Err)); + + // Trigger graph emission. + ES.lookup( + LookupKind::Static, {{JD.get(), JITDylibLookupFlags::MatchAllSymbols}}, + SymbolLookupSet(ReentryGraphSym, + SymbolLookupFlags::WeaklyReferencedSymbol), + SymbolState::Ready, + [OnTrampolinesReady = std::move(OnTrampolinesReady), + TrampolineAddrs = + std::move(TrampolineAddrs)](Expected Result) mutable { + if (Result) + OnTrampolinesReady(std::move(*TrampolineAddrs)); + else + OnTrampolinesReady(Result.takeError()); + }, + NoDependenciesToRegister); +} + +Expected> +createJITLinkLazyReexportsManager(ObjectLinkingLayer &ObjLinkingLayer, + RedirectableSymbolManager &RSMgr, + JITDylib &PlatformJD) { + auto JLT = JITLinkReentryTrampolines::Create(ObjLinkingLayer); + if (!JLT) + return JLT.takeError(); + + return LazyReexportsManager::Create( + [JLT = std::move(*JLT)](ResourceTrackerSP RT, size_t NumTrampolines, + LazyReexportsManager::OnTrampolinesReadyFn + OnTrampolinesReady) mutable { + JLT->emit(std::move(RT), NumTrampolines, std::move(OnTrampolinesReady)); + }, + RSMgr, PlatformJD); +} + +} // namespace llvm::orc diff --git a/llvm/lib/ExecutionEngine/Orc/LazyObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/LazyObjectLinkingLayer.cpp index 1eff9a1bdf08b..543337eb60f5d 100644 --- a/llvm/lib/ExecutionEngine/Orc/LazyObjectLinkingLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LazyObjectLinkingLayer.cpp @@ -71,10 +71,9 @@ class LazyObjectLinkingLayer::RenamerPlugin }; LazyObjectLinkingLayer::LazyObjectLinkingLayer(ObjectLinkingLayer &BaseLayer, - LazyCallThroughManager &LCTMgr, - RedirectableSymbolManager &RSMgr) + LazyReexportsManager &LRMgr) : ObjectLayer(BaseLayer.getExecutionSession()), BaseLayer(BaseLayer), - LCTMgr(LCTMgr), RSMgr(RSMgr) { + LRMgr(LRMgr) { BaseLayer.addPlugin(std::make_unique()); } @@ -101,8 +100,7 @@ Error LazyObjectLinkingLayer::add(ResourceTrackerSP RT, return Err; auto &JD = RT->getJITDylib(); - return JD.define(lazyReexports(LCTMgr, RSMgr, JD, std::move(LazySymbols)), - std::move(RT)); + return JD.define(lazyReexports(LRMgr, std::move(LazySymbols)), std::move(RT)); } void LazyObjectLinkingLayer::emit( diff --git a/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp b/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp index 15c5f79fdbd3c..7a7e5d13ce03f 100644 --- a/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp @@ -8,7 +8,9 @@ #include "llvm/ExecutionEngine/Orc/LazyReexports.h" +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" #include "llvm/ExecutionEngine/Orc/OrcABISupport.h" +#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h" #include "llvm/TargetParser/Triple.h" #define DEBUG_TYPE "orc" @@ -229,5 +231,167 @@ LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) { return MaterializationUnit::Interface(std::move(SymbolFlags), nullptr); } +class LazyReexportsManager::MU : public MaterializationUnit { +public: + MU(LazyReexportsManager &LRMgr, SymbolAliasMap Reexports) + : MaterializationUnit(getInterface(Reexports)), LRMgr(LRMgr), + Reexports(std::move(Reexports)) {} + +private: + Interface getInterface(const SymbolAliasMap &Reexports) { + SymbolFlagsMap SF; + for (auto &[Alias, AI] : Reexports) + SF[Alias] = AI.AliasFlags; + return {std::move(SF), nullptr}; + } + + StringRef getName() const override { return "LazyReexportsManager::MU"; } + + void materialize(std::unique_ptr R) override { + LRMgr.emitReentryTrampolines(std::move(R), std::move(Reexports)); + } + + void discard(const JITDylib &JD, const SymbolStringPtr &Name) override { + Reexports.erase(Name); + } + + LazyReexportsManager &LRMgr; + SymbolAliasMap Reexports; +}; + +class LazyReexportsManager::Plugin : public ObjectLinkingLayer::Plugin { +public: + void modifyPassConfig(MaterializationResponsibility &MR, + jitlink::LinkGraph &G, + jitlink::PassConfiguration &Config) override {} + + Error notifyFailed(MaterializationResponsibility &MR) override { + return Error::success(); + } + + Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override { + return Error::success(); + } + + void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, + ResourceKey SrcKey) override {} + +private: + std::mutex M; +}; + +Expected> +LazyReexportsManager::Create(EmitTrampolinesFn EmitTrampolines, + RedirectableSymbolManager &RSMgr, + JITDylib &PlatformJD) { + Error Err = Error::success(); + std::unique_ptr LRM(new LazyReexportsManager( + std::move(EmitTrampolines), RSMgr, PlatformJD, Err)); + if (Err) + return std::move(Err); + return std::move(LRM); +} + +LazyReexportsManager::LazyReexportsManager(EmitTrampolinesFn EmitTrampolines, + RedirectableSymbolManager &RSMgr, + JITDylib &PlatformJD, Error &Err) + : EmitTrampolines(std::move(EmitTrampolines)), RSMgr(RSMgr) { + + using namespace shared; + + ErrorAsOutParameter _(&Err); + + auto &ES = PlatformJD.getExecutionSession(); + ExecutionSession::JITDispatchHandlerAssociationMap WFs; + + WFs[ES.intern("__orc_rt_resolve_tag")] = + ES.wrapAsyncWithSPS(SPSExecutorAddr)>( + this, &LazyReexportsManager::resolve); + + Err = ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs)); +} + +std::unique_ptr +LazyReexportsManager::createLazyReexports(SymbolAliasMap Reexports) { + return std::make_unique(*this, std::move(Reexports)); +} + +void LazyReexportsManager::emitReentryTrampolines( + std::unique_ptr MR, + SymbolAliasMap Reexports) { + size_t NumTrampolines = Reexports.size(); + auto RT = MR->getResourceTracker(); + EmitTrampolines( + std::move(RT), NumTrampolines, + [this, MR = std::move(MR), Reexports = std::move(Reexports)]( + Expected> ReentryPoints) mutable { + emitRedirectableSymbols(std::move(MR), std::move(Reexports), + std::move(ReentryPoints)); + }); +} + +void LazyReexportsManager::emitRedirectableSymbols( + std::unique_ptr MR, SymbolAliasMap Reexports, + Expected> ReentryPoints) { + + if (!ReentryPoints) { + MR->getExecutionSession().reportError(ReentryPoints.takeError()); + MR->failMaterialization(); + return; + } + + assert(Reexports.size() == ReentryPoints->size() && + "Number of reentry points doesn't match number of reexports"); + + // Bind entry points to names. + SymbolMap Redirs; + { + std::lock_guard Lock(M); + size_t I = 0; + for (auto &[Name, AI] : Reexports) { + const auto &ReentryPoint = (*ReentryPoints)[I++]; + Redirs[Name] = ReentryPoint; + CallThroughs[ReentryPoint.getAddress()] = {Name, AI.Aliasee, + &MR->getTargetJITDylib()}; + } + } + + RSMgr.emitRedirectableSymbols(std::move(MR), std::move(Redirs)); +} + +void LazyReexportsManager::resolve(ResolveSendResultFn SendResult, + ExecutorAddr ReentryStubAddr) { + + CallThroughInfo LandingInfo; + + { + std::lock_guard Lock(M); + + auto I = CallThroughs.find(ReentryStubAddr); + if (I == CallThroughs.end()) + return SendResult(make_error( + "Reentry address " + formatv("{0:x}", ReentryStubAddr) + + " not registered", + inconvertibleErrorCode())); + LandingInfo = I->second; + } + + SymbolInstance LandingSym(LandingInfo.JD, std::move(LandingInfo.BodyName)); + LandingSym.lookupAsync([this, JD = std::move(LandingInfo.JD), + ReentryName = std::move(LandingInfo.Name), + SendResult = std::move(SendResult)]( + Expected Result) mutable { + if (Result) { + // FIXME: Make RedirectionManager operations async, then use the async + // APIs here. + if (auto Err = RSMgr.redirect(*JD, ReentryName, *Result)) + SendResult(std::move(Err)); + else + SendResult(std::move(Result)); + } else + SendResult(std::move(Result)); + }); +} + } // End namespace orc. } // End namespace llvm. diff --git a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp index f3fba51f2e743..3eee2fd027293 100644 --- a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp +++ b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp @@ -409,6 +409,7 @@ SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) { SymbolAliasMap Aliases; addAliases(ES, Aliases, requiredCXXAliases()); addAliases(ES, Aliases, standardRuntimeUtilityAliases()); + addAliases(ES, Aliases, standardLazyCompilationAliases()); return Aliases; } @@ -436,6 +437,17 @@ MachOPlatform::standardRuntimeUtilityAliases() { StandardRuntimeUtilityAliases); } +ArrayRef> +MachOPlatform::standardLazyCompilationAliases() { + static const std::pair + StandardLazyCompilationAliases[] = { + {"__orc_rt_reentry", "__orc_rt_sysv_reentry"}, + {"__orc_rt_resolve_tag", "___orc_rt_resolve_tag"}}; + + return ArrayRef>( + StandardLazyCompilationAliases); +} + bool MachOPlatform::supportedTarget(const Triple &TT) { switch (TT.getArch()) { case Triple::aarch64: diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp index 77c07cf5cdb45..3c58b8934462a 100644 --- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp +++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp @@ -30,6 +30,7 @@ #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" #include "llvm/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.h" +#include "llvm/ExecutionEngine/Orc/JITLinkReentryTrampolines.h" #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/LoadLinkableFile.h" #include "llvm/ExecutionEngine/Orc/MachO.h" @@ -949,41 +950,18 @@ class PhonyExternalsGenerator : public DefinitionGenerator { } }; -static void handleLazyCallFailure() { - dbgs() << "ERROR: failure to materialize lazy call-through target.\n"; - exit(1); -} - -static void *reenter(void *Ctx, void *TrampolineAddr) { - std::promise LandingAddressP; - auto LandingAddressF = LandingAddressP.get_future(); - - auto *EPCIU = static_cast(Ctx); - EPCIU->getLazyCallThroughManager().resolveTrampolineLandingAddress( - ExecutorAddr::fromPtr(TrampolineAddr), [&](ExecutorAddr LandingAddress) { - LandingAddressP.set_value(LandingAddress.toPtr()); - }); - return LandingAddressF.get(); -} - Expected> -createLazyLinkingSupport(ObjectLinkingLayer &OLL) { - auto EPCIU = EPCIndirectionUtils::Create(OLL.getExecutionSession()); - if (!EPCIU) - return EPCIU.takeError(); - if (auto Err = (*EPCIU) - ->writeResolverBlock(ExecutorAddr::fromPtr(&reenter), - ExecutorAddr::fromPtr(EPCIU->get())) - .takeError()) - return Err; - (*EPCIU)->createLazyCallThroughManager( - OLL.getExecutionSession(), ExecutorAddr::fromPtr(handleLazyCallFailure)); +createLazyLinkingSupport(ObjectLinkingLayer &OLL, JITDylib &PlatformJD) { auto RSMgr = JITLinkRedirectableSymbolManager::Create(OLL); if (!RSMgr) return RSMgr.takeError(); - return std::make_unique(std::move(*EPCIU), - std::move(*RSMgr), OLL); + auto LRMgr = createJITLinkLazyReexportsManager(OLL, **RSMgr, PlatformJD); + if (!LRMgr) + return LRMgr.takeError(); + + return std::make_unique(std::move(*RSMgr), + std::move(*LRMgr), OLL); } Expected> Session::Create(Triple TT, @@ -1020,7 +998,8 @@ Expected> Session::Create(Triple TT, S->Features = std::move(Features); if (lazyLinkingRequested()) { - if (auto LazyLinking = createLazyLinkingSupport(S->ObjLayer)) + if (auto LazyLinking = + createLazyLinkingSupport(S->ObjLayer, *S->PlatformJD)) S->LazyLinking = std::move(*LazyLinking); else return LazyLinking.takeError(); @@ -1642,10 +1621,17 @@ static Error sanitizeArguments(const Triple &TT, const char *ArgV0) { OutOfProcessExecutor = OOPExecutorPath.str().str(); } - if (lazyLinkingRequested() && !TestHarnesses.empty()) - return make_error( - "Lazy linking cannot be used with -harness mode", - inconvertibleErrorCode()); + // If lazy linking is requested then check compatibility with other options. + if (lazyLinkingRequested()) { + if (OrcRuntime.empty()) + return make_error("Lazy linking requries the ORC runtime", + inconvertibleErrorCode()); + + if (!TestHarnesses.empty()) + return make_error( + "Lazy linking cannot be used with -harness mode", + inconvertibleErrorCode()); + } return Error::success(); } diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.h b/llvm/tools/llvm-jitlink/llvm-jitlink.h index bdf91ea7e3f18..bfad5211c2176 100644 --- a/llvm/tools/llvm-jitlink/llvm-jitlink.h +++ b/llvm/tools/llvm-jitlink/llvm-jitlink.h @@ -15,9 +15,9 @@ #include "llvm/ADT/StringSet.h" #include "llvm/ExecutionEngine/Orc/Core.h" -#include "llvm/ExecutionEngine/Orc/EPCIndirectionUtils.h" #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" #include "llvm/ExecutionEngine/Orc/LazyObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/Orc/LazyReexports.h" #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" #include "llvm/ExecutionEngine/Orc/RedirectionManager.h" #include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h" @@ -33,20 +33,14 @@ namespace llvm { struct Session { struct LazyLinkingSupport { - LazyLinkingSupport(std::unique_ptr EPCIU, - std::unique_ptr RSMgr, + LazyLinkingSupport(std::unique_ptr RSMgr, + std::unique_ptr LRMgr, orc::ObjectLinkingLayer &ObjLinkingLayer) - : EPCIU(std::move(EPCIU)), RSMgr(std::move(RSMgr)), - LazyObjLinkingLayer(ObjLinkingLayer, - this->EPCIU->getLazyCallThroughManager(), - *this->RSMgr) {} - ~LazyLinkingSupport() { - if (auto Err = EPCIU->cleanup()) - LazyObjLinkingLayer.getExecutionSession().reportError(std::move(Err)); - } - - std::unique_ptr EPCIU; + : RSMgr(std::move(RSMgr)), LRMgr(std::move(LRMgr)), + LazyObjLinkingLayer(ObjLinkingLayer, *this->LRMgr) {} + std::unique_ptr RSMgr; + std::unique_ptr LRMgr; orc::LazyObjectLinkingLayer LazyObjLinkingLayer; }; From 9e1d009b7a06f650e857898a93727f2eb24a1aed Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Fri, 6 Dec 2024 16:43:09 +1100 Subject: [PATCH 2/4] Update lazy-link.ll --- compiler-rt/test/orc/TestCases/Generic/lazy-link.ll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll b/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll index a8a569a21ce85..abf9f626355df 100644 --- a/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll +++ b/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll @@ -11,7 +11,7 @@ ; RUN: -lazy %t/x.o | FileCheck %s ; ; UNSUPPORTED: system-windows -; REQUIRE: target={{(arm|aarch)64{.*}}} +; REQUIRES: target={{(arm|aarch)64{.*}}} ; ; CHECK: Linking {{.*}}main.o ; CHECK-DAG: Linking From bbcd64fc8d296a39c4851d45a53297003bba43e8 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Sat, 7 Dec 2024 07:57:55 +1100 Subject: [PATCH 3/4] Update lazy-link.ll --- compiler-rt/test/orc/TestCases/Generic/lazy-link.ll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll b/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll index abf9f626355df..e722b813c3fe0 100644 --- a/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll +++ b/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll @@ -11,7 +11,7 @@ ; RUN: -lazy %t/x.o | FileCheck %s ; ; UNSUPPORTED: system-windows -; REQUIRES: target={{(arm|aarch)64{.*}}} +; REQUIRES: target={{(arm|aarch)64.*}} ; ; CHECK: Linking {{.*}}main.o ; CHECK-DAG: Linking From 6aad37a33351af0781d8d587aa44d8bb2b579141 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Sat, 7 Dec 2024 07:59:24 +1100 Subject: [PATCH 4/4] Delete compiler-rt/test/orc/TestCases/Generic/orc-rt-executor-usage.test --- .../test/orc/TestCases/Generic/orc-rt-executor-usage.test | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 compiler-rt/test/orc/TestCases/Generic/orc-rt-executor-usage.test diff --git a/compiler-rt/test/orc/TestCases/Generic/orc-rt-executor-usage.test b/compiler-rt/test/orc/TestCases/Generic/orc-rt-executor-usage.test deleted file mode 100644 index e756477131d06..0000000000000 --- a/compiler-rt/test/orc/TestCases/Generic/orc-rt-executor-usage.test +++ /dev/null @@ -1,8 +0,0 @@ -// Test that the orc-remote-executor tool errors out as expected when called -// with no arguments. -// -// RUN: not %orc_rt_executor 2>&1 | FileCheck %s - -// REQUIRES: system-linux - -// CHECK: usage: orc-rt-executor [help] [] ...