1 //===---------------------- RemoteObjectLayerTest.cpp ---------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
10 #include "llvm/ExecutionEngine/Orc/NullResolver.h"
11 #include "llvm/ExecutionEngine/Orc/RemoteObjectLayer.h"
12 #include "OrcTestCommon.h"
13 #include "QueueChannel.h"
14 #include "gtest/gtest.h"
17 using namespace llvm::orc
;
21 class MockObjectLayer
{
24 using ObjHandleT
= uint64_t;
26 using ObjectPtr
= std::unique_ptr
<MemoryBuffer
>;
28 using LookupFn
= std::function
<JITSymbol(StringRef
, bool)>;
29 using SymbolLookupTable
= std::map
<ObjHandleT
, LookupFn
>;
32 std::function
<Expected
<ObjHandleT
>(ObjectPtr
, SymbolLookupTable
&)>;
34 class ObjectNotFound
: public remote::ResourceNotFound
<ObjHandleT
> {
36 ObjectNotFound(ObjHandleT H
) : ResourceNotFound(H
, "Object handle") {}
39 MockObjectLayer(AddObjectFtor AddObject
)
40 : AddObject(std::move(AddObject
)) {}
42 Expected
<ObjHandleT
> addObject(ObjectPtr Obj
,
43 std::shared_ptr
<JITSymbolResolver
> Resolver
) {
44 return AddObject(std::move(Obj
), SymTab
);
47 Error
removeObject(ObjHandleT H
) {
49 return Error::success();
51 return make_error
<ObjectNotFound
>(H
);
54 JITSymbol
findSymbol(StringRef Name
, bool ExportedSymbolsOnly
) {
55 for (auto KV
: SymTab
) {
56 if (auto Sym
= KV
.second(Name
, ExportedSymbolsOnly
))
58 else if (auto Err
= Sym
.takeError())
59 return std::move(Err
);
61 return JITSymbol(nullptr);
64 JITSymbol
findSymbolIn(ObjHandleT H
, StringRef Name
,
65 bool ExportedSymbolsOnly
) {
66 auto LI
= SymTab
.find(H
);
67 if (LI
!= SymTab
.end())
68 return LI
->second(Name
, ExportedSymbolsOnly
);
70 return make_error
<ObjectNotFound
>(H
);
73 Error
emitAndFinalize(ObjHandleT H
) {
75 return Error::success();
77 return make_error
<ObjectNotFound
>(H
);
81 AddObjectFtor AddObject
;
82 SymbolLookupTable SymTab
;
85 using RPCEndpoint
= rpc::SingleThreadedRPCEndpoint
<rpc::RawByteChannel
>;
87 MockObjectLayer::ObjectPtr
createTestObject() {
88 OrcNativeTarget::initialize();
89 auto TM
= std::unique_ptr
<TargetMachine
>(EngineBuilder().selectTarget());
95 ModuleBuilder
MB(Ctx
, TM
->getTargetTriple().str(), "TestModule");
96 MB
.getModule()->setDataLayout(TM
->createDataLayout());
97 auto *Main
= MB
.createFunctionDecl(
98 FunctionType::get(Type::getInt32Ty(Ctx
),
99 {Type::getInt32Ty(Ctx
),
100 Type::getInt8PtrTy(Ctx
)->getPointerTo()},
103 Main
->getBasicBlockList().push_back(BasicBlock::Create(Ctx
));
104 IRBuilder
<> B(&Main
->back());
105 B
.CreateRet(ConstantInt::getSigned(Type::getInt32Ty(Ctx
), 42));
107 SimpleCompiler
IRCompiler(*TM
);
108 return IRCompiler(*MB
.getModule());
111 TEST(RemoteObjectLayer
, AddObject
) {
112 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
113 auto TestObject
= createTestObject();
117 auto Channels
= createPairedQueueChannels();
119 auto ReportError
= [](Error Err
) {
120 logAllUnhandledErrors(std::move(Err
), llvm::errs());
123 // Copy the bytes out of the test object: the copy will be used to verify
124 // that the original is correctly transmitted over RPC to the mock layer.
125 StringRef ObjBytes
= TestObject
->getBuffer();
126 std::vector
<char> ObjContents(ObjBytes
.size());
127 std::copy(ObjBytes
.begin(), ObjBytes
.end(), ObjContents
.begin());
129 RPCEndpoint
ClientEP(*Channels
.first
, true);
130 RemoteObjectClientLayer
<RPCEndpoint
> Client(AcknowledgeORCv1Deprecation
,
131 ClientEP
, ReportError
);
133 RPCEndpoint
ServerEP(*Channels
.second
, true);
134 MockObjectLayer
BaseLayer(
135 [&ObjContents
](MockObjectLayer::ObjectPtr Obj
,
136 MockObjectLayer::SymbolLookupTable
&SymTab
) {
138 // Check that the received object file content matches the original.
139 StringRef RPCObjContents
= Obj
->getBuffer();
140 EXPECT_EQ(RPCObjContents
.size(), ObjContents
.size())
141 << "RPC'd object file has incorrect size";
142 EXPECT_TRUE(std::equal(RPCObjContents
.begin(), RPCObjContents
.end(),
143 ObjContents
.begin()))
144 << "RPC'd object file content does not match original content";
148 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(
149 AcknowledgeORCv1Deprecation
, BaseLayer
, ServerEP
, ReportError
);
151 bool Finished
= false;
152 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
153 [&]() { Finished
= true; }
159 cantFail(ServerEP
.handleOne());
162 cantFail(Client
.addObject(std::move(TestObject
),
163 std::make_shared
<NullLegacyResolver
>()));
164 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());
168 TEST(RemoteObjectLayer
, AddObjectFailure
) {
169 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
170 auto TestObject
= createTestObject();
174 auto Channels
= createPairedQueueChannels();
178 auto ErrMsg
= toString(std::move(Err
));
179 EXPECT_EQ(ErrMsg
, "AddObjectFailure - Test Message")
180 << "Expected error string to be \"AddObjectFailure - Test Message\"";
183 RPCEndpoint
ClientEP(*Channels
.first
, true);
184 RemoteObjectClientLayer
<RPCEndpoint
> Client(AcknowledgeORCv1Deprecation
,
185 ClientEP
, ReportError
);
187 RPCEndpoint
ServerEP(*Channels
.second
, true);
188 MockObjectLayer
BaseLayer(
189 [](MockObjectLayer::ObjectPtr Obj
,
190 MockObjectLayer::SymbolLookupTable
&SymTab
)
191 -> Expected
<MockObjectLayer::ObjHandleT
> {
192 return make_error
<StringError
>("AddObjectFailure - Test Message",
193 inconvertibleErrorCode());
195 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(
196 AcknowledgeORCv1Deprecation
, BaseLayer
, ServerEP
, ReportError
);
198 bool Finished
= false;
199 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
200 [&]() { Finished
= true; }
206 cantFail(ServerEP
.handleOne());
209 auto HandleOrErr
= Client
.addObject(std::move(TestObject
),
210 std::make_shared
<NullLegacyResolver
>());
212 EXPECT_FALSE(HandleOrErr
) << "Expected error from addObject";
214 auto ErrMsg
= toString(HandleOrErr
.takeError());
215 EXPECT_EQ(ErrMsg
, "AddObjectFailure - Test Message")
216 << "Expected error string to be \"AddObjectFailure - Test Message\"";
218 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());
223 TEST(RemoteObjectLayer
, RemoveObject
) {
224 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
225 auto TestObject
= createTestObject();
229 auto Channels
= createPairedQueueChannels();
231 auto ReportError
= [](Error Err
) {
232 logAllUnhandledErrors(std::move(Err
), llvm::errs());
235 RPCEndpoint
ClientEP(*Channels
.first
, true);
236 RemoteObjectClientLayer
<RPCEndpoint
> Client(AcknowledgeORCv1Deprecation
,
237 ClientEP
, ReportError
);
239 RPCEndpoint
ServerEP(*Channels
.second
, true);
241 MockObjectLayer
BaseLayer(
242 [](MockObjectLayer::ObjectPtr Obj
,
243 MockObjectLayer::SymbolLookupTable
&SymTab
) {
244 SymTab
[1] = MockObjectLayer::LookupFn();
247 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(
248 AcknowledgeORCv1Deprecation
, BaseLayer
, ServerEP
, ReportError
);
250 bool Finished
= false;
251 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
252 [&]() { Finished
= true; }
258 cantFail(ServerEP
.handleOne());
261 auto H
= cantFail(Client
.addObject(std::move(TestObject
),
262 std::make_shared
<NullLegacyResolver
>()));
264 cantFail(Client
.removeObject(H
));
266 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());
270 TEST(RemoteObjectLayer
, RemoveObjectFailure
) {
271 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
272 auto TestObject
= createTestObject();
276 auto Channels
= createPairedQueueChannels();
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\"";
285 RPCEndpoint
ClientEP(*Channels
.first
, true);
286 RemoteObjectClientLayer
<RPCEndpoint
> Client(AcknowledgeORCv1Deprecation
,
287 ClientEP
, ReportError
);
289 RPCEndpoint
ServerEP(*Channels
.second
, true);
291 // AddObject lambda does not update symbol table, so removeObject will treat
292 // this as a bad object handle.
293 MockObjectLayer
BaseLayer(
294 [](MockObjectLayer::ObjectPtr Obj
,
295 MockObjectLayer::SymbolLookupTable
&SymTab
) {
298 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(
299 AcknowledgeORCv1Deprecation
, BaseLayer
, ServerEP
, ReportError
);
301 bool Finished
= false;
302 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
303 [&]() { Finished
= true; }
309 cantFail(ServerEP
.handleOne());
312 auto H
= cantFail(Client
.addObject(std::move(TestObject
),
313 std::make_shared
<NullLegacyResolver
>()));
315 auto Err
= Client
.removeObject(H
);
316 EXPECT_TRUE(!!Err
) << "Expected error from removeObject";
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\"";
322 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());
326 TEST(RemoteObjectLayer
, FindSymbol
) {
327 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
328 auto TestObject
= createTestObject();
332 auto Channels
= createPairedQueueChannels();
336 auto ErrMsg
= toString(std::move(Err
));
337 EXPECT_EQ(ErrMsg
, "Could not find symbol 'badsymbol'")
338 << "Expected error string to be \"Object handle 42 not found\"";
341 RPCEndpoint
ClientEP(*Channels
.first
, true);
342 RemoteObjectClientLayer
<RPCEndpoint
> Client(AcknowledgeORCv1Deprecation
,
343 ClientEP
, ReportError
);
345 RPCEndpoint
ServerEP(*Channels
.second
, true);
347 // AddObject lambda does not update symbol table, so removeObject will treat
348 // this as a bad object handle.
349 MockObjectLayer
BaseLayer(
350 [](MockObjectLayer::ObjectPtr Obj
,
351 MockObjectLayer::SymbolLookupTable
&SymTab
) {
353 [](StringRef Name
, bool ExportedSymbolsOnly
) -> JITSymbol
{
354 if (Name
== "foobar")
355 return JITSymbol(0x12348765, JITSymbolFlags::Exported
);
356 if (Name
== "badsymbol")
357 return make_error
<JITSymbolNotFound
>(Name
);
362 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(
363 AcknowledgeORCv1Deprecation
, BaseLayer
, ServerEP
, ReportError
);
365 bool Finished
= false;
366 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
367 [&]() { Finished
= true; }
373 cantFail(ServerEP
.handleOne());
376 cantFail(Client
.addObject(std::move(TestObject
),
377 std::make_shared
<NullLegacyResolver
>()));
379 // Check that we can find and materialize a valid symbol.
380 auto Sym1
= Client
.findSymbol("foobar", true);
381 EXPECT_TRUE(!!Sym1
) << "Symbol 'foobar' should be findable";
382 EXPECT_EQ(cantFail(Sym1
.getAddress()), 0x12348765ULL
)
383 << "Symbol 'foobar' does not return the correct address";
386 // Check that we can return a symbol containing an error.
387 auto Sym2
= Client
.findSymbol("badsymbol", true);
388 EXPECT_FALSE(!!Sym2
) << "Symbol 'badsymbol' should not be findable";
389 auto Err
= Sym2
.takeError();
390 EXPECT_TRUE(!!Err
) << "Sym2 should contain an error value";
391 auto ErrMsg
= toString(std::move(Err
));
392 EXPECT_EQ(ErrMsg
, "Could not find symbol 'badsymbol'")
393 << "Expected symbol-not-found error for Sym2";
397 // Check that we can return a 'null' symbol.
398 auto Sym3
= Client
.findSymbol("baz", true);
399 EXPECT_FALSE(!!Sym3
) << "Symbol 'baz' should convert to false";
400 auto Err
= Sym3
.takeError();
401 EXPECT_FALSE(!!Err
) << "Symbol 'baz' should not contain an error";
404 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());
408 TEST(RemoteObjectLayer
, FindSymbolIn
) {
409 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
410 auto TestObject
= createTestObject();
414 auto Channels
= createPairedQueueChannels();
418 auto ErrMsg
= toString(std::move(Err
));
419 EXPECT_EQ(ErrMsg
, "Could not find symbol 'barbaz'")
420 << "Expected error string to be \"Object handle 42 not found\"";
423 RPCEndpoint
ClientEP(*Channels
.first
, true);
424 RemoteObjectClientLayer
<RPCEndpoint
> Client(AcknowledgeORCv1Deprecation
,
425 ClientEP
, ReportError
);
427 RPCEndpoint
ServerEP(*Channels
.second
, true);
429 // AddObject lambda does not update symbol table, so removeObject will treat
430 // this as a bad object handle.
431 MockObjectLayer
BaseLayer(
432 [](MockObjectLayer::ObjectPtr Obj
,
433 MockObjectLayer::SymbolLookupTable
&SymTab
) {
435 [](StringRef Name
, bool ExportedSymbolsOnly
) -> JITSymbol
{
436 if (Name
== "foobar")
437 return JITSymbol(0x12348765, JITSymbolFlags::Exported
);
438 return make_error
<JITSymbolNotFound
>(Name
);
440 // Dummy symbol table entry - this should not be visible to
443 [](StringRef Name
, bool ExportedSymbolsOnly
) -> JITSymbol
{
444 if (Name
== "barbaz")
445 return JITSymbol(0xdeadbeef, JITSymbolFlags::Exported
);
446 return make_error
<JITSymbolNotFound
>(Name
);
451 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(
452 AcknowledgeORCv1Deprecation
, BaseLayer
, ServerEP
, ReportError
);
454 bool Finished
= false;
455 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
456 [&]() { Finished
= true; }
462 cantFail(ServerEP
.handleOne());
465 auto H
= cantFail(Client
.addObject(std::move(TestObject
),
466 std::make_shared
<NullLegacyResolver
>()));
468 auto Sym1
= Client
.findSymbolIn(H
, "foobar", true);
470 EXPECT_TRUE(!!Sym1
) << "Symbol 'foobar' should be findable";
471 EXPECT_EQ(cantFail(Sym1
.getAddress()), 0x12348765ULL
)
472 << "Symbol 'foobar' does not return the correct address";
474 auto Sym2
= Client
.findSymbolIn(H
, "barbaz", true);
475 EXPECT_FALSE(!!Sym2
) << "Symbol 'barbaz' should not be findable";
476 auto Err
= Sym2
.takeError();
477 EXPECT_TRUE(!!Err
) << "Sym2 should contain an error value";
478 auto ErrMsg
= toString(std::move(Err
));
479 EXPECT_EQ(ErrMsg
, "Could not find symbol 'barbaz'")
480 << "Expected symbol-not-found error for Sym2";
482 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());
486 TEST(RemoteObjectLayer
, EmitAndFinalize
) {
487 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
488 auto TestObject
= createTestObject();
492 auto Channels
= createPairedQueueChannels();
494 auto ReportError
= [](Error Err
) {
495 logAllUnhandledErrors(std::move(Err
), llvm::errs());
498 RPCEndpoint
ClientEP(*Channels
.first
, true);
499 RemoteObjectClientLayer
<RPCEndpoint
> Client(AcknowledgeORCv1Deprecation
,
500 ClientEP
, ReportError
);
502 RPCEndpoint
ServerEP(*Channels
.second
, true);
504 MockObjectLayer
BaseLayer(
505 [](MockObjectLayer::ObjectPtr Obj
,
506 MockObjectLayer::SymbolLookupTable
&SymTab
) {
507 SymTab
[1] = MockObjectLayer::LookupFn();
510 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(
511 AcknowledgeORCv1Deprecation
, BaseLayer
, ServerEP
, ReportError
);
513 bool Finished
= false;
514 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
515 [&]() { Finished
= true; }
521 cantFail(ServerEP
.handleOne());
524 auto H
= cantFail(Client
.addObject(std::move(TestObject
),
525 std::make_shared
<NullLegacyResolver
>()));
527 auto Err
= Client
.emitAndFinalize(H
);
528 EXPECT_FALSE(!!Err
) << "emitAndFinalize should work";
530 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());
534 TEST(RemoteObjectLayer
, EmitAndFinalizeFailure
) {
535 llvm::orc::rpc::registerStringError
<rpc::RawByteChannel
>();
536 auto TestObject
= createTestObject();
540 auto Channels
= createPairedQueueChannels();
544 auto ErrMsg
= toString(std::move(Err
));
545 EXPECT_EQ(ErrMsg
, "Object handle 1 not found")
546 << "Expected bad handle error";
549 RPCEndpoint
ClientEP(*Channels
.first
, true);
550 RemoteObjectClientLayer
<RPCEndpoint
> Client(AcknowledgeORCv1Deprecation
,
551 ClientEP
, ReportError
);
553 RPCEndpoint
ServerEP(*Channels
.second
, true);
555 MockObjectLayer
BaseLayer(
556 [](MockObjectLayer::ObjectPtr Obj
,
557 MockObjectLayer::SymbolLookupTable
&SymTab
) {
560 RemoteObjectServerLayer
<MockObjectLayer
, RPCEndpoint
> Server(
561 AcknowledgeORCv1Deprecation
, BaseLayer
, ServerEP
, ReportError
);
563 bool Finished
= false;
564 ServerEP
.addHandler
<remote::utils::TerminateSession
>(
565 [&]() { Finished
= true; }
571 cantFail(ServerEP
.handleOne());
574 auto H
= cantFail(Client
.addObject(std::move(TestObject
),
575 std::make_shared
<NullLegacyResolver
>()));
577 auto Err
= Client
.emitAndFinalize(H
);
578 EXPECT_TRUE(!!Err
) << "emitAndFinalize should work";
580 auto ErrMsg
= toString(std::move(Err
));
581 EXPECT_EQ(ErrMsg
, "Object handle 1 not found")
582 << "emitAndFinalize returned incorrect error";
584 cantFail(ClientEP
.callB
<remote::utils::TerminateSession
>());