diff options
Diffstat (limited to 'gnu/llvm/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp')
-rw-r--r-- | gnu/llvm/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/gnu/llvm/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp b/gnu/llvm/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp new file mode 100644 index 00000000000..c88c94f17b1 --- /dev/null +++ b/gnu/llvm/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp @@ -0,0 +1,275 @@ +//===- ObjectTransformLayerTest.cpp - Unit tests for ObjectTransformLayer -===// +// +// 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/ObjectTransformLayer.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "gtest/gtest.h" + +using namespace llvm::orc; + +namespace { + +// Stand-in for RuntimeDyld::MemoryManager +typedef int MockMemoryManager; + +// Stand-in for RuntimeDyld::SymbolResolver +typedef int MockSymbolResolver; + +// stand-in for object::ObjectFile +typedef int MockObjectFile; + +// stand-in for llvm::MemoryBuffer set +typedef int MockMemoryBufferSet; + +// Mock transform that operates on unique pointers to object files, and +// allocates new object files rather than mutating the given ones. +struct AllocatingTransform { + std::unique_ptr<MockObjectFile> + operator()(std::unique_ptr<MockObjectFile> Obj) const { + return llvm::make_unique<MockObjectFile>(*Obj + 1); + } +}; + +// Mock base layer for verifying behavior of transform layer. +// Each method "T foo(args)" is accompanied by two auxiliary methods: +// - "void expectFoo(args)", to be called before calling foo on the transform +// layer; saves values of args, which mock layer foo then verifies against. +// - "void verifyFoo(T)", to be called after foo, which verifies that the +// transform layer called the base layer and forwarded any return value. +class MockBaseLayer { +public: + typedef int ObjSetHandleT; + + MockBaseLayer() : MockSymbol(nullptr) { resetExpectations(); } + + template <typename ObjSetT, typename MemoryManagerPtrT, + typename SymbolResolverPtrT> + ObjSetHandleT addObjectSet(ObjSetT &Objects, MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { + EXPECT_EQ(MockManager, *MemMgr) << "MM should pass through"; + EXPECT_EQ(MockResolver, *Resolver) << "Resolver should pass through"; + size_t I = 0; + for (auto &ObjPtr : Objects) { + EXPECT_EQ(MockObjects[I++] + 1, *ObjPtr) << "Transform should be applied"; + } + EXPECT_EQ(MockObjects.size(), I) << "Number of objects should match"; + LastCalled = "addObjectSet"; + MockObjSetHandle = 111; + return MockObjSetHandle; + } + template <typename ObjSetT> + void expectAddObjectSet(ObjSetT &Objects, MockMemoryManager *MemMgr, + MockSymbolResolver *Resolver) { + MockManager = *MemMgr; + MockResolver = *Resolver; + for (auto &ObjPtr : Objects) { + MockObjects.push_back(*ObjPtr); + } + } + void verifyAddObjectSet(ObjSetHandleT Returned) { + EXPECT_EQ("addObjectSet", LastCalled); + EXPECT_EQ(MockObjSetHandle, Returned) << "Return should pass through"; + resetExpectations(); + } + + void removeObjectSet(ObjSetHandleT H) { + EXPECT_EQ(MockObjSetHandle, H); + LastCalled = "removeObjectSet"; + } + void expectRemoveObjectSet(ObjSetHandleT H) { MockObjSetHandle = H; } + void verifyRemoveObjectSet() { + EXPECT_EQ("removeObjectSet", LastCalled); + resetExpectations(); + } + + JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { + EXPECT_EQ(MockName, Name) << "Name should pass through"; + EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through"; + LastCalled = "findSymbol"; + MockSymbol = JITSymbol(122, llvm::JITSymbolFlags::None); + return MockSymbol; + } + void expectFindSymbol(const std::string &Name, bool ExportedSymbolsOnly) { + MockName = Name; + MockBool = ExportedSymbolsOnly; + } + void verifyFindSymbol(llvm::orc::JITSymbol Returned) { + EXPECT_EQ("findSymbol", LastCalled); + EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress()) + << "Return should pass through"; + resetExpectations(); + } + + JITSymbol findSymbolIn(ObjSetHandleT H, const std::string &Name, + bool ExportedSymbolsOnly) { + EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through"; + EXPECT_EQ(MockName, Name) << "Name should pass through"; + EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through"; + LastCalled = "findSymbolIn"; + MockSymbol = JITSymbol(122, llvm::JITSymbolFlags::None); + return MockSymbol; + } + void expectFindSymbolIn(ObjSetHandleT H, const std::string &Name, + bool ExportedSymbolsOnly) { + MockObjSetHandle = H; + MockName = Name; + MockBool = ExportedSymbolsOnly; + } + void verifyFindSymbolIn(llvm::orc::JITSymbol Returned) { + EXPECT_EQ("findSymbolIn", LastCalled); + EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress()) + << "Return should pass through"; + resetExpectations(); + } + + void emitAndFinalize(ObjSetHandleT H) { + EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through"; + LastCalled = "emitAndFinalize"; + } + void expectEmitAndFinalize(ObjSetHandleT H) { MockObjSetHandle = H; } + void verifyEmitAndFinalize() { + EXPECT_EQ("emitAndFinalize", LastCalled); + resetExpectations(); + } + + void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress, + TargetAddress TargetAddr) { + EXPECT_EQ(MockObjSetHandle, H); + EXPECT_EQ(MockLocalAddress, LocalAddress); + EXPECT_EQ(MockTargetAddress, TargetAddr); + LastCalled = "mapSectionAddress"; + } + void expectMapSectionAddress(ObjSetHandleT H, const void *LocalAddress, + TargetAddress TargetAddr) { + MockObjSetHandle = H; + MockLocalAddress = LocalAddress; + MockTargetAddress = TargetAddr; + } + void verifyMapSectionAddress() { + EXPECT_EQ("mapSectionAddress", LastCalled); + resetExpectations(); + } + +private: + // Backing fields for remembering parameter/return values + std::string LastCalled; + MockMemoryManager MockManager; + MockSymbolResolver MockResolver; + std::vector<MockObjectFile> MockObjects; + ObjSetHandleT MockObjSetHandle; + std::string MockName; + bool MockBool; + JITSymbol MockSymbol; + const void *MockLocalAddress; + TargetAddress MockTargetAddress; + MockMemoryBufferSet MockBufferSet; + + // Clear remembered parameters between calls + void resetExpectations() { + LastCalled = "nothing"; + MockManager = 0; + MockResolver = 0; + MockObjects.clear(); + MockObjSetHandle = 0; + MockName = "bogus"; + MockSymbol = JITSymbol(nullptr); + MockLocalAddress = nullptr; + MockTargetAddress = 0; + MockBufferSet = 0; + } +}; + +// Test each operation on ObjectTransformLayer. +TEST(ObjectTransformLayerTest, Main) { + MockBaseLayer M; + + // Create one object transform layer using a transform (as a functor) + // that allocates new objects, and deals in unique pointers. + ObjectTransformLayer<MockBaseLayer, AllocatingTransform> T1(M); + + // Create a second object transform layer using a transform (as a lambda) + // that mutates objects in place, and deals in naked pointers + ObjectTransformLayer<MockBaseLayer, + std::function<MockObjectFile *(MockObjectFile *)>> + T2(M, [](MockObjectFile *Obj) { + ++(*Obj); + return Obj; + }); + + // Instantiate some mock objects to use below + MockObjectFile MockObject1 = 211; + MockObjectFile MockObject2 = 222; + MockMemoryManager MockManager = 233; + MockSymbolResolver MockResolver = 244; + + // Test addObjectSet with T1 (allocating, unique pointers) + std::vector<std::unique_ptr<MockObjectFile>> Objs1; + Objs1.push_back(llvm::make_unique<MockObjectFile>(MockObject1)); + Objs1.push_back(llvm::make_unique<MockObjectFile>(MockObject2)); + auto MM = llvm::make_unique<MockMemoryManager>(MockManager); + auto SR = llvm::make_unique<MockSymbolResolver>(MockResolver); + M.expectAddObjectSet(Objs1, MM.get(), SR.get()); + auto H = T1.addObjectSet(Objs1, std::move(MM), std::move(SR)); + M.verifyAddObjectSet(H); + + // Test addObjectSet with T2 (mutating, naked pointers) + llvm::SmallVector<MockObjectFile *, 2> Objs2; + Objs2.push_back(&MockObject1); + Objs2.push_back(&MockObject2); + M.expectAddObjectSet(Objs2, &MockManager, &MockResolver); + H = T2.addObjectSet(Objs2, &MockManager, &MockResolver); + M.verifyAddObjectSet(H); + EXPECT_EQ(212, MockObject1) << "Expected mutation"; + EXPECT_EQ(223, MockObject2) << "Expected mutation"; + + // Test removeObjectSet + M.expectRemoveObjectSet(H); + T1.removeObjectSet(H); + M.verifyRemoveObjectSet(); + + // Test findSymbol + std::string Name = "foo"; + bool ExportedOnly = true; + M.expectFindSymbol(Name, ExportedOnly); + JITSymbol Symbol = T2.findSymbol(Name, ExportedOnly); + M.verifyFindSymbol(Symbol); + + // Test findSymbolIn + Name = "bar"; + ExportedOnly = false; + M.expectFindSymbolIn(H, Name, ExportedOnly); + Symbol = T1.findSymbolIn(H, Name, ExportedOnly); + M.verifyFindSymbolIn(Symbol); + + // Test emitAndFinalize + M.expectEmitAndFinalize(H); + T2.emitAndFinalize(H); + M.verifyEmitAndFinalize(); + + // Test mapSectionAddress + char Buffer[24]; + TargetAddress MockAddress = 255; + M.expectMapSectionAddress(H, Buffer, MockAddress); + T1.mapSectionAddress(H, Buffer, MockAddress); + M.verifyMapSectionAddress(); + + // Verify transform getter (non-const) + MockObjectFile Mutatee = 277; + MockObjectFile *Out = T2.getTransform()(&Mutatee); + EXPECT_EQ(&Mutatee, Out) << "Expected in-place transform"; + EXPECT_EQ(278, Mutatee) << "Expected incrementing transform"; + + // Verify transform getter (const) + auto OwnedObj = llvm::make_unique<MockObjectFile>(288); + const auto &T1C = T1; + OwnedObj = T1C.getTransform()(std::move(OwnedObj)); + EXPECT_EQ(289, *OwnedObj) << "Expected incrementing transform"; +} +} |