[llvm] 7163b1a - [JITLink][docs] Update docs for generic link algorithm and memory manager apis.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 9 23:37:38 PST 2023


Author: Lang Hames
Date: 2023-03-09T23:37:32-08:00
New Revision: 7163b1ab8d95905fb7fe4cd1a60102ce57e76ecb

URL: https://github.com/llvm/llvm-project/commit/7163b1ab8d95905fb7fe4cd1a60102ce57e76ecb
DIFF: https://github.com/llvm/llvm-project/commit/7163b1ab8d95905fb7fe4cd1a60102ce57e76ecb.diff

LOG: [JITLink][docs] Update docs for generic link algorithm and memory manager apis.

These sections were out of date.

Added: 
    

Modified: 
    llvm/docs/JITLink.rst

Removed: 
    


################################################################################
diff  --git a/llvm/docs/JITLink.rst b/llvm/docs/JITLink.rst
index 55425eeb08ab..8316892ba794 100644
--- a/llvm/docs/JITLink.rst
+++ b/llvm/docs/JITLink.rst
@@ -419,7 +419,12 @@ Generic Link Algorithm
 ======================
 
 JITLink provides a generic link algorithm which can be extended / modified at
-certain points by the introduction of JITLink :ref:`passes`:
+certain points by the introduction of JITLink :ref:`passes`.
+
+At the end of each phase the linker packages its state into a *continuation*
+and calls the ``JITLinkContext`` object to perform a (potentialy high-latency)
+asynchronous operation: allocating memory, resolving external symbols, and
+finally transferring linked memory to the executing process.
 
 #. Phase 1
 
@@ -457,21 +462,18 @@ certain points by the introduction of JITLink :ref:`passes`:
       Notable use cases: Building Global Offset Table (GOT), Procedure Linkage
       Table (PLT), and Thread Local Variable (TLV) entries.
 
-   #. Sort blocks into segments.
-
-      Sorts all blocks by ordinal and then address. Collects sections with
-      matching permissions into segments and computes the size of these
-      segments for memory allocation.
-
-   #. Allocate segment memory, update node addresses.
+   #. Asynchronously allocate memory.
 
       Calls the ``JITLinkContext``'s ``JITLinkMemoryManager`` to allocate both
-      working and target memory for the graph, then updates all node addresses
-      to their assigned target address.
+      working and target memory for the graph. As part of this process the
+      ``JITLinkMemoryManager`` will update the the addresses of all nodes
+      defined in the graph to their assigned target address.
 
       Note: This step only updates the addresses of nodes defined in this graph.
       External symbols will still have null addresses.
 
+#. Phase 2
+
    #. Run post-allocation passes.
 
       These passes are run on the graph after working and target memory have
@@ -497,15 +499,9 @@ certain points by the introduction of JITLink :ref:`passes`:
    #. Identify external symbols and resolve their addresses asynchronously.
 
       Calls the ``JITLinkContext`` to resolve the target address of any external
-      symbols in the graph. This step is asynchronous -- JITLink will pack the
-      link state into a *continuation* to be run once the symbols are resolved.
+      symbols in the graph.
 
-      This is the final step of Phase 1.
-
-#. Phase 2
-
-   This phase is called by the continuation constructed at the end of the
-   external symbol resolution step above.
+#. Phase 3
 
    #. Apply external symbol resolution results.
 
@@ -541,21 +537,14 @@ certain points by the introduction of JITLink :ref:`passes`:
    #. Finalize memory asynchronously.
 
       Calls the ``JITLinkMemoryManager`` to copy working memory to the executor
-      process and apply the requested permissions. This step is asynchronous --
-      JITLink will pack the link state into a *continuation* to be run once
-      memory has been copied and protected.
-
-      This is the final step of Phase 2.
+      process and apply the requested permissions.
 
 #. Phase 3.
 
-   This phase is called by the continuation constructed at the end of the
-   memory finalization step above.
-
    #. Notify the context that the graph has been emitted.
 
       Calls ``JITLinkContext::notifyFinalized`` and hands off the
-      ``JITLinkMemoryManager::Allocation`` object for this graph's memory
+      ``JITLinkMemoryManager::FinalizedAlloc`` object for this graph's memory
       allocation. This allows the context to track/hold memory allocations and
       react to the newly emitted definitions. In ORC this is used to update the
       ``ExecutionSession`` instance's dependence graph, which may result in
@@ -664,58 +653,84 @@ the common case of running across processes on the same machine for security)
 via the host operating system's virtual memory management APIs.
 
 To satisfy these requirements ``JITLinkMemoryManager`` adopts the following
-design: The memory manager itself has just one virtual method that returns a
-``JITLinkMemoryManager::Allocation``:
+design: The memory manager itself has just two virtual methods for asynchronous
+operations (each with convenience overloads for calling synchronously):
 
 .. code-block:: c++
 
