From 044eb2f6afba375a914ac9d8024f8f5142bb912e Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Mon, 18 Dec 2017 20:10:56 +0000 Subject: Vendor import of llvm trunk r321017: https://llvm.org/svn/llvm-project/llvm/trunk@321017 --- .../ExecutionEngine/Orc/RemoteObjectLayerTest.cpp | 589 +++++++++++++++++++++ 1 file changed, 589 insertions(+) create mode 100644 unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp (limited to 'unittests/ExecutionEngine/Orc/RemoteObjectLayerTest.cpp') 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>; + + using LookupFn = std::function; + using SymbolLookupTable = std::map; + + using AddObjectFtor = + std::function(ObjectPtr, SymbolLookupTable&)>; + + class ObjectNotFound : public remote::ResourceNotFound { + public: + ObjectNotFound(ObjHandleT H) : ResourceNotFound(H, "Object handle") {} + }; + + MockObjectLayer(AddObjectFtor AddObject) + : AddObject(std::move(AddObject)) {} + + Expected addObject(ObjectPtr Obj, + std::shared_ptr Resolver) { + return AddObject(Obj, SymTab); + } + + Error removeObject(ObjHandleT H) { + if (SymTab.count(H)) + return Error::success(); + else + return make_error(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(H); + } + + Error emitAndFinalize(ObjHandleT H) { + if (SymTab.count(H)) + return Error::success(); + else + return make_error(H); + } + +private: + AddObjectFtor AddObject; + SymbolLookupTable SymTab; +}; + +using RPCEndpoint = rpc::SingleThreadedRPCEndpoint; + +MockObjectLayer::ObjectPtr createTestObject() { + OrcNativeTarget::initialize(); + auto TM = std::unique_ptr(EngineBuilder().selectTarget()); + + if (!TM) + return nullptr; + + LLVMContext Ctx; + ModuleBuilder MB(Ctx, TM->getTargetTriple().str(), "TestModule"); + MB.getModule()->setDataLayout(TM->createDataLayout()); + auto *Main = MB.createFunctionDecl("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>( + IRCompiler(*MB.getModule())); +} + +TEST(RemoteObjectLayer, AddObject) { + llvm::orc::rpc::registerStringError(); + 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 ObjContents(ObjBytes.size()); + std::copy(ObjBytes.begin(), ObjBytes.end(), ObjContents.begin()); + + RPCEndpoint ClientEP(*Channels.first, true); + RemoteObjectClientLayer 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 Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + cantFail(Client.addObject(std::move(TestObject), + std::make_shared())); + cantFail(ClientEP.callB()); + ServerThread.join(); +} + +TEST(RemoteObjectLayer, AddObjectFailure) { + llvm::orc::rpc::registerStringError(); + 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 Client(ClientEP, ReportError); + + RPCEndpoint ServerEP(*Channels.second, true); + MockObjectLayer BaseLayer( + [](MockObjectLayer::ObjectPtr Obj, + MockObjectLayer::SymbolLookupTable &SymTab) + -> Expected { + return make_error("AddObjectFailure - Test Message", + inconvertibleErrorCode()); + }); + RemoteObjectServerLayer Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + auto HandleOrErr = + Client.addObject(std::move(TestObject), std::make_shared()); + + 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()); + ServerThread.join(); +} + + +TEST(RemoteObjectLayer, RemoveObject) { + llvm::orc::rpc::registerStringError(); + 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 Client(ClientEP, ReportError); + + RPCEndpoint ServerEP(*Channels.second, true); + + MockObjectLayer BaseLayer( + [](MockObjectLayer::ObjectPtr Obj, + MockObjectLayer::SymbolLookupTable &SymTab) { + SymTab[1] = MockObjectLayer::LookupFn(); + return 1; + }); + RemoteObjectServerLayer Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + auto H = cantFail(Client.addObject(std::move(TestObject), + std::make_shared())); + + cantFail(Client.removeObject(H)); + + cantFail(ClientEP.callB()); + ServerThread.join(); +} + +TEST(RemoteObjectLayer, RemoveObjectFailure) { + llvm::orc::rpc::registerStringError(); + 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 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 Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + auto H = cantFail(Client.addObject(std::move(TestObject), + std::make_shared())); + + 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()); + ServerThread.join(); +} + +TEST(RemoteObjectLayer, FindSymbol) { + llvm::orc::rpc::registerStringError(); + 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 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(Name); + return nullptr; + }; + return 42; + }); + RemoteObjectServerLayer Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + cantFail(Client.addObject(std::move(TestObject), + std::make_shared())); + + // 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()); + ServerThread.join(); +} + +TEST(RemoteObjectLayer, FindSymbolIn) { + llvm::orc::rpc::registerStringError(); + 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 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(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(Name); + }; + + return 42; + }); + RemoteObjectServerLayer Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + auto H = cantFail(Client.addObject(std::move(TestObject), + std::make_shared())); + + 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()); + ServerThread.join(); +} + +TEST(RemoteObjectLayer, EmitAndFinalize) { + llvm::orc::rpc::registerStringError(); + 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 Client(ClientEP, ReportError); + + RPCEndpoint ServerEP(*Channels.second, true); + + MockObjectLayer BaseLayer( + [](MockObjectLayer::ObjectPtr Obj, + MockObjectLayer::SymbolLookupTable &SymTab) { + SymTab[1] = MockObjectLayer::LookupFn(); + return 1; + }); + RemoteObjectServerLayer Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + auto H = cantFail(Client.addObject(std::move(TestObject), + std::make_shared())); + + auto Err = Client.emitAndFinalize(H); + EXPECT_FALSE(!!Err) << "emitAndFinalize should work"; + + cantFail(ClientEP.callB()); + ServerThread.join(); +} + +TEST(RemoteObjectLayer, EmitAndFinalizeFailure) { + llvm::orc::rpc::registerStringError(); + 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 Client(ClientEP, ReportError); + + RPCEndpoint ServerEP(*Channels.second, true); + + MockObjectLayer BaseLayer( + [](MockObjectLayer::ObjectPtr Obj, + MockObjectLayer::SymbolLookupTable &SymTab) { + return 1; + }); + RemoteObjectServerLayer Server(BaseLayer, + ServerEP, + ReportError); + + bool Finished = false; + ServerEP.addHandler( + [&]() { Finished = true; } + ); + + auto ServerThread = + std::thread([&]() { + while (!Finished) + cantFail(ServerEP.handleOne()); + }); + + auto H = cantFail(Client.addObject(std::move(TestObject), + std::make_shared())); + + 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()); + ServerThread.join(); +} + +} -- cgit v1.2.3