blob: da76890d73df30d6929b6e08c0a7c8359b6a756c [file] [log] [blame]
Lang Hames617fc352017-09-05 03:34:09 +00001//===---------------------- RemoteObjectLayerTest.cpp ---------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
11#include "llvm/ExecutionEngine/Orc/NullResolver.h"
12#include "llvm/ExecutionEngine/Orc/RemoteObjectLayer.h"
13#include "OrcTestCommon.h"
14#include "QueueChannel.h"
15#include "gtest/gtest.h"
16
17using namespace llvm;
18using namespace llvm::orc;
19
20namespace {
21
22class MockObjectLayer {
23public:
24
25 using ObjHandleT = uint64_t;
26
27 using ObjectPtr =
28 std::shared_ptr<object::OwningBinary<object::ObjectFile>>;
29
30 using LookupFn = std::function<JITSymbol(StringRef, bool)>;
31 using SymbolLookupTable = std::map<ObjHandleT, LookupFn>;
32
33 using AddObjectFtor =
34 std::function<Expected<ObjHandleT>(ObjectPtr, SymbolLookupTable&)>;
35
36 class ObjectNotFound : public remote::ResourceNotFound<ObjHandleT> {
37 public:
38 ObjectNotFound(ObjHandleT H) : ResourceNotFound(H, "Object handle") {}
39 };
40
41 MockObjectLayer(AddObjectFtor AddObject)
42 : AddObject(std::move(AddObject)) {}
43
44 Expected<ObjHandleT> addObject(ObjectPtr Obj,
45 std::shared_ptr<JITSymbolResolver> Resolver) {
46 return AddObject(Obj, SymTab);
47 }
48
49 Error removeObject(ObjHandleT H) {
50 if (SymTab.count(H))
51 return Error::success();
52 else
53 return make_error<ObjectNotFound>(H);
54 }
55
56 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
57 for (auto KV : SymTab) {
58 if (auto Sym = KV.second(Name, ExportedSymbolsOnly))
59 return Sym;
60 else if (auto Err = Sym.takeError())
61 return std::move(Err);
62 }
63 return JITSymbol(nullptr);
64 }
65
66 JITSymbol findSymbolIn(ObjHandleT H, StringRef Name,
67 bool ExportedSymbolsOnly) {
68 auto LI = SymTab.find(H);
69 if (LI != SymTab.end())
70 return LI->second(Name, ExportedSymbolsOnly);
71 else
72 return make_error<ObjectNotFound>(H);
73 }
74
75 Error emitAndFinalize(ObjHandleT H) {
76 if (SymTab.count(H))
77 return Error::success();
78 else
79 return make_error<ObjectNotFound>(H);
80 }
81
82private:
83 AddObjectFtor AddObject;
84 SymbolLookupTable SymTab;
85};
86
87using RPCEndpoint = rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>;
88
89MockObjectLayer::ObjectPtr createTestObject() {
90 OrcNativeTarget::initialize();
91 auto TM = std::unique_ptr<TargetMachine>(EngineBuilder().selectTarget());
92
93 if (!TM)
94 return nullptr;
95
96 LLVMContext Ctx;
97 ModuleBuilder MB(Ctx, TM->getTargetTriple().str(), "TestModule");
98 MB.getModule()->setDataLayout(TM->createDataLayout());
99 auto *Main = MB.createFunctionDecl<void(int, char**)>("main");
100 Main->getBasicBlockList().push_back(BasicBlock::Create(Ctx));
101 IRBuilder<> B(&Main->back());
102 B.CreateRet(ConstantInt::getSigned(Type::getInt32Ty(Ctx), 42));
103
104 SimpleCompiler IRCompiler(*TM);
105 return std::make_shared<object::OwningBinary<object::ObjectFile>>(
106 IRCompiler(*MB.getModule()));
107}
108
109TEST(RemoteObjectLayer, AddObject) {
110 llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
111 auto TestObject = createTestObject();
112 if (!TestObject)
113 return;
114
115 auto Channels = createPairedQueueChannels();
116
117 auto ReportError =
118 [](Error Err) {
119 logAllUnhandledErrors(std::move(Err), llvm::errs(), "");
120 };
121
122 // Copy the bytes out of the test object: the copy will be used to verify
123 // that the original is correctly transmitted over RPC to the mock layer.
124 StringRef ObjBytes = TestObject->getBinary()->getData();
125 std::vector<char> ObjContents(ObjBytes.size());
126 std::copy(ObjBytes.begin(), ObjBytes.end(), ObjContents.begin());
127
128 RPCEndpoint ClientEP(*Channels.first, true);
129 RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
130
131 RPCEndpoint ServerEP(*Channels.second, true);
132 MockObjectLayer BaseLayer(
133 [&ObjContents](MockObjectLayer::ObjectPtr Obj,
134 MockObjectLayer::SymbolLookupTable &SymTab) {
135
136 // Check that the received object file content matches the original.
137 StringRef RPCObjContents = Obj->getBinary()->getData();
138 EXPECT_EQ(RPCObjContents.size(), ObjContents.size())
139 << "RPC'd object file has incorrect size";
140 EXPECT_TRUE(std::equal(RPCObjContents.begin(), RPCObjContents.end(),
141 ObjContents.begin()))
142 << "RPC'd object file content does not match original content";
143
144 return 1;
145 });
146 RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
147 ServerEP,
148 ReportError);
149
150 bool Finished = false;
151 ServerEP.addHandler<remote::utils::TerminateSession>(
152 [&]() { Finished = true; }
153 );
154
155 auto ServerThread =
156 std::thread([&]() {
157 while (!Finished)
158 cantFail(ServerEP.handleOne());
159 });
160
161 cantFail(Client.addObject(std::move(TestObject),
162 std::make_shared<NullResolver>()));
163 cantFail(ClientEP.callB<remote::utils::TerminateSession>());
164 ServerThread.join();
165}
166
167TEST(RemoteObjectLayer, AddObjectFailure) {
168 llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
169 auto TestObject = createTestObject();
170 if (!TestObject)
171 return;
172
173 auto Channels = createPairedQueueChannels();
174
175 auto ReportError =
176 [](Error Err) {
177 auto ErrMsg = toString(std::move(Err));
178 EXPECT_EQ(ErrMsg, "AddObjectFailure - Test Message")
179 << "Expected error string to be \"AddObjectFailure - Test Message\"";
180 };
181
182 RPCEndpoint ClientEP(*Channels.first, true);
183 RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
184
185 RPCEndpoint ServerEP(*Channels.second, true);
186 MockObjectLayer BaseLayer(
187 [](MockObjectLayer::ObjectPtr Obj,
188 MockObjectLayer::SymbolLookupTable &SymTab)
189 -> Expected<MockObjectLayer::ObjHandleT> {
190 return make_error<StringError>("AddObjectFailure - Test Message",
191 inconvertibleErrorCode());
192 });
193 RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
194 ServerEP,
195 ReportError);
196
197 bool Finished = false;
198 ServerEP.addHandler<remote::utils::TerminateSession>(
199 [&]() { Finished = true; }
200 );
201
202 auto ServerThread =
203 std::thread([&]() {
204 while (!Finished)
205 cantFail(ServerEP.handleOne());
206 });
207
208 auto HandleOrErr =
209 Client.addObject(std::move(TestObject), std::make_shared<NullResolver>());
210
211 EXPECT_FALSE(HandleOrErr) << "Expected error from addObject";
212
213 auto ErrMsg = toString(HandleOrErr.takeError());
214 EXPECT_EQ(ErrMsg, "AddObjectFailure - Test Message")
215 << "Expected error string to be \"AddObjectFailure - Test Message\"";
216
217 cantFail(ClientEP.callB<remote::utils::TerminateSession>());
218 ServerThread.join();
219}
220
221
222TEST(RemoteObjectLayer, RemoveObject) {
223 llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
224 auto TestObject = createTestObject();
225 if (!TestObject)
226 return;
227
228 auto Channels = createPairedQueueChannels();
229
230 auto ReportError =
231 [](Error Err) {
232 logAllUnhandledErrors(std::move(Err), llvm::errs(), "");
233 };
234
235 RPCEndpoint ClientEP(*Channels.first, true);
236 RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
237
238 RPCEndpoint ServerEP(*Channels.second, true);
239
240 MockObjectLayer BaseLayer(
241 [](MockObjectLayer::ObjectPtr Obj,
242 MockObjectLayer::SymbolLookupTable &SymTab) {
243 SymTab[1] = MockObjectLayer::LookupFn();
244 return 1;
245 });
246 RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
247 ServerEP,
248 ReportError);
249
250 bool Finished = false;
251 ServerEP.addHandler<remote::utils::TerminateSession>(
252 [&]() { Finished = true; }
253 );
254
255 auto ServerThread =
256 std::thread([&]() {
257 while (!Finished)
258 cantFail(ServerEP.handleOne());
259 });
260
261 auto H = cantFail(Client.addObject(std::move(TestObject),
262 std::make_shared<NullResolver>()));
263
264 cantFail(Client.removeObject(H));
265
266 cantFail(ClientEP.callB<remote::utils::TerminateSession>());
267 ServerThread.join();
268}
269
270TEST(RemoteObjectLayer, RemoveObjectFailure) {
271 llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
272 auto TestObject = createTestObject();
273 if (!TestObject)
274 return;
275
276 auto Channels = createPairedQueueChannels();
277
278 auto ReportError =
279 [](Error Err) {
280 auto ErrMsg = toString(std::move(Err));
281 EXPECT_EQ(ErrMsg, "Object handle 42 not found")
282 << "Expected error string to be \"Object handle 42 not found\"";
283 };
284
285 RPCEndpoint ClientEP(*Channels.first, true);
286 RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
287
288 RPCEndpoint ServerEP(*Channels.second, true);
289
290 // AddObject lambda does not update symbol table, so removeObject will treat
291 // this as a bad object handle.
292 MockObjectLayer BaseLayer(
293 [](MockObjectLayer::ObjectPtr Obj,
294 MockObjectLayer::SymbolLookupTable &SymTab) {
295 return 42;
296 });
297 RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
298 ServerEP,
299 ReportError);
300
301 bool Finished = false;
302 ServerEP.addHandler<remote::utils::TerminateSession>(
303 [&]() { Finished = true; }
304 );
305
306 auto ServerThread =
307 std::thread([&]() {
308 while (!Finished)
309 cantFail(ServerEP.handleOne());
310 });
311
312 auto H = cantFail(Client.addObject(std::move(TestObject),
313 std::make_shared<NullResolver>()));
314
315 auto Err = Client.removeObject(H);
316 EXPECT_TRUE(!!Err) << "Expected error from removeObject";
317
318 auto ErrMsg = toString(std::move(Err));
319 EXPECT_EQ(ErrMsg, "Object handle 42 not found")
320 << "Expected error string to be \"Object handle 42 not found\"";
321
322 cantFail(ClientEP.callB<remote::utils::TerminateSession>());
323 ServerThread.join();
324}
325
326TEST(RemoteObjectLayer, FindSymbol) {
327 llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
328 auto TestObject = createTestObject();
329 if (!TestObject)
330 return;
331
332 auto Channels = createPairedQueueChannels();
333
334 auto ReportError =
335 [](Error Err) {
336 auto ErrMsg = toString(std::move(Err));
337 EXPECT_EQ(ErrMsg, "Could not find symbol 'barbaz'")
338 << "Expected error string to be \"Object handle 42 not found\"";
339 };
340
341 RPCEndpoint ClientEP(*Channels.first, true);
342 RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
343
344 RPCEndpoint ServerEP(*Channels.second, true);
345
346 // AddObject lambda does not update symbol table, so removeObject will treat
347 // this as a bad object handle.
348 MockObjectLayer BaseLayer(
349 [](MockObjectLayer::ObjectPtr Obj,
350 MockObjectLayer::SymbolLookupTable &SymTab) {
351 SymTab[42] =
352 [](StringRef Name, bool ExportedSymbolsOnly) -> JITSymbol {
353 if (Name == "foobar")
354 return JITSymbol(0x12348765, JITSymbolFlags::Exported);
355 return make_error<JITSymbolNotFound>(Name);
356 };
357 return 42;
358 });
359 RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
360 ServerEP,
361 ReportError);
362
363 bool Finished = false;
364 ServerEP.addHandler<remote::utils::TerminateSession>(
365 [&]() { Finished = true; }
366 );
367
368 auto ServerThread =
369 std::thread([&]() {
370 while (!Finished)
371 cantFail(ServerEP.handleOne());
372 });
373
374 cantFail(Client.addObject(std::move(TestObject),
375 std::make_shared<NullResolver>()));
376
377 auto Sym1 = Client.findSymbol("foobar", true);
378
379 EXPECT_TRUE(!!Sym1) << "Symbol 'foobar' should be findable";
380 EXPECT_EQ(cantFail(Sym1.getAddress()), 0x12348765ULL)
381 << "Symbol 'foobar' does not return the correct address";
382
383 auto Sym2 = Client.findSymbol("barbaz", true);
384 EXPECT_FALSE(!!Sym2) << "Symbol 'barbaz' should not be findable";
385 auto Err = Sym2.takeError();
386 EXPECT_TRUE(!!Err) << "Sym2 should contain an error value";
387 auto ErrMsg = toString(std::move(Err));
388 EXPECT_EQ(ErrMsg, "Could not find symbol 'barbaz'")
389 << "Expected symbol-not-found error for Sym2";
390
391 cantFail(ClientEP.callB<remote::utils::TerminateSession>());
392 ServerThread.join();
393}
394
395TEST(RemoteObjectLayer, FindSymbolIn) {
396 llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
397 auto TestObject = createTestObject();
398 if (!TestObject)
399 return;
400
401 auto Channels = createPairedQueueChannels();
402
403 auto ReportError =
404 [](Error Err) {
405 auto ErrMsg = toString(std::move(Err));
406 EXPECT_EQ(ErrMsg, "Could not find symbol 'barbaz'")
407 << "Expected error string to be \"Object handle 42 not found\"";
408 };
409
410 RPCEndpoint ClientEP(*Channels.first, true);
411 RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
412
413 RPCEndpoint ServerEP(*Channels.second, true);
414
415 // AddObject lambda does not update symbol table, so removeObject will treat
416 // this as a bad object handle.
417 MockObjectLayer BaseLayer(
418 [](MockObjectLayer::ObjectPtr Obj,
419 MockObjectLayer::SymbolLookupTable &SymTab) {
420 SymTab[42] =
421 [](StringRef Name, bool ExportedSymbolsOnly) -> JITSymbol {
422 if (Name == "foobar")
423 return JITSymbol(0x12348765, JITSymbolFlags::Exported);
424 return make_error<JITSymbolNotFound>(Name);
425 };
426 // Dummy symbol table entry - this should not be visible to
427 // findSymbolIn.
428 SymTab[43] =
429 [](StringRef Name, bool ExportedSymbolsOnly) -> JITSymbol {
430 if (Name == "barbaz")
431 return JITSymbol(0xdeadbeef, JITSymbolFlags::Exported);
432 return make_error<JITSymbolNotFound>(Name);
433 };
434
435 return 42;
436 });
437 RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
438 ServerEP,
439 ReportError);
440
441 bool Finished = false;
442 ServerEP.addHandler<remote::utils::TerminateSession>(
443 [&]() { Finished = true; }
444 );
445
446 auto ServerThread =
447 std::thread([&]() {
448 while (!Finished)
449 cantFail(ServerEP.handleOne());
450 });
451
452 auto H = cantFail(Client.addObject(std::move(TestObject),
453 std::make_shared<NullResolver>()));
454
455 auto Sym1 = Client.findSymbolIn(H, "foobar", true);
456
457 EXPECT_TRUE(!!Sym1) << "Symbol 'foobar' should be findable";
458 EXPECT_EQ(cantFail(Sym1.getAddress()), 0x12348765ULL)
459 << "Symbol 'foobar' does not return the correct address";
460
461 auto Sym2 = Client.findSymbolIn(H, "barbaz", true);
462 EXPECT_FALSE(!!Sym2) << "Symbol 'barbaz' should not be findable";
463 auto Err = Sym2.takeError();
464 EXPECT_TRUE(!!Err) << "Sym2 should contain an error value";
465 auto ErrMsg = toString(std::move(Err));
466 EXPECT_EQ(ErrMsg, "Could not find symbol 'barbaz'")
467 << "Expected symbol-not-found error for Sym2";
468
469 cantFail(ClientEP.callB<remote::utils::TerminateSession>());
470 ServerThread.join();
471}
472
473TEST(RemoteObjectLayer, EmitAndFinalize) {
474 llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
475 auto TestObject = createTestObject();
476 if (!TestObject)
477 return;
478
479 auto Channels = createPairedQueueChannels();
480
481 auto ReportError =
482 [](Error Err) {
483 logAllUnhandledErrors(std::move(Err), llvm::errs(), "");
484 };
485
486 RPCEndpoint ClientEP(*Channels.first, true);
487 RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
488
489 RPCEndpoint ServerEP(*Channels.second, true);
490
491 MockObjectLayer BaseLayer(
492 [](MockObjectLayer::ObjectPtr Obj,
493 MockObjectLayer::SymbolLookupTable &SymTab) {
494 SymTab[1] = MockObjectLayer::LookupFn();
495 return 1;
496 });
497 RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
498 ServerEP,
499 ReportError);
500
501 bool Finished = false;
502 ServerEP.addHandler<remote::utils::TerminateSession>(
503 [&]() { Finished = true; }
504 );
505
506 auto ServerThread =
507 std::thread([&]() {
508 while (!Finished)
509 cantFail(ServerEP.handleOne());
510 });
511
512 auto H = cantFail(Client.addObject(std::move(TestObject),
513 std::make_shared<NullResolver>()));
514
515 auto Err = Client.emitAndFinalize(H);
516 EXPECT_FALSE(!!Err) << "emitAndFinalize should work";
517
518 cantFail(ClientEP.callB<remote::utils::TerminateSession>());
519 ServerThread.join();
520}
521
522TEST(RemoteObjectLayer, EmitAndFinalizeFailure) {
523 llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
524 auto TestObject = createTestObject();
525 if (!TestObject)
526 return;
527
528 auto Channels = createPairedQueueChannels();
529
530 auto ReportError =
531 [](Error Err) {
532 auto ErrMsg = toString(std::move(Err));
533 EXPECT_EQ(ErrMsg, "Object handle 1 not found")
534 << "Expected bad handle error";
535 };
536
537 RPCEndpoint ClientEP(*Channels.first, true);
538 RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError);
539
540 RPCEndpoint ServerEP(*Channels.second, true);
541
542 MockObjectLayer BaseLayer(
543 [](MockObjectLayer::ObjectPtr Obj,
544 MockObjectLayer::SymbolLookupTable &SymTab) {
545 return 1;
546 });
547 RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer,
548 ServerEP,
549 ReportError);
550
551 bool Finished = false;
552 ServerEP.addHandler<remote::utils::TerminateSession>(
553 [&]() { Finished = true; }
554 );
555
556 auto ServerThread =
557 std::thread([&]() {
558 while (!Finished)
559 cantFail(ServerEP.handleOne());
560 });
561
562 auto H = cantFail(Client.addObject(std::move(TestObject),
563 std::make_shared<NullResolver>()));
564
565 auto Err = Client.emitAndFinalize(H);
566 EXPECT_TRUE(!!Err) << "emitAndFinalize should work";
567
568 auto ErrMsg = toString(std::move(Err));
569 EXPECT_EQ(ErrMsg, "Object handle 1 not found")
570 << "emitAndFinalize returned incorrect error";
571
572 cantFail(ClientEP.callB<remote::utils::TerminateSession>());
573 ServerThread.join();
574}
575
576}