llvm.org GIT mirror llvm / fb51095
[ORC] Add ObjectTransformLayer Summary: This is a utility for clients that want to insert a layer that modifies each ObjectFile and then passes it along to the next layer. Reviewers: lhames Reviewed By: lhames Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D10456 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@240640 91177308-0d34-0410-b5e6-96231b3b80d8 Joseph Tremoulet 5 years ago
3 changed file(s) with 414 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 //===- ObjectTransformLayer.h - Run all objects through functor -*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Run all objects passed in through a user supplied functor.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_EXECUTIONENGINE_ORC_OBJECTTRANSFORMLAYER_H
14 #define LLVM_EXECUTIONENGINE_ORC_OBJECTTRANSFORMLAYER_H
15
16 #include "JITSymbol.h"
17
18 namespace llvm {
19 namespace orc {
20
21 /// @brief Object mutating layer.
22 ///
23 /// This layer accepts sets of ObjectFiles (via addObjectSet). It
24 /// immediately applies the user supplied functor to each object, then adds
25 /// the set of transformed objects to the layer below.
26 template
27 class ObjectTransformLayer {
28 public:
29 /// @brief Handle to a set of added objects.
30 typedef typename BaseLayerT::ObjSetHandleT ObjSetHandleT;
31
32 /// @brief Construct an ObjectTransformLayer with the given BaseLayer
33 ObjectTransformLayer(BaseLayerT &BaseLayer,
34 TransformFtor Transform = TransformFtor())
35 : BaseLayer(BaseLayer), Transform(std::move(Transform)) {}
36
37 /// @brief Apply the transform functor to each object in the object set, then
38 /// add the resulting set of objects to the base layer, along with the
39 /// memory manager and symbol resolver.
40 ///
41 /// @return A handle for the added objects.
42 template
43 typename SymbolResolverPtrT>
44 ObjSetHandleT addObjectSet(ObjSetT &Objects, MemoryManagerPtrT MemMgr,
45 SymbolResolverPtrT Resolver) {
46
47 for (auto I = Objects.begin(), E = Objects.end(); I != E; ++I)
48 *I = Transform(std::move(*I));
49
50 return BaseLayer.addObjectSet(Objects, std::move(MemMgr),
51 std::move(Resolver));
52 }
53
54 /// @brief Remove the object set associated with the handle H.
55 void removeObjectSet(ObjSetHandleT H) { BaseLayer.removeObjectSet(H); }
56
57 /// @brief Search for the given named symbol.
58 /// @param Name The name of the symbol to search for.
59 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
60 /// @return A handle for the given named symbol, if it exists.
61 JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
62 return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
63 }
64
65 /// @brief Get the address of the given symbol in the context of the set of
66 /// objects represented by the handle H. This call is forwarded to the
67 /// base layer's implementation.
68 /// @param H The handle for the object set to search in.
69 /// @param Name The name of the symbol to search for.
70 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
71 /// @return A handle for the given named symbol, if it is found in the
72 /// given object set.
73 JITSymbol findSymbolIn(ObjSetHandleT H, const std::string &Name,
74 bool ExportedSymbolsOnly) {
75 return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly);
76 }
77
78 /// @brief Immediately emit and finalize the object set represented by the
79 /// given handle.
80 /// @param H Handle for object set to emit/finalize.
81 void emitAndFinalize(ObjSetHandleT H) { BaseLayer.emitAndFinalize(H); }
82
83 /// @brief Map section addresses for the objects associated with the handle H.
84 void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
85 TargetAddress TargetAddr) {
86 BaseLayer.mapSectionAddress(H, LocalAddress, TargetAddr);
87 }
88
89 // Ownership hack.
90 // FIXME: Remove this as soon as RuntimeDyldELF can apply relocations without
91 // referencing the original object.
92 template
93 void takeOwnershipOfBuffers(ObjSetHandleT H, OwningMBSet MBs) {
94 BaseLayer.takeOwnershipOfBuffers(H, std::move(MBs));
95 }
96
97 /// @brief Access the transform functor directly.
98 TransformFtor &getTransform() { return Transform; }
99
100 /// @brief Access the mumate functor directly.
101 const TransformFtor &getTransform() const { return Transform; }
102
103 private:
104 BaseLayerT &BaseLayer;
105 TransformFtor Transform;
106 };
107
108 } // End namespace orc.
109 } // End namespace llvm.
110
111 #endif // LLVM_EXECUTIONENGINE_ORC_OBJECTTRANSFORMLAYER_H
66 add_llvm_unittest(OrcJITTests
77 IndirectionUtilsTest.cpp
88 LazyEmittingLayerTest.cpp
9 ObjectTransformLayerTest.cpp
910 OrcTestCommon.cpp
1011 )
0 //===- ObjectTransformLayerTest.cpp - Unit tests for ObjectTransformLayer -===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
10 #include "llvm/ADT/SmallVector.h"
11 #include "gtest/gtest.h"
12
13 using namespace llvm::orc;
14
15 namespace {
16
17 // Stand-in for RuntimeDyld::MemoryManager
18 typedef int MockMemoryManager;
19
20 // Stand-in for RuntimeDyld::SymbolResolver
21 typedef int MockSymbolResolver;
22
23 // stand-in for object::ObjectFile
24 typedef int MockObjectFile;
25
26 // stand-in for llvm::MemoryBuffer set
27 typedef int MockMemoryBufferSet;
28
29 // Mock transform that operates on unique pointers to object files, and
30 // allocates new object files rather than mutating the given ones.
31 struct AllocatingTransform {
32 std::unique_ptr
33 operator()(std::unique_ptr Obj) const {
34 return std::make_unique(*Obj + 1);
35 }
36 };
37
38 // Mock base layer for verifying behavior of transform layer.
39 // Each method "T foo(args)" is accompanied by two auxiliary methods:
40 // - "void expectFoo(args)", to be called before calling foo on the transform
41 // layer; saves values of args, which mock layer foo then verifies against.
42 // - "void verifyFoo(T)", to be called after foo, which verifies that the
43 // transform layer called the base layer and forwarded any return value.
44 class MockBaseLayer {
45 public:
46 typedef int ObjSetHandleT;
47
48 MockBaseLayer() : MockSymbol(nullptr) { resetExpectations(); }
49
50 template
51 typename SymbolResolverPtrT>
52 ObjSetHandleT addObjectSet(ObjSetT &Objects, MemoryManagerPtrT MemMgr,
53 SymbolResolverPtrT Resolver) {
54 EXPECT_EQ(MockManager, *MemMgr) << "MM should pass through";
55 EXPECT_EQ(MockResolver, *Resolver) << "Resolver should pass through";
56 int I = 0;
57 for (auto &ObjPtr : Objects) {
58 EXPECT_EQ(MockObjects[I++] + 1, *ObjPtr) << "Transform should be applied";
59 }
60 EXPECT_EQ(MockObjects.size(), I) << "Number of objects should match";
61 LastCalled = "addObjectSet";
62 MockObjSetHandle = 111;
63 return MockObjSetHandle;
64 }
65 template
66 void expectAddObjectSet(ObjSetT &Objects, MockMemoryManager *MemMgr,
67 MockSymbolResolver *Resolver) {
68 MockManager = *MemMgr;
69 MockResolver = *Resolver;
70 for (auto &ObjPtr : Objects) {
71 MockObjects.push_back(*ObjPtr);
72 }
73 }
74 void verifyAddObjectSet(ObjSetHandleT Returned) {
75 EXPECT_EQ("addObjectSet", LastCalled);
76 EXPECT_EQ(MockObjSetHandle, Returned) << "Return should pass through";
77 resetExpectations();
78 }
79
80 void removeObjectSet(ObjSetHandleT H) {
81 EXPECT_EQ(MockObjSetHandle, H);
82 LastCalled = "removeObjectSet";
83 }
84 void expectRemoveObjectSet(ObjSetHandleT H) { MockObjSetHandle = H; }
85 void verifyRemoveObjectSet() {
86 EXPECT_EQ("removeObjectSet", LastCalled);
87 resetExpectations();
88 }
89
90 JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
91 EXPECT_EQ(MockName, Name) << "Name should pass through";
92 EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
93 LastCalled = "findSymbol";
94 MockSymbol = JITSymbol(122, llvm::JITSymbolFlags::None);
95 return MockSymbol;
96 }
97 void expectFindSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
98 MockName = Name;
99 MockBool = ExportedSymbolsOnly;
100 }
101 void verifyFindSymbol(llvm::orc::JITSymbol Returned) {
102 EXPECT_EQ("findSymbol", LastCalled);
103 EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
104 << "Return should pass through";
105 resetExpectations();
106 }
107
108 JITSymbol findSymbolIn(ObjSetHandleT H, const std::string &Name,
109 bool ExportedSymbolsOnly) {
110 EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
111 EXPECT_EQ(MockName, Name) << "Name should pass through";
112 EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
113 LastCalled = "findSymbolIn";
114 MockSymbol = JITSymbol(122, llvm::JITSymbolFlags::None);
115 return MockSymbol;
116 }
117 void expectFindSymbolIn(ObjSetHandleT H, const std::string &Name,
118 bool ExportedSymbolsOnly) {
119 MockObjSetHandle = H;
120 MockName = Name;
121 MockBool = ExportedSymbolsOnly;
122 }
123 void verifyFindSymbolIn(llvm::orc::JITSymbol Returned) {
124 EXPECT_EQ("findSymbolIn", LastCalled);
125 EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
126 << "Return should pass through";
127 resetExpectations();
128 }
129
130 void emitAndFinalize(ObjSetHandleT H) {
131 EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
132 LastCalled = "emitAndFinalize";
133 }
134 void expectEmitAndFinalize(ObjSetHandleT H) { MockObjSetHandle = H; }
135 void verifyEmitAndFinalize() {
136 EXPECT_EQ("emitAndFinalize", LastCalled);
137 resetExpectations();
138 }
139
140 void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
141 TargetAddress TargetAddr) {
142 EXPECT_EQ(MockObjSetHandle, H);
143 EXPECT_EQ(MockLocalAddress, LocalAddress);
144 EXPECT_EQ(MockTargetAddress, TargetAddr);
145 LastCalled = "mapSectionAddress";
146 }
147 void expectMapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
148 TargetAddress TargetAddr) {
149 MockObjSetHandle = H;
150 MockLocalAddress = LocalAddress;
151 MockTargetAddress = TargetAddr;
152 }
153 void verifyMapSectionAddress() {
154 EXPECT_EQ("mapSectionAddress", LastCalled);
155 resetExpectations();
156 }
157
158 template
159 void takeOwnershipOfBuffers(ObjSetHandleT H, OwningMBSet MBs) {
160 EXPECT_EQ(MockObjSetHandle, H);
161 EXPECT_EQ(MockBufferSet, *MBs);
162 LastCalled = "takeOwnershipOfBuffers";
163 }
164 void expectTakeOwnershipOfBuffers(ObjSetHandleT H, MockMemoryBufferSet *MBs) {
165 MockObjSetHandle = H;
166 MockBufferSet = *MBs;
167 }
168 void verifyTakeOwnershipOfBuffers() {
169 EXPECT_EQ("takeOwnershipOfBuffers", LastCalled);
170 resetExpectations();
171 }
172
173 private:
174 // Backing fields for remembering parameter/return values
175 std::string LastCalled;
176 MockMemoryManager MockManager;
177 MockSymbolResolver MockResolver;
178 std::vector MockObjects;
179 ObjSetHandleT MockObjSetHandle;
180 std::string MockName;
181 bool MockBool;
182 JITSymbol MockSymbol;
183 const void *MockLocalAddress;
184 TargetAddress MockTargetAddress;
185 MockMemoryBufferSet MockBufferSet;
186
187 // Clear remembered parameters between calls
188 void resetExpectations() {
189 LastCalled = "nothing";
190 MockManager = 0;
191 MockResolver = 0;
192 MockObjects.clear();
193 MockObjSetHandle = 0;
194 MockName = "bogus";
195 MockSymbol = JITSymbol(nullptr);
196 MockLocalAddress = nullptr;
197 MockTargetAddress = 0;
198 MockBufferSet = 0;
199 }
200 };
201
202 // Test each operation on ObjectTransformLayer.
203 TEST(ObjectTransformLayerTest, Main) {
204 MockBaseLayer M;
205
206 // Create one object transform layer using a transform (as a functor)
207 // that allocates new objects, and deals in unique pointers.
208 ObjectTransformLayer T1(M);
209
210 // Create a second object transform layer using a transform (as a lambda)
211 // that mutates objects in place, and deals in naked pointers
212 ObjectTransformLayer
213 std::function>
214 T2(M, [](MockObjectFile *Obj) {
215 ++(*Obj);
216 return Obj;
217 });
218
219 // Instantiate some mock objects to use below
220 MockObjectFile MockObject1 = 211;
221 MockObjectFile MockObject2 = 222;
222 MockMemoryManager MockManager = 233;
223 MockSymbolResolver MockResolver = 244;
224
225 // Test addObjectSet with T1 (allocating, unique pointers)
226 std::vector> Objs1;
227 Objs1.push_back(std::make_unique(MockObject1));
228 Objs1.push_back(std::make_unique(MockObject2));
229 auto MM = std::make_unique(MockManager);
230 auto SR = std::make_unique(MockResolver);
231 M.expectAddObjectSet(Objs1, MM.get(), SR.get());
232 auto H = T1.addObjectSet(Objs1, std::move(MM), std::move(SR));
233 M.verifyAddObjectSet(H);
234
235 // Test addObjectSet with T2 (mutating, naked pointers)
236 llvm::SmallVector Objs2;
237 Objs2.push_back(&MockObject1);
238 Objs2.push_back(&MockObject2);
239 M.expectAddObjectSet(Objs2, &MockManager, &MockResolver);
240 H = T2.addObjectSet(Objs2, &MockManager, &MockResolver);
241 M.verifyAddObjectSet(H);
242 EXPECT_EQ(212, MockObject1) << "Expected mutation";
243 EXPECT_EQ(223, MockObject2) << "Expected mutation";
244
245 // Test removeObjectSet
246 M.expectRemoveObjectSet(H);
247 T1.removeObjectSet(H);
248 M.verifyRemoveObjectSet();
249
250 // Test findSymbol
251 std::string Name = "foo";
252 bool ExportedOnly = true;
253 M.expectFindSymbol(Name, ExportedOnly);
254 JITSymbol Symbol = T2.findSymbol(Name, ExportedOnly);
255 M.verifyFindSymbol(Symbol);
256
257 // Test findSymbolIn
258 Name = "bar";
259 ExportedOnly = false;
260 M.expectFindSymbolIn(H, Name, ExportedOnly);
261 Symbol = T1.findSymbolIn(H, Name, ExportedOnly);
262 M.verifyFindSymbolIn(Symbol);
263
264 // Test emitAndFinalize
265 M.expectEmitAndFinalize(H);
266 T2.emitAndFinalize(H);
267 M.verifyEmitAndFinalize();
268
269 // Test mapSectionAddress
270 char Buffer[24];
271 TargetAddress MockAddress = 255;
272 M.expectMapSectionAddress(H, Buffer, MockAddress);
273 T1.mapSectionAddress(H, Buffer, MockAddress);
274 M.verifyMapSectionAddress();
275
276 // Test takeOwnershipOfBuffers, using unique pointer to buffer set
277 auto MockBufferSetPtr = std::make_unique(366);
278 M.expectTakeOwnershipOfBuffers(H, MockBufferSetPtr.get());
279 T2.takeOwnershipOfBuffers(H, std::move(MockBufferSetPtr));
280 M.verifyTakeOwnershipOfBuffers();
281
282 // Test takeOwnershipOfBuffers, using naked pointer to buffer set
283 MockMemoryBufferSet MockBufferSet = 266;
284 M.expectTakeOwnershipOfBuffers(H, &MockBufferSet);
285 T1.takeOwnershipOfBuffers(H, &MockBufferSet);
286 M.verifyTakeOwnershipOfBuffers();
287
288 // Verify transform getter (non-const)
289 MockObjectFile Mutatee = 277;
290 MockObjectFile *Out = T2.getTransform()(&Mutatee);
291 EXPECT_EQ(&Mutatee, Out) << "Expected in-place transform";
292 EXPECT_EQ(278, Mutatee) << "Expected incrementing transform";
293
294 // Verify transform getter (const)
295 auto OwnedObj = std::make_unique(288);
296 const auto &T1C = T1;
297 OwnedObj = T1C.getTransform()(std::move(OwnedObj));
298 EXPECT_EQ(289, *OwnedObj) << "Expected incrementing transform";
299 }
300 }