1//===- MemoryMapper.h - Cross-process memory mapper -------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Cross-process (and in-process) memory mapping and transfer
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_EXECUTIONENGINE_ORC_MEMORYMAPPER_H
14#define LLVM_EXECUTIONENGINE_ORC_MEMORYMAPPER_H
15
16#include "llvm/ExecutionEngine/Orc/Core.h"
17#include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h"
18#include "llvm/Support/Process.h"
19
20#include <mutex>
21
22namespace llvm {
23namespace orc {
24
25/// Manages mapping, content transfer and protections for JIT memory
26class MemoryMapper {
27public:
28  /// Represents a single allocation containing multiple segments and
29  /// initialization and deinitialization actions
30  struct AllocInfo {
31    struct SegInfo {
32      ExecutorAddrDiff Offset;
33      const char *WorkingMem;
34      size_t ContentSize;
35      size_t ZeroFillSize;
36      AllocGroup AG;
37    };
38
39    ExecutorAddr MappingBase;
40    std::vector<SegInfo> Segments;
41    shared::AllocActions Actions;
42  };
43
44  using OnReservedFunction = unique_function<void(Expected<ExecutorAddrRange>)>;
45
46  // Page size of the target process
47  virtual unsigned int getPageSize() = 0;
48
49  /// Reserves address space in executor process
50  virtual void reserve(size_t NumBytes, OnReservedFunction OnReserved) = 0;
51
52  /// Provides working memory
53  virtual char *prepare(ExecutorAddr Addr, size_t ContentSize) = 0;
54
55  using OnInitializedFunction = unique_function<void(Expected<ExecutorAddr>)>;
56
57  /// Ensures executor memory is synchronized with working copy memory, sends
58  /// functions to be called after initilization and before deinitialization and
59  /// applies memory protections
60  /// Returns a unique address identifying the allocation. This address should
61  /// be passed to deinitialize to run deallocation actions (and reset
62  /// permissions where possible).
63  virtual void initialize(AllocInfo &AI,
64                          OnInitializedFunction OnInitialized) = 0;
65
66  using OnDeinitializedFunction = unique_function<void(Error)>;
67
68  /// Runs previously specified deinitialization actions
69  /// Executor addresses returned by initialize should be passed
70  virtual void deinitialize(ArrayRef<ExecutorAddr> Allocations,
71                            OnDeinitializedFunction OnDeInitialized) = 0;
72
73  using OnReleasedFunction = unique_function<void(Error)>;
74
75  /// Release address space acquired through reserve()
76  virtual void release(ArrayRef<ExecutorAddr> Reservations,
77                       OnReleasedFunction OnRelease) = 0;
78
79  virtual ~MemoryMapper();
80};
81
82class InProcessMemoryMapper : public MemoryMapper {
83public:
84  InProcessMemoryMapper(size_t PageSize);
85
86  static Expected<std::unique_ptr<InProcessMemoryMapper>> Create();
87
88  unsigned int getPageSize() override { return PageSize; }
89
90  void reserve(size_t NumBytes, OnReservedFunction OnReserved) override;
91
92  void initialize(AllocInfo &AI, OnInitializedFunction OnInitialized) override;
93
94  char *prepare(ExecutorAddr Addr, size_t ContentSize) override;
95
96  void deinitialize(ArrayRef<ExecutorAddr> Allocations,
97                    OnDeinitializedFunction OnDeInitialized) override;
98
99  void release(ArrayRef<ExecutorAddr> Reservations,
100               OnReleasedFunction OnRelease) override;
101
102  ~InProcessMemoryMapper() override;
103
104private:
105  struct Allocation {
106    size_t Size;
107    std::vector<shared::WrapperFunctionCall> DeinitializationActions;
108  };
109  using AllocationMap = DenseMap<ExecutorAddr, Allocation>;
110
111  struct Reservation {
112    size_t Size;
113    std::vector<ExecutorAddr> Allocations;
114  };
115  using ReservationMap = DenseMap<void *, Reservation>;
116
117  std::mutex Mutex;
118  ReservationMap Reservations;
119  AllocationMap Allocations;
120
121  size_t PageSize;
122};
123
124class SharedMemoryMapper final : public MemoryMapper {
125public:
126  struct SymbolAddrs {
127    ExecutorAddr Instance;
128    ExecutorAddr Reserve;
129    ExecutorAddr Initialize;
130    ExecutorAddr Deinitialize;
131    ExecutorAddr Release;
132  };
133
134  SharedMemoryMapper(ExecutorProcessControl &EPC, SymbolAddrs SAs,
135                     size_t PageSize);
136
137  static Expected<std::unique_ptr<SharedMemoryMapper>>
138  Create(ExecutorProcessControl &EPC, SymbolAddrs SAs);
139
140  unsigned int getPageSize() override { return PageSize; }
141
142  void reserve(size_t NumBytes, OnReservedFunction OnReserved) override;
143
144  char *prepare(ExecutorAddr Addr, size_t ContentSize) override;
145
146  void initialize(AllocInfo &AI, OnInitializedFunction OnInitialized) override;
147
148  void deinitialize(ArrayRef<ExecutorAddr> Allocations,
149                    OnDeinitializedFunction OnDeInitialized) override;
150
151  void release(ArrayRef<ExecutorAddr> Reservations,
152               OnReleasedFunction OnRelease) override;
153
154  ~SharedMemoryMapper() override;
155
156private:
157  struct Reservation {
158    void *LocalAddr;
159    size_t Size;
160  };
161
162  ExecutorProcessControl &EPC;
163  SymbolAddrs SAs;
164
165  std::mutex Mutex;
166
167  std::map<ExecutorAddr, Reservation> Reservations;
168
169  size_t PageSize;
170};
171
172} // namespace orc
173} // end namespace llvm
174
175#endif // LLVM_EXECUTIONENGINE_ORC_MEMORYMAPPER_H
176