1 //===---------------------- RemoteObjectLayerTest.cpp ---------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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"
18 using namespace llvm::orc
;
22 class MockObjectLayer
{
25 using ObjHandleT
= uint64_t;
27 using ObjectPtr
= std::unique_ptr
<MemoryBuffer
>;
29 using LookupFn
= std::function
<JITSymbol(StringRef
, bool)>;
30 using SymbolLookupTable
= std::map
<ObjHandleT
, LookupFn
>;
33 std::function
<Expected
<ObjHandleT
>(ObjectPtr
, SymbolLookupTable
&)>;
35 class ObjectNotFound
: public remote::ResourceNotFound
<ObjHandleT
> {
37 ObjectNotFound(ObjHandleT H
) : ResourceNotFound(H
, "Object handle") {}
40 MockObjectLayer(AddObjectFtor AddObject
)
41 : AddObject(std::move(AddObject
)) {}
43 Expected
<ObjHandleT
> addObject(ObjectPtr Obj
,
44 std::shared_ptr
<JITSymbolResolver
> Resolver
) {
45 return AddObject(std::move(Obj
), SymTab
);
48 Error
removeObject(ObjHandleT H
) {
50 return Error::success();
52 return make_error
<ObjectNotFound
>(H
);
55 JITSymbol
findSymbol(StringRef Name
, bool ExportedSymbolsOnly
) {
56 for (auto KV
: SymTab
) {
57 if (auto Sym
= KV
.second(Name
, ExportedSymbolsOnly
))
59 else if (auto Err
= Sym
.takeError())
60 return std::move(Err
);
62 return JITSymbol(nullptr);
65 JITSymbol
findSymbolIn(ObjHandleT H
, StringRef Name
,
66 bool ExportedSymbolsOnly
) {
67 auto LI
= SymTab
.find(H
);
68 if (LI
!= SymTab
.end())
69 return LI
->second(Name
, ExportedSymbolsOnly
);
71 return make_error
<ObjectNotFound
>(H
);
74 Error
emitAndFinalize(ObjHandleT H
) {
76 return Error::success();
78 return make_error
<ObjectNotFound
>(H
);
82 AddObjectFtor AddObject
;
83 SymbolLookupTable SymTab
;
86 using RPCEndpoint
= rpc::SingleThreadedRPCEndpoint
<rpc::RawByteChannel
>;
88 MockObjectLayer::ObjectPtr
createTestObject() {
89 OrcNativeTarget::initialize();
90 auto TM
= std::unique_ptr
<TargetMachine
>(EngineBuilder().selectTarget());
96 ModuleBuilder
MB(Ctx
, TM
->getTargetTriple().str(), "TestModule");
97 MB
.getModule()->setDataLayout(TM
->createDataLayout());
98 auto *Main
= MB
.createFunctionDecl
<void(int, char**)>("main");
99 Main
->getBasicBlockList().push_back(BasicBlock::Create(Ctx
));
100 IRBuilder
<> B(&Main
->back());
101 B
.CreateRet(ConstantInt::getSigned(Type::getInt32Ty(Ctx
), 42));
103 SimpleCompiler
IRCompiler(*TM
);
104 return IRCompiler(*MB
.getModule());
107 TEST(RemoteObjectLayer
, AddObject
) {
108 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
109 auto TestObject
= createTestObject();
113 auto Channels
= createPairedQueueChannels();
117 logAllUnhandledErrors(std::move(Err
), llvm::errs(), "");
120 // Copy the bytes out of the test object: the copy will be used to verify
121 // that the original is correctly transmitted over RPC to the mock layer.
122 StringRef ObjBytes
= TestObject
->getBuffer();
123 std::vector
<char> ObjContents(ObjBytes
.size());
124 std::copy(ObjBytes
.begin(), ObjBytes
.end(), ObjContents
.begin());
126 RPCEndpoint
ClientEP(*Channels
.first
, true);
127 RemoteObjectClientLayer
<RPCEndpoint
> Client(ClientEP
, ReportError
);
129 RPCEndpoint
ServerEP(*Channels
.second
, true);
130 MockObjectLayer
BaseLayer(
131 [&ObjContents
](MockObjectLayer::ObjectPtr Obj
,
132 MockObjectLayer::SymbolLookupTable
&SymTab
) {
134 // Check that the received object file content matches the original.
135 StringRef RPCObjContents
= Obj
->getBuffer();
136 EXPECT_EQ(RPCObjContents
.size(), ObjContents
.size())
137 << "RPC'd object file has incorrect size";
138 EXPECT_TRUE(std::equal(RPCObjContents
.begin(), RPCObjContents
.end(),
139 ObjContents
.begin()))
140 << "RPC'd object file content does not match original content";
144 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(BaseLayer
,
148 bool Finished
= false;
149 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
150 [&]() { Finished
= true; }
156 cantFail(ServerEP
.handleOne());
159 cantFail(Client
.addObject(std::move(TestObject
),
160 std::make_shared
<NullLegacyResolver
>()));
161 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());
165 TEST(RemoteObjectLayer
, AddObjectFailure
) {
166 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
167 auto TestObject
= createTestObject();
171 auto Channels
= createPairedQueueChannels();
175 auto ErrMsg
= toString(std::move(Err
));
176 EXPECT_EQ(ErrMsg
, "AddObjectFailure - Test Message")
177 << "Expected error string to be \"AddObjectFailure - Test Message\"";
180 RPCEndpoint
ClientEP(*Channels
.first
, true);
181 RemoteObjectClientLayer
<RPCEndpoint
> Client(ClientEP
, ReportError
);
183 RPCEndpoint
ServerEP(*Channels
.second
, true);
184 MockObjectLayer
BaseLayer(
185 [](MockObjectLayer::ObjectPtr Obj
,
186 MockObjectLayer::SymbolLookupTable
&SymTab
)
187 -> Expected
<MockObjectLayer::ObjHandleT
> {
188 return make_error
<StringError
>("AddObjectFailure - Test Message",
189 inconvertibleErrorCode());
191 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(BaseLayer
,
195 bool Finished
= false;
196 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
197 [&]() { Finished
= true; }
203 cantFail(ServerEP
.handleOne());
206 auto HandleOrErr
= Client
.addObject(std::move(TestObject
),
207 std::make_shared
<NullLegacyResolver
>());
209 EXPECT_FALSE(HandleOrErr
) << "Expected error from addObject";
211 auto ErrMsg
= toString(HandleOrErr
.takeError());
212 EXPECT_EQ(ErrMsg
, "AddObjectFailure - Test Message")
213 << "Expected error string to be \"AddObjectFailure - Test Message\"";
215 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());
220 TEST(RemoteObjectLayer
, RemoveObject
) {
221 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
222 auto TestObject
= createTestObject();
226 auto Channels
= createPairedQueueChannels();
230 logAllUnhandledErrors(std::move(Err
), llvm::errs(), "");
233 RPCEndpoint
ClientEP(*Channels
.first
, true);
234 RemoteObjectClientLayer
<RPCEndpoint
> Client(ClientEP
, ReportError
);
236 RPCEndpoint
ServerEP(*Channels
.second
, true);
238 MockObjectLayer
BaseLayer(
239 [](MockObjectLayer::ObjectPtr Obj
,
240 MockObjectLayer::SymbolLookupTable
&SymTab
) {
241 SymTab
[1] = MockObjectLayer::LookupFn();
244 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(BaseLayer
,
248 bool Finished
= false;
249 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
250 [&]() { Finished
= true; }
256 cantFail(ServerEP
.handleOne());
259 auto H
= cantFail(Client
.addObject(std::move(TestObject
),
260 std::make_shared
<NullLegacyResolver
>()));
262 cantFail(Client
.removeObject(H
));
264 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());
268 TEST(RemoteObjectLayer
, RemoveObjectFailure
) {
269 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
270 auto TestObject
= createTestObject();
274 auto Channels
= createPairedQueueChannels();
278 auto ErrMsg
= toString(std::move(Err
));
279 EXPECT_EQ(ErrMsg
, "Object handle 42 not found")
280 << "Expected error string to be \"Object handle 42 not found\"";
283 RPCEndpoint
ClientEP(*Channels
.first
, true);
284 RemoteObjectClientLayer
<RPCEndpoint
> Client(ClientEP
, ReportError
);
286 RPCEndpoint
ServerEP(*Channels
.second
, true);
288 // AddObject lambda does not update symbol table, so removeObject will treat
289 // this as a bad object handle.
290 MockObjectLayer
BaseLayer(
291 [](MockObjectLayer::ObjectPtr Obj
,
292 MockObjectLayer::SymbolLookupTable
&SymTab
) {
295 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(BaseLayer
,
299 bool Finished
= false;
300 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
301 [&]() { Finished
= true; }
307 cantFail(ServerEP
.handleOne());
310 auto H
= cantFail(Client
.addObject(std::move(TestObject
),
311 std::make_shared
<NullLegacyResolver
>()));
313 auto Err
= Client
.removeObject(H
);
314 EXPECT_TRUE(!!Err
) << "Expected error from removeObject";
316 auto ErrMsg
= toString(std::move(Err
));
317 EXPECT_EQ(ErrMsg
, "Object handle 42 not found")
318 << "Expected error string to be \"Object handle 42 not found\"";
320 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());
324 TEST(RemoteObjectLayer
, FindSymbol
) {
325 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
326 auto TestObject
= createTestObject();
330 auto Channels
= createPairedQueueChannels();
334 auto ErrMsg
= toString(std::move(Err
));
335 EXPECT_EQ(ErrMsg
, "Could not find symbol 'badsymbol'")
336 << "Expected error string to be \"Object handle 42 not found\"";
339 RPCEndpoint
ClientEP(*Channels
.first
, true);
340 RemoteObjectClientLayer
<RPCEndpoint
> Client(ClientEP
, ReportError
);
342 RPCEndpoint
ServerEP(*Channels
.second
, true);
344 // AddObject lambda does not update symbol table, so removeObject will treat
345 // this as a bad object handle.
346 MockObjectLayer
BaseLayer(
347 [](MockObjectLayer::ObjectPtr Obj
,
348 MockObjectLayer::SymbolLookupTable
&SymTab
) {
350 [](StringRef Name
, bool ExportedSymbolsOnly
) -> JITSymbol
{
351 if (Name
== "foobar")
352 return JITSymbol(0x12348765, JITSymbolFlags::Exported
);
353 if (Name
== "badsymbol")
354 return make_error
<JITSymbolNotFound
>(Name
);
359 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(BaseLayer
,
363 bool Finished
= false;
364 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
365 [&]() { Finished
= true; }
371 cantFail(ServerEP
.handleOne());
374 cantFail(Client
.addObject(std::move(TestObject
),
375 std::make_shared
<NullLegacyResolver
>()));
377 // Check that we can find and materialize a valid symbol.
378 auto Sym1
= Client
.findSymbol("foobar", true);
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";
384 // Check that we can return a symbol containing an error.
385 auto Sym2
= Client
.findSymbol("badsymbol", true);
386 EXPECT_FALSE(!!Sym2
) << "Symbol 'badsymbol' should not be findable";
387 auto Err
= Sym2
.takeError();
388 EXPECT_TRUE(!!Err
) << "Sym2 should contain an error value";
389 auto ErrMsg
= toString(std::move(Err
));
390 EXPECT_EQ(ErrMsg
, "Could not find symbol 'badsymbol'")
391 << "Expected symbol-not-found error for Sym2";
395 // Check that we can return a 'null' symbol.
396 auto Sym3
= Client
.findSymbol("baz", true);
397 EXPECT_FALSE(!!Sym3
) << "Symbol 'baz' should convert to false";
398 auto Err
= Sym3
.takeError();
399 EXPECT_FALSE(!!Err
) << "Symbol 'baz' should not contain an error";
402 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());
406 TEST(RemoteObjectLayer
, FindSymbolIn
) {
407 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
408 auto TestObject
= createTestObject();
412 auto Channels
= createPairedQueueChannels();
416 auto ErrMsg
= toString(std::move(Err
));
417 EXPECT_EQ(ErrMsg
, "Could not find symbol 'barbaz'")
418 << "Expected error string to be \"Object handle 42 not found\"";
421 RPCEndpoint
ClientEP(*Channels
.first
, true);
422 RemoteObjectClientLayer
<RPCEndpoint
> Client(ClientEP
, ReportError
);
424 RPCEndpoint
ServerEP(*Channels
.second
, true);
426 // AddObject lambda does not update symbol table, so removeObject will treat
427 // this as a bad object handle.
428 MockObjectLayer
BaseLayer(
429 [](MockObjectLayer::ObjectPtr Obj
,
430 MockObjectLayer::SymbolLookupTable
&SymTab
) {
432 [](StringRef Name
, bool ExportedSymbolsOnly
) -> JITSymbol
{
433 if (Name
== "foobar")
434 return JITSymbol(0x12348765, JITSymbolFlags::Exported
);
435 return make_error
<JITSymbolNotFound
>(Name
);
437 // Dummy symbol table entry - this should not be visible to
440 [](StringRef Name
, bool ExportedSymbolsOnly
) -> JITSymbol
{
441 if (Name
== "barbaz")
442 return JITSymbol(0xdeadbeef, JITSymbolFlags::Exported
);
443 return make_error
<JITSymbolNotFound
>(Name
);
448 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(BaseLayer
,
452 bool Finished
= false;
453 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
454 [&]() { Finished
= true; }
460 cantFail(ServerEP
.handleOne());
463 auto H
= cantFail(Client
.addObject(std::move(TestObject
),
464 std::make_shared
<NullLegacyResolver
>()));
466 auto Sym1
= Client
.findSymbolIn(H
, "foobar", true);
468 EXPECT_TRUE(!!Sym1
) << "Symbol 'foobar' should be findable";
469 EXPECT_EQ(cantFail(Sym1
.getAddress()), 0x12348765ULL
)
470 << "Symbol 'foobar' does not return the correct address";
472 auto Sym2
= Client
.findSymbolIn(H
, "barbaz", true);
473 EXPECT_FALSE(!!Sym2
) << "Symbol 'barbaz' should not be findable";
474 auto Err
= Sym2
.takeError();
475 EXPECT_TRUE(!!Err
) << "Sym2 should contain an error value";
476 auto ErrMsg
= toString(std::move(Err
));
477 EXPECT_EQ(ErrMsg
, "Could not find symbol 'barbaz'")
478 << "Expected symbol-not-found error for Sym2";
480 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());
484 TEST(RemoteObjectLayer
, EmitAndFinalize
) {
485 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
486 auto TestObject
= createTestObject();
490 auto Channels
= createPairedQueueChannels();
494 logAllUnhandledErrors(std::move(Err
), llvm::errs(), "");
497 RPCEndpoint
ClientEP(*Channels
.first
, true);
498 RemoteObjectClientLayer
<RPCEndpoint
> Client(ClientEP
, ReportError
);
500 RPCEndpoint
ServerEP(*Channels
.second
, true);
502 MockObjectLayer
BaseLayer(
503 [](MockObjectLayer::ObjectPtr Obj
,
504 MockObjectLayer::SymbolLookupTable
&SymTab
) {
505 SymTab
[1] = MockObjectLayer::LookupFn();
508 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(BaseLayer
,
512 bool Finished
= false;
513 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
514 [&]() { Finished
= true; }
520 cantFail(ServerEP
.handleOne());
523 auto H
= cantFail(Client
.addObject(std::move(TestObject
),
524 std::make_shared
<NullLegacyResolver
>()));
526 auto Err
= Client
.emitAndFinalize(H
);
527 EXPECT_FALSE(!!Err
) << "emitAndFinalize should work";
529 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());
533 TEST(RemoteObjectLayer
, EmitAndFinalizeFailure
) {
534 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
535 auto TestObject
= createTestObject();
539 auto Channels
= createPairedQueueChannels();
543 auto ErrMsg
= toString(std::move(Err
));
544 EXPECT_EQ(ErrMsg
, "Object handle 1 not found")
545 << "Expected bad handle error";
548 RPCEndpoint
ClientEP(*Channels
.first
, true);
549 RemoteObjectClientLayer
<RPCEndpoint
> Client(ClientEP
, ReportError
);
551 RPCEndpoint
ServerEP(*Channels
.second
, true);
553 MockObjectLayer
BaseLayer(
554 [](MockObjectLayer::ObjectPtr Obj
,
555 MockObjectLayer::SymbolLookupTable
&SymTab
) {
558 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(BaseLayer
,
562 bool Finished
= false;
563 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
564 [&]() { Finished
= true; }
570 cantFail(ServerEP
.handleOne());
573 auto H
= cantFail(Client
.addObject(std::move(TestObject
),
574 std::make_shared
<NullLegacyResolver
>()));
576 auto Err
= Client
.emitAndFinalize(H
);
577 EXPECT_TRUE(!!Err
) << "emitAndFinalize should work";
579 auto ErrMsg
= toString(std::move(Err
));
580 EXPECT_EQ(ErrMsg
, "Object handle 1 not found")
581 << "emitAndFinalize returned incorrect error";
583 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());