diff options
Diffstat (limited to 'unittests/ExecutionEngine/Orc')
10 files changed, 800 insertions, 76 deletions
diff --git a/unittests/ExecutionEngine/Orc/CMakeLists.txt b/unittests/ExecutionEngine/Orc/CMakeLists.txt index db40c4213bd7..28e07959ac7b 100644 --- a/unittests/ExecutionEngine/Orc/CMakeLists.txt +++ b/unittests/ExecutionEngine/Orc/CMakeLists.txt @@ -18,8 +18,10 @@ add_llvm_unittest(OrcJITTests OrcCAPITest.cpp OrcTestCommon.cpp QueueChannel.cpp + RemoteObjectLayerTest.cpp RPCUtilsTest.cpp RTDyldObjectLinkingLayerTest.cpp + SymbolStringPoolTest.cpp ) -target_link_libraries(OrcJITTests ${LLVM_PTHREAD_LIB}) +target_link_libraries(OrcJITTests PRIVATE ${LLVM_PTHREAD_LIB}) diff --git a/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp b/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp index 844746f28c06..61ce310e6311 100644 --- a/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp +++ b/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp @@ -21,7 +21,7 @@ public: DummyCallbackManager() : JITCompileCallbackManager(0) {} public: - void grow() override { llvm_unreachable("not implemented"); } + Error grow() override { llvm_unreachable("not implemented"); } }; class DummyStubsManager : public orc::IndirectStubsManager { @@ -49,21 +49,18 @@ public: }; TEST(CompileOnDemandLayerTest, FindSymbol) { - auto MockBaseLayer = createMockBaseLayer<int>( - DoNothingAndReturn<int>(0), - [](int Handle) { return Error::success(); }, - [](const std::string &Name, bool) { - if (Name == "foo") - return JITSymbol(1, JITSymbolFlags::Exported); - return JITSymbol(nullptr); - }, - ReturnNullJITSymbol()); + MockBaseLayer<int, std::shared_ptr<Module>> TestBaseLayer; + TestBaseLayer.findSymbolImpl = + [](const std::string &Name, bool) { + if (Name == "foo") + return JITSymbol(1, JITSymbolFlags::Exported); + return JITSymbol(nullptr); + }; - typedef decltype(MockBaseLayer) MockBaseLayerT; DummyCallbackManager CallbackMgr; - llvm::orc::CompileOnDemandLayer<MockBaseLayerT> COD( - MockBaseLayer, [](Function &F) { return std::set<Function *>{&F}; }, + llvm::orc::CompileOnDemandLayer<decltype(TestBaseLayer)> COD( + TestBaseLayer, [](Function &F) { return std::set<Function *>{&F}; }, CallbackMgr, [] { return llvm::make_unique<DummyStubsManager>(); }, true); auto Sym = COD.findSymbol("foo", true); diff --git a/unittests/ExecutionEngine/Orc/GlobalMappingLayerTest.cpp b/unittests/ExecutionEngine/Orc/GlobalMappingLayerTest.cpp index 2756999c2160..d093b2a99bd7 100644 --- a/unittests/ExecutionEngine/Orc/GlobalMappingLayerTest.cpp +++ b/unittests/ExecutionEngine/Orc/GlobalMappingLayerTest.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/GlobalMappingLayer.h" +#include "OrcTestCommon.h" #include "gtest/gtest.h" using namespace llvm; @@ -15,21 +16,26 @@ using namespace llvm::orc; namespace { -struct MockBaseLayer { +TEST(GlobalMappingLayerTest, Empty) { + MockBaseLayer<int, std::shared_ptr<Module>> TestBaseLayer; - typedef int ModuleHandleT; + TestBaseLayer.addModuleImpl = + [](std::shared_ptr<Module> M, std::shared_ptr<JITSymbolResolver> R) { + return 42; + }; - JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { - if (Name == "bar") - return llvm::JITSymbol(0x4567, JITSymbolFlags::Exported); - return nullptr; - } + TestBaseLayer.findSymbolImpl = + [](const std::string &Name, bool ExportedSymbolsOnly) -> JITSymbol { + if (Name == "bar") + return llvm::JITSymbol(0x4567, JITSymbolFlags::Exported); + return nullptr; + }; -}; + GlobalMappingLayer<decltype(TestBaseLayer)> L(TestBaseLayer); -TEST(GlobalMappingLayerTest, Empty) { - MockBaseLayer M; - GlobalMappingLayer<MockBaseLayer> L(M); + // Test addModule interface. + int H = cantFail(L.addModule(nullptr, nullptr)); + EXPECT_EQ(H, 42) << "Incorrect result from addModule"; // Test fall-through for missing symbol. auto FooSym = L.findSymbol("foo", true); diff --git a/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp b/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp index 25103f79ac6c..7cd6443b5d4a 100644 --- a/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp +++ b/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp @@ -10,7 +10,6 @@ #include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ExecutionEngine/Orc/CompileUtils.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" #include "llvm/ExecutionEngine/Orc/NullResolver.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" diff --git a/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp b/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp index 5a4d6b4a2252..d9448d47667f 100644 --- a/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp +++ b/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "OrcTestCommon.h" +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" #include "llvm-c/Core.h" #include "llvm-c/OrcBindings.h" #include "llvm-c/Target.h" @@ -37,6 +38,15 @@ protected: return MB.takeModule(); } + std::shared_ptr<object::OwningBinary<object::ObjectFile>> + createTestObject() { + orc::SimpleCompiler IRCompiler(*TM); + auto M = createTestModule(TM->getTargetTriple()); + M->setDataLayout(TM->createDataLayout()); + return std::make_shared<object::OwningBinary<object::ObjectFile>>( + IRCompiler(*M)); + } + typedef int (*MainFnTy)(); static int myTestFuncImpl() { @@ -134,6 +144,36 @@ TEST_F(OrcCAPIExecutionTest, TestLazyIRCompilation) { LLVMOrcDisposeInstance(JIT); } +TEST_F(OrcCAPIExecutionTest, TestAddObjectFile) { + if (!TM) + return; + + std::unique_ptr<MemoryBuffer> ObjBuffer; + { + auto OwningObj = createTestObject(); + auto ObjAndBuffer = OwningObj->takeBinary(); + ObjBuffer = std::move(ObjAndBuffer.second); + } + + LLVMOrcJITStackRef JIT = + LLVMOrcCreateInstance(wrap(TM.get())); + LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc"); + + LLVMOrcModuleHandle H; + LLVMOrcAddObjectFile(JIT, &H, wrap(ObjBuffer.release()), myResolver, nullptr); + LLVMOrcTargetAddress MainAddr; + LLVMOrcGetSymbolAddress(JIT, &MainAddr, "main"); + MainFnTy MainFn = (MainFnTy)MainAddr; + int Result = MainFn(); + EXPECT_EQ(Result, 42) + << "Lazily JIT'd code did not return expected result"; + + LLVMOrcRemoveModule(JIT, H); + + LLVMOrcDisposeMangledSymbol(testFuncName); + LLVMOrcDisposeInstance(JIT); +} + TEST_F(OrcCAPIExecutionTest, TestDirectCallbacksAPI) { if (!TM) return; diff --git a/unittests/ExecutionEngine/Orc/OrcTestCommon.h b/unittests/ExecutionEngine/Orc/OrcTestCommon.h index 6c6b4918c205..28a5f08ee439 100644 --- a/unittests/ExecutionEngine/Orc/OrcTestCommon.h +++ b/unittests/ExecutionEngine/Orc/OrcTestCommon.h @@ -105,73 +105,63 @@ public: } }; -template <typename HandleT, - typename AddModuleFtor, - typename RemoveModuleFtor, - typename FindSymbolFtor, - typename FindSymbolInFtor> +template <typename HandleT, typename ModuleT> class MockBaseLayer { public: - typedef HandleT ModuleHandleT; - - MockBaseLayer(AddModuleFtor &&AddModule, - RemoveModuleFtor &&RemoveModule, - FindSymbolFtor &&FindSymbol, - FindSymbolInFtor &&FindSymbolIn) - : AddModule(std::move(AddModule)), - RemoveModule(std::move(RemoveModule)), - FindSymbol(std::move(FindSymbol)), - FindSymbolIn(std::move(FindSymbolIn)) - {} - - template <typename ModuleT, typename MemoryManagerPtrT, - typename SymbolResolverPtrT> - Expected<ModuleHandleT> addModule(ModuleT Ms, MemoryManagerPtrT MemMgr, - SymbolResolverPtrT Resolver) { - return AddModule(std::move(Ms), std::move(MemMgr), std::move(Resolver)); + using ModuleHandleT = HandleT; + + using AddModuleSignature = + Expected<ModuleHandleT>(ModuleT M, + std::shared_ptr<JITSymbolResolver> R); + + using RemoveModuleSignature = Error(ModuleHandleT H); + using FindSymbolSignature = JITSymbol(const std::string &Name, + bool ExportedSymbolsOnly); + using FindSymbolInSignature = JITSymbol(ModuleHandleT H, + const std::string &Name, + bool ExportedSymbolsONly); + using EmitAndFinalizeSignature = Error(ModuleHandleT H); + + std::function<AddModuleSignature> addModuleImpl; + std::function<RemoveModuleSignature> removeModuleImpl; + std::function<FindSymbolSignature> findSymbolImpl; + std::function<FindSymbolInSignature> findSymbolInImpl; + std::function<EmitAndFinalizeSignature> emitAndFinalizeImpl; + + Expected<ModuleHandleT> addModule(ModuleT M, + std::shared_ptr<JITSymbolResolver> R) { + assert(addModuleImpl && + "addModule called, but no mock implementation was provided"); + return addModuleImpl(std::move(M), std::move(R)); } Error removeModule(ModuleHandleT H) { - return RemoveModule(H); + assert(removeModuleImpl && + "removeModule called, but no mock implementation was provided"); + return removeModuleImpl(H); } JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { - return FindSymbol(Name, ExportedSymbolsOnly); + assert(findSymbolImpl && + "findSymbol called, but no mock implementation was provided"); + return findSymbolImpl(Name, ExportedSymbolsOnly); } JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name, bool ExportedSymbolsOnly) { - return FindSymbolIn(H, Name, ExportedSymbolsOnly); + assert(findSymbolInImpl && + "findSymbolIn called, but no mock implementation was provided"); + return findSymbolInImpl(H, Name, ExportedSymbolsOnly); } -private: - AddModuleFtor AddModule; - RemoveModuleFtor RemoveModule; - FindSymbolFtor FindSymbol; - FindSymbolInFtor FindSymbolIn; + Error emitAndFinaliez(ModuleHandleT H) { + assert(emitAndFinalizeImpl && + "emitAndFinalize called, but no mock implementation was provided"); + return emitAndFinalizeImpl(H); + } }; -template <typename ModuleHandleT, - typename AddModuleFtor, - typename RemoveModuleFtor, - typename FindSymbolFtor, - typename FindSymbolInFtor> -MockBaseLayer<ModuleHandleT, AddModuleFtor, RemoveModuleFtor, - FindSymbolFtor, FindSymbolInFtor> -createMockBaseLayer(AddModuleFtor &&AddModule, - RemoveModuleFtor &&RemoveModule, - FindSymbolFtor &&FindSymbol, - FindSymbolInFtor &&FindSymbolIn) { - return MockBaseLayer<ModuleHandleT, AddModuleFtor, RemoveModuleFtor, - FindSymbolFtor, FindSymbolInFtor>( - std::forward<AddModuleFtor>(AddModule), - std::forward<RemoveModuleFtor>(RemoveModule), - std::forward<FindSymbolFtor>(FindSymbol), - std::forward<FindSymbolInFtor>(FindSymbolIn)); -} - - class ReturnNullJITSymbol { public: template <typename... Args> diff --git a/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp b/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp index 1c9764b555fd..7fe449b70169 100644 --- a/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp +++ b/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp @@ -263,6 +263,51 @@ TEST(DummyRPC, TestCallAsyncIntInt) { ServerThread.join(); } +TEST(DummyRPC, TestAsyncVoidBoolHandler) { + auto Channels = createPairedQueueChannels(); + DummyRPCEndpoint Client(*Channels.first); + DummyRPCEndpoint Server(*Channels.second); + + std::thread ServerThread([&]() { + Server.addAsyncHandler<DummyRPCAPI::VoidBool>( + [](std::function<Error(Error)> SendResult, + bool B) { + EXPECT_EQ(B, true) << "Server void(bool) receieved unexpected result"; + cantFail(SendResult(Error::success())); + return Error::success(); + }); + + { + // Poke the server to handle the negotiate call. + auto Err = Server.handleOne(); + EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate"; + } + + { + // Poke the server to handle the VoidBool call. + auto Err = Server.handleOne(); + EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)"; + } + }); + + { + auto Err = Client.callAsync<DummyRPCAPI::VoidBool>( + [](Error Result) { + EXPECT_FALSE(!!Result) << "Async void(bool) response handler failed"; + return Error::success(); + }, true); + EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(bool)"; + } + + { + // Poke the client to process the result. + auto Err = Client.handleOne(); + EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)"; + } + + ServerThread.join(); +} + TEST(DummyRPC, TestAsyncIntIntHandler) { auto Channels = createPairedQueueChannels(); DummyRPCEndpoint Client(*Channels.first); diff --git a/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp b/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp index e4b61d855c5f..ed7b327124d7 100644 --- a/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp +++ b/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp @@ -255,4 +255,12 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) { "(multiple unrelated objects loaded prior to finalization)"; } +TEST_F(RTDyldObjectLinkingLayerExecutionTest, TestNotifyLoadedSignature) { + RTDyldObjectLinkingLayer ObjLayer( + []() { return nullptr; }, + [](RTDyldObjectLinkingLayer::ObjHandleT, + const RTDyldObjectLinkingLayer::ObjectPtr &obj, + const RuntimeDyld::LoadedObjectInfo &info) {}); +} + } // end anonymous namespace 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(); +} + +} diff --git a/unittests/ExecutionEngine/Orc/SymbolStringPoolTest.cpp b/unittests/ExecutionEngine/Orc/SymbolStringPoolTest.cpp new file mode 100644 index 000000000000..79929e332182 --- /dev/null +++ b/unittests/ExecutionEngine/Orc/SymbolStringPoolTest.cpp @@ -0,0 +1,48 @@ +//===----- SymbolStringPoolTest.cpp - Unit tests for SymbolStringPool -----===// +// +// 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/SymbolStringPool.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::orc; + +namespace { + +TEST(SymbolStringPool, UniquingAndComparisons) { + SymbolStringPool SP; + auto P1 = SP.intern("hello"); + + std::string S("hel"); + S += "lo"; + auto P2 = SP.intern(S); + + auto P3 = SP.intern("goodbye"); + + EXPECT_EQ(P1, P2) << "Failed to unique entries"; + EXPECT_NE(P1, P3) << "Inequal pooled symbol strings comparing equal"; + + // We want to test that less-than comparison of SymbolStringPtrs compiles, + // however we can't test the actual result as this is a pointer comparison and + // SymbolStringPtr doesn't expose the underlying address of the string. + (void)(P1 < P3); +} + +TEST(SymbolStringPool, ClearDeadEntries) { + SymbolStringPool SP; + { + auto P1 = SP.intern("s1"); + SP.clearDeadEntries(); + EXPECT_FALSE(SP.empty()) << "\"s1\" entry in pool should still be retained"; + } + SP.clearDeadEntries(); + EXPECT_TRUE(SP.empty()) << "pool should be empty"; +} + +} |
