diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
| commit | 044eb2f6afba375a914ac9d8024f8f5142bb912e (patch) | |
| tree | 1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp | |
| parent | eb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff) | |
Notes
Diffstat (limited to 'unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp')
| -rw-r--r-- | unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp b/unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp new file mode 100644 index 000000000000..819c5f8eb34b --- /dev/null +++ b/unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp @@ -0,0 +1,589 @@ +//===---------------------- RemoteObjectLayerTest.cpp ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/NullResolver.h" +#include "llvm/ExecutionEngine/Orc/RemoteObjectLayer.h" +#include "OrcTestCommon.h" +#include "QueueChannel.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::orc; + +namespace { + +class MockObjectLayer { +public: + + using ObjHandleT = uint64_t; + + using ObjectPtr = + std::shared_ptr<object::OwningBinary<object::ObjectFile>>; + + using LookupFn = std::function<JITSymbol(StringRef, bool)>; + using SymbolLookupTable = std::map<ObjHandleT, LookupFn>; + + using AddObjectFtor = + std::function<Expected<ObjHandleT>(ObjectPtr, SymbolLookupTable&)>; + + class ObjectNotFound : public remote::ResourceNotFound<ObjHandleT> { + public: + ObjectNotFound(ObjHandleT H) : ResourceNotFound(H, "Object handle") {} + }; + + MockObjectLayer(AddObjectFtor AddObject) + : AddObject(std::move(AddObject)) {} + + Expected<ObjHandleT> addObject(ObjectPtr Obj, + std::shared_ptr<JITSymbolResolver> Resolver) { + return AddObject(Obj, SymTab); + } + + Error removeObject(ObjHandleT H) { + if (SymTab.count(H)) + return Error::success(); + else + return make_error<ObjectNotFound>(H); + } + + JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) { + for (auto KV : SymTab) { + if (auto Sym = KV.second(Name, ExportedSymbolsOnly)) + return Sym; + else if (auto Err = Sym.takeError()) + return std::move(Err); + } + return JITSymbol(nullptr); + } + + JITSymbol findSymbolIn(ObjHandleT H, StringRef Name, + bool ExportedSymbolsOnly) { + auto LI = SymTab.find(H); + if (LI != SymTab.end()) + return LI->second(Name, ExportedSymbolsOnly); + else + return make_error<ObjectNotFound>(H); + } + + Error emitAndFinalize(ObjHandleT H) { + if (SymTab.count(H)) + return Error::success(); + else + return make_error<ObjectNotFound>(H); + } + +private: + AddObjectFtor AddObject; + SymbolLookupTable SymTab; +}; + +using RPCEndpoint = rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>; + +MockObjectLayer::ObjectPtr createTestObject() { + OrcNativeTarget::initialize(); + auto TM = std::unique_ptr<TargetMachine>(EngineBuilder().selectTarget()); + + if (!TM) + return nullptr; + + LLVMContext Ctx; + ModuleBuilder MB(Ctx, TM->getTargetTriple().str(), "TestModule"); + MB.getModule()->setDataLayout(TM->createDataLayout()); + auto *Main = MB.createFunctionDecl<void(int, char**)>("main"); + Main->getBasicBlockList().push_back(BasicBlock::Create(Ctx)); + IRBuilder<> B(&Main->back()); + B.CreateRet(ConstantInt::getSigned(Type::getInt32Ty(Ctx), 42)); + + SimpleCompiler IRCompiler(*TM); + return std::make_shared<object::OwningBinary<object::ObjectFile>>( + IRCompiler(*MB.getModule())); +} + +TEST(RemoteObjectLayer, AddObject) { + llvm::orc::rpc::registerStringError<rpc::RawByteChannel>(); + auto TestObject = createTestObject(); + if (!TestObject) + return; + + auto Channels = createPairedQueueChannels(); + + auto ReportError = + [](Error Err) { + logAllUnhandledErrors(std::move(Err), llvm::errs(), ""); + }; + + // Copy the bytes out of the test object: the copy will be used to verify + // that the original is correctly transmitted over RPC to the mock layer. + StringRef ObjBytes = TestObject->getBinary()->getData(); + std::vector<char> ObjContents(ObjBytes.size()); + std::copy(ObjBytes.begin(), ObjBytes.end(), ObjContents.begin()); + + RPCEndpoint ClientEP(*Channels.first, true); + RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError); + + RPCEndpoint ServerEP(*Channels.second, true); + MockObjectLayer BaseLayer( + [&ObjContents](MockObjectLayer::ObjectPtr Obj, + MockObjectLayer::SymbolLookupTable &SymTab) { + + // Check that the received object file content matches the original. + StringRef RPCObjContents = Obj->getBinary()->getData(); + EXPECT_EQ(RPCObjContents.size(), ObjContents.size()) + << "RPC'd object file has incorrect size"; + EXPECT_TRUE(std::equal(RPCObjContents.begin(), RPCObjContents.end(), + ObjContents.begin())) + << "RPC'd object file content does not match original content"; + + return 1; + }); + RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler<remote::utils::TerminateSession>( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + cantFail(Client.addObject(std::move(TestObject), + std::make_shared<NullResolver>())); + cantFail(ClientEP.callB<remote::utils::TerminateSession>()); + ServerThread.join(); +} + +TEST(RemoteObjectLayer, AddObjectFailure) { + llvm::orc::rpc::registerStringError<rpc::RawByteChannel>(); + auto TestObject = createTestObject(); + if (!TestObject) + return; + + auto Channels = createPairedQueueChannels(); + + auto ReportError = + [](Error Err) { + auto ErrMsg = toString(std::move(Err)); + EXPECT_EQ(ErrMsg, "AddObjectFailure - Test Message") + << "Expected error string to be \"AddObjectFailure - Test Message\""; + }; + + RPCEndpoint ClientEP(*Channels.first, true); + RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError); + + RPCEndpoint ServerEP(*Channels.second, true); + MockObjectLayer BaseLayer( + [](MockObjectLayer::ObjectPtr Obj, + MockObjectLayer::SymbolLookupTable &SymTab) + -> Expected<MockObjectLayer::ObjHandleT> { + return make_error<StringError>("AddObjectFailure - Test Message", + inconvertibleErrorCode()); + }); + RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler<remote::utils::TerminateSession>( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + auto HandleOrErr = + Client.addObject(std::move(TestObject), std::make_shared<NullResolver>()); + + EXPECT_FALSE(HandleOrErr) << "Expected error from addObject"; + + auto ErrMsg = toString(HandleOrErr.takeError()); + EXPECT_EQ(ErrMsg, "AddObjectFailure - Test Message") + << "Expected error string to be \"AddObjectFailure - Test Message\""; + + cantFail(ClientEP.callB<remote::utils::TerminateSession>()); + ServerThread.join(); +} + + +TEST(RemoteObjectLayer, RemoveObject) { + llvm::orc::rpc::registerStringError<rpc::RawByteChannel>(); + auto TestObject = createTestObject(); + if (!TestObject) + return; + + auto Channels = createPairedQueueChannels(); + + auto ReportError = + [](Error Err) { + logAllUnhandledErrors(std::move(Err), llvm::errs(), ""); + }; + + RPCEndpoint ClientEP(*Channels.first, true); + RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError); + + RPCEndpoint ServerEP(*Channels.second, true); + + MockObjectLayer BaseLayer( + [](MockObjectLayer::ObjectPtr Obj, + MockObjectLayer::SymbolLookupTable &SymTab) { + SymTab[1] = MockObjectLayer::LookupFn(); + return 1; + }); + RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler<remote::utils::TerminateSession>( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + auto H = cantFail(Client.addObject(std::move(TestObject), + std::make_shared<NullResolver>())); + + cantFail(Client.removeObject(H)); + + cantFail(ClientEP.callB<remote::utils::TerminateSession>()); + ServerThread.join(); +} + +TEST(RemoteObjectLayer, RemoveObjectFailure) { + llvm::orc::rpc::registerStringError<rpc::RawByteChannel>(); + auto TestObject = createTestObject(); + if (!TestObject) + return; + + auto Channels = createPairedQueueChannels(); + + auto ReportError = + [](Error Err) { + auto ErrMsg = toString(std::move(Err)); + EXPECT_EQ(ErrMsg, "Object handle 42 not found") + << "Expected error string to be \"Object handle 42 not found\""; + }; + + RPCEndpoint ClientEP(*Channels.first, true); + RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError); + + RPCEndpoint ServerEP(*Channels.second, true); + + // AddObject lambda does not update symbol table, so removeObject will treat + // this as a bad object handle. + MockObjectLayer BaseLayer( + [](MockObjectLayer::ObjectPtr Obj, + MockObjectLayer::SymbolLookupTable &SymTab) { + return 42; + }); + RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler<remote::utils::TerminateSession>( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + auto H = cantFail(Client.addObject(std::move(TestObject), + std::make_shared<NullResolver>())); + + auto Err = Client.removeObject(H); + EXPECT_TRUE(!!Err) << "Expected error from removeObject"; + + auto ErrMsg = toString(std::move(Err)); + EXPECT_EQ(ErrMsg, "Object handle 42 not found") + << "Expected error string to be \"Object handle 42 not found\""; + + cantFail(ClientEP.callB<remote::utils::TerminateSession>()); + ServerThread.join(); +} + +TEST(RemoteObjectLayer, FindSymbol) { + llvm::orc::rpc::registerStringError<rpc::RawByteChannel>(); + auto TestObject = createTestObject(); + if (!TestObject) + return; + + auto Channels = createPairedQueueChannels(); + + auto ReportError = + [](Error Err) { + auto ErrMsg = toString(std::move(Err)); + EXPECT_EQ(ErrMsg, "Could not find symbol 'badsymbol'") + << "Expected error string to be \"Object handle 42 not found\""; + }; + + RPCEndpoint ClientEP(*Channels.first, true); + RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError); + + RPCEndpoint ServerEP(*Channels.second, true); + + // AddObject lambda does not update symbol table, so removeObject will treat + // this as a bad object handle. + MockObjectLayer BaseLayer( + [](MockObjectLayer::ObjectPtr Obj, + MockObjectLayer::SymbolLookupTable &SymTab) { + SymTab[42] = + [](StringRef Name, bool ExportedSymbolsOnly) -> JITSymbol { + if (Name == "foobar") + return JITSymbol(0x12348765, JITSymbolFlags::Exported); + if (Name == "badsymbol") + return make_error<JITSymbolNotFound>(Name); + return nullptr; + }; + return 42; + }); + RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler<remote::utils::TerminateSession>( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + cantFail(Client.addObject(std::move(TestObject), + std::make_shared<NullResolver>())); + + // Check that we can find and materialize a valid symbol. + auto Sym1 = Client.findSymbol("foobar", true); + EXPECT_TRUE(!!Sym1) << "Symbol 'foobar' should be findable"; + EXPECT_EQ(cantFail(Sym1.getAddress()), 0x12348765ULL) + << "Symbol 'foobar' does not return the correct address"; + + { + // Check that we can return a symbol containing an error. + auto Sym2 = Client.findSymbol("badsymbol", true); + EXPECT_FALSE(!!Sym2) << "Symbol 'badsymbol' should not be findable"; + auto Err = Sym2.takeError(); + EXPECT_TRUE(!!Err) << "Sym2 should contain an error value"; + auto ErrMsg = toString(std::move(Err)); + EXPECT_EQ(ErrMsg, "Could not find symbol 'badsymbol'") + << "Expected symbol-not-found error for Sym2"; + } + + { + // Check that we can return a 'null' symbol. + auto Sym3 = Client.findSymbol("baz", true); + EXPECT_FALSE(!!Sym3) << "Symbol 'baz' should convert to false"; + auto Err = Sym3.takeError(); + EXPECT_FALSE(!!Err) << "Symbol 'baz' should not contain an error"; + } + + cantFail(ClientEP.callB<remote::utils::TerminateSession>()); + ServerThread.join(); +} + +TEST(RemoteObjectLayer, FindSymbolIn) { + llvm::orc::rpc::registerStringError<rpc::RawByteChannel>(); + auto TestObject = createTestObject(); + if (!TestObject) + return; + + auto Channels = createPairedQueueChannels(); + + auto ReportError = + [](Error Err) { + auto ErrMsg = toString(std::move(Err)); + EXPECT_EQ(ErrMsg, "Could not find symbol 'barbaz'") + << "Expected error string to be \"Object handle 42 not found\""; + }; + + RPCEndpoint ClientEP(*Channels.first, true); + RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError); + + RPCEndpoint ServerEP(*Channels.second, true); + + // AddObject lambda does not update symbol table, so removeObject will treat + // this as a bad object handle. + MockObjectLayer BaseLayer( + [](MockObjectLayer::ObjectPtr Obj, + MockObjectLayer::SymbolLookupTable &SymTab) { + SymTab[42] = + [](StringRef Name, bool ExportedSymbolsOnly) -> JITSymbol { + if (Name == "foobar") + return JITSymbol(0x12348765, JITSymbolFlags::Exported); + return make_error<JITSymbolNotFound>(Name); + }; + // Dummy symbol table entry - this should not be visible to + // findSymbolIn. + SymTab[43] = + [](StringRef Name, bool ExportedSymbolsOnly) -> JITSymbol { + if (Name == "barbaz") + return JITSymbol(0xdeadbeef, JITSymbolFlags::Exported); + return make_error<JITSymbolNotFound>(Name); + }; + + return 42; + }); + RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler<remote::utils::TerminateSession>( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + auto H = cantFail(Client.addObject(std::move(TestObject), + std::make_shared<NullResolver>())); + + auto Sym1 = Client.findSymbolIn(H, "foobar", true); + + EXPECT_TRUE(!!Sym1) << "Symbol 'foobar' should be findable"; + EXPECT_EQ(cantFail(Sym1.getAddress()), 0x12348765ULL) + << "Symbol 'foobar' does not return the correct address"; + + auto Sym2 = Client.findSymbolIn(H, "barbaz", true); + EXPECT_FALSE(!!Sym2) << "Symbol 'barbaz' should not be findable"; + auto Err = Sym2.takeError(); + EXPECT_TRUE(!!Err) << "Sym2 should contain an error value"; + auto ErrMsg = toString(std::move(Err)); + EXPECT_EQ(ErrMsg, "Could not find symbol 'barbaz'") + << "Expected symbol-not-found error for Sym2"; + + cantFail(ClientEP.callB<remote::utils::TerminateSession>()); + ServerThread.join(); +} + +TEST(RemoteObjectLayer, EmitAndFinalize) { + llvm::orc::rpc::registerStringError<rpc::RawByteChannel>(); + auto TestObject = createTestObject(); + if (!TestObject) + return; + + auto Channels = createPairedQueueChannels(); + + auto ReportError = + [](Error Err) { + logAllUnhandledErrors(std::move(Err), llvm::errs(), ""); + }; + + RPCEndpoint ClientEP(*Channels.first, true); + RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError); + + RPCEndpoint ServerEP(*Channels.second, true); + + MockObjectLayer BaseLayer( + [](MockObjectLayer::ObjectPtr Obj, + MockObjectLayer::SymbolLookupTable &SymTab) { + SymTab[1] = MockObjectLayer::LookupFn(); + return 1; + }); + RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler<remote::utils::TerminateSession>( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + auto H = cantFail(Client.addObject(std::move(TestObject), + std::make_shared<NullResolver>())); + + auto Err = Client.emitAndFinalize(H); + EXPECT_FALSE(!!Err) << "emitAndFinalize should work"; + + cantFail(ClientEP.callB<remote::utils::TerminateSession>()); + ServerThread.join(); +} + +TEST(RemoteObjectLayer, EmitAndFinalizeFailure) { + llvm::orc::rpc::registerStringError<rpc::RawByteChannel>(); + auto TestObject = createTestObject(); + if (!TestObject) + return; + + auto Channels = createPairedQueueChannels(); + + auto ReportError = + [](Error Err) { + auto ErrMsg = toString(std::move(Err)); + EXPECT_EQ(ErrMsg, "Object handle 1 not found") + << "Expected bad handle error"; + }; + + RPCEndpoint ClientEP(*Channels.first, true); + RemoteObjectClientLayer<RPCEndpoint> Client(ClientEP, ReportError); + + RPCEndpoint ServerEP(*Channels.second, true); + + MockObjectLayer BaseLayer( + [](MockObjectLayer::ObjectPtr Obj, + MockObjectLayer::SymbolLookupTable &SymTab) { + return 1; + }); + RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler<remote::utils::TerminateSession>( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + auto H = cantFail(Client.addObject(std::move(TestObject), + std::make_shared<NullResolver>())); + + auto Err = Client.emitAndFinalize(H); + EXPECT_TRUE(!!Err) << "emitAndFinalize should work"; + + auto ErrMsg = toString(std::move(Err)); + EXPECT_EQ(ErrMsg, "Object handle 1 not found") + << "emitAndFinalize returned incorrect error"; + + cantFail(ClientEP.callB<remote::utils::TerminateSession>()); + ServerThread.join(); +} + +} |