-  virtual Expected<std::unique_ptr<Allocation>>
-  allocate(const JITLinkDylib *JD, const SegmentsRequestMap &Request) = 0;
+  /// Called when allocation has been completed.
+  using OnAllocatedFunction =
+    unique_function<void(Expected<std::unique_ptr<InFlightAlloc>)>;
+
+  /// Called when deallocation has completed.
+  using OnDeallocatedFunction = unique_function<void(Error)>;
+
+  /// Call to allocate memory.
+  virtual void allocate(const JITLinkDylib *JD, LinkGraph &G,
+                        OnAllocatedFunction OnAllocated) = 0;
+
+  /// Call to deallocate memory.
+  virtual void deallocate(std::vector<FinalizedAlloc> Allocs,
+                          OnDeallocatedFunction OnDeallocated) = 0;
 
-This method takes a ``JITLinkDylib*`` representing the target simulated
-dylib, and the full set of sections that must be allocated for this object.
+The ``allocate`` method takes a ``JITLinkDylib*`` representing the target
+simulated dylib, a reference to the ``LinkGraph`` that must be allocated for,
+and a callback to run once an ``InFlightAlloc`` has been constructed.
 ``JITLinkMemoryManager`` implementations can (optionally) use the ``JD``
 argument to manage a per-simulated-dylib memory pool (since code model
 constraints are typically imposed on a per-dylib basis, and not across
-dylibs) [2]_. The ``Request`` argument, by describing all sections in the current
-object up-front, allows the implementer to allocate those sections as a
-single slab, either within a pre-allocated per-jitdylib pool or directly
-from system memory.
+dylibs) [2]_. The ``LinkGraph`` describes the object file that we need to
+allocate memory for. The allocator must allocate working memory for all of
+the Blocks defined in the graph, assign address space for each Block within the
+executing processes memory, and update the Blocks' addresses to reflect this
+assignment. Block content should be copied to working memory, but does not need
+to be transferred to executor memory yet (that will be done once the content is
+fixed up). ``JITLinkMemoryManager`` implementations can take full
+responsibility for these steps, or use the ``BasicLayout`` utility to reduce
+the task to allocating working and executor memory for *segments*: chunks of
+memory defined by permissions, alignments, content sizes, and zero-fill sizes.
+Once the allocation step is complete the memory manager should construct an
+``InFlightAlloc`` object to represent the allocation, and then pass this object
+to the ``OnAllocated`` callback.
+
+The ``InFlightAlloc`` object has two virtual methods:
 
-All subsequent operations are provided by the
-``JITLinkMemoryManager::Allocation`` interface:
-
-* ``virtual MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg)``
-
-  Should be overridden to return the address in working memory of the segment
-  with the given protection flags.
+.. code-block:: c++
 
-* ``virtual JITTargetAddress getTargetMemory(ProtectionFlags Seg)``
+    using OnFinalizedFunction = unique_function<void(Expected<FinalizedAlloc>)>;
+    using OnAbandonedFunction = unique_function<void(Error)>;
 
-  Should be overridden to return the address in the executor's address space of
-  the segment with the given protection flags.
+    /// Called prior to finalization if the allocation should be abandoned.
+    virtual void abandon(OnAbandonedFunction OnAbandoned) = 0;
 
-* ``virtual void finalizeAsync(FinalizeContinuation OnFinalize)``
+    /// Called to transfer working memory to the target and apply finalization.
+    virtual void finalize(OnFinalizedFunction OnFinalized) = 0;
 
-  Should be overridden to copy the contents of working memory to the target
-  address space and apply memory protections for all segments. Where working
-  memory and target memory are separate, this method should deallocate the
-  working memory.
+The linking process will call the ``finalize`` method on the ``InFlightAlloc``
+object if linking succeeds up to the finalization step, otherwise it will call
+``abandon`` to indicate that some error occurred during linking. A call to the
+``InFlightAlloc::finalize`` method should cause content for the allocation to be
+transferred from working to executor memory, and permissions to be run. A call
+to ``abandon`` should result in both kinds of memory being deallocated.
 
-* ``virtual Error deallocate()``
+On successful finalization, the ``InFlightAlloc::finalize`` method should
+construct a ``FinalizedAlloc`` object (an opaque uint64_t id that the
+``JITLinkMemoryManager`` can use to identify executor memory for deallocation)
+and pass it to the ``OnFinalized`` callback.
 
-  Should be overridden to deallocate memory in the target address space.
+Finalized allocations (represented by ``FinalizedAlloc`` objects) can be
+deallocated by calling the ``JITLinkMemoryManager::dealloc`` method. This method
+takes a vector of ``FinalizedAlloc`` objects, since it is common to deallocate
+multiple objects at the same time and this allows us to batch these requsets for
+transmission to the executing process.
 
 JITLink provides a simple in-process implementation of this interface:
 ``InProcessMemoryManager``. It allocates pages once and re-uses them as both
 working and target memory.
 
-ORC provides a cross-process ``JITLinkMemoryManager`` based on an ORC-RPC-based
-implementation of the ``orc::TargetProcessControl`` API:
-``OrcRPCTPCJITLinkMemoryManager``. This API uses TargetProcessControl API calls
-to allocate and manage memory in a remote process. The underlying communication
-channel is determined by the ORC-RPC channel type. Common options include unix
-sockets or TCP.
+ORC provides a cross-process-capable ``MapperJITLinkMemoryManager`` that can use
+shared memory or ORC-RPC-based communication to transfer content to the executing
+process.
 
 JITLinkMemoryManager and Security
 ---------------------------------


        


More information about the llvm-commits mailing list