ObjectTransformLayerTest.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. //===- ObjectTransformLayerTest.cpp - Unit tests for ObjectTransformLayer -===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "llvm/ADT/STLExtras.h"
  10. #include "llvm/ADT/SmallVector.h"
  11. #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
  12. #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
  13. #include "llvm/ExecutionEngine/Orc/NullResolver.h"
  14. #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
  15. #include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
  16. #include "llvm/Object/ObjectFile.h"
  17. #include "gtest/gtest.h"
  18. using namespace llvm::orc;
  19. namespace {
  20. // Stand-in for RuntimeDyld::MemoryManager
  21. typedef int MockMemoryManager;
  22. // Stand-in for RuntimeDyld::SymbolResolver
  23. typedef int MockSymbolResolver;
  24. // stand-in for object::ObjectFile
  25. typedef int MockObjectFile;
  26. // stand-in for llvm::MemoryBuffer set
  27. typedef int MockMemoryBufferSet;
  28. // Mock transform that operates on unique pointers to object files, and
  29. // allocates new object files rather than mutating the given ones.
  30. struct AllocatingTransform {
  31. std::unique_ptr<MockObjectFile>
  32. operator()(std::unique_ptr<MockObjectFile> Obj) const {
  33. return llvm::make_unique<MockObjectFile>(*Obj + 1);
  34. }
  35. };
  36. // Mock base layer for verifying behavior of transform layer.
  37. // Each method "T foo(args)" is accompanied by two auxiliary methods:
  38. // - "void expectFoo(args)", to be called before calling foo on the transform
  39. // layer; saves values of args, which mock layer foo then verifies against.
  40. // - "void verifyFoo(T)", to be called after foo, which verifies that the
  41. // transform layer called the base layer and forwarded any return value.
  42. class MockBaseLayer {
  43. public:
  44. typedef int ObjSetHandleT;
  45. MockBaseLayer() : MockSymbol(nullptr) { resetExpectations(); }
  46. template <typename ObjSetT, typename MemoryManagerPtrT,
  47. typename SymbolResolverPtrT>
  48. ObjSetHandleT addObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr,
  49. SymbolResolverPtrT Resolver) {
  50. EXPECT_EQ(MockManager, *MemMgr) << "MM should pass through";
  51. EXPECT_EQ(MockResolver, *Resolver) << "Resolver should pass through";
  52. size_t I = 0;
  53. for (auto &ObjPtr : Objects) {
  54. EXPECT_EQ(MockObjects[I] + 1, *ObjPtr) << "Transform should be applied";
  55. I++;
  56. }
  57. EXPECT_EQ(MockObjects.size(), I) << "Number of objects should match";
  58. LastCalled = "addObjectSet";
  59. MockObjSetHandle = 111;
  60. return MockObjSetHandle;
  61. }
  62. template <typename ObjSetT>
  63. void expectAddObjectSet(ObjSetT &Objects, MockMemoryManager *MemMgr,
  64. MockSymbolResolver *Resolver) {
  65. MockManager = *MemMgr;
  66. MockResolver = *Resolver;
  67. for (auto &ObjPtr : Objects) {
  68. MockObjects.push_back(*ObjPtr);
  69. }
  70. }
  71. void verifyAddObjectSet(ObjSetHandleT Returned) {
  72. EXPECT_EQ("addObjectSet", LastCalled);
  73. EXPECT_EQ(MockObjSetHandle, Returned) << "Return should pass through";
  74. resetExpectations();
  75. }
  76. void removeObjectSet(ObjSetHandleT H) {
  77. EXPECT_EQ(MockObjSetHandle, H);
  78. LastCalled = "removeObjectSet";
  79. }
  80. void expectRemoveObjectSet(ObjSetHandleT H) { MockObjSetHandle = H; }
  81. void verifyRemoveObjectSet() {
  82. EXPECT_EQ("removeObjectSet", LastCalled);
  83. resetExpectations();
  84. }
  85. llvm::JITSymbol findSymbol(const std::string &Name,
  86. bool ExportedSymbolsOnly) {
  87. EXPECT_EQ(MockName, Name) << "Name should pass through";
  88. EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
  89. LastCalled = "findSymbol";
  90. MockSymbol = llvm::JITSymbol(122, llvm::JITSymbolFlags::None);
  91. return MockSymbol;
  92. }
  93. void expectFindSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
  94. MockName = Name;
  95. MockBool = ExportedSymbolsOnly;
  96. }
  97. void verifyFindSymbol(llvm::JITSymbol Returned) {
  98. EXPECT_EQ("findSymbol", LastCalled);
  99. EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
  100. << "Return should pass through";
  101. resetExpectations();
  102. }
  103. llvm::JITSymbol findSymbolIn(ObjSetHandleT H, const std::string &Name,
  104. bool ExportedSymbolsOnly) {
  105. EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
  106. EXPECT_EQ(MockName, Name) << "Name should pass through";
  107. EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
  108. LastCalled = "findSymbolIn";
  109. MockSymbol = llvm::JITSymbol(122, llvm::JITSymbolFlags::None);
  110. return MockSymbol;
  111. }
  112. void expectFindSymbolIn(ObjSetHandleT H, const std::string &Name,
  113. bool ExportedSymbolsOnly) {
  114. MockObjSetHandle = H;
  115. MockName = Name;
  116. MockBool = ExportedSymbolsOnly;
  117. }
  118. void verifyFindSymbolIn(llvm::JITSymbol Returned) {
  119. EXPECT_EQ("findSymbolIn", LastCalled);
  120. EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
  121. << "Return should pass through";
  122. resetExpectations();
  123. }
  124. void emitAndFinalize(ObjSetHandleT H) {
  125. EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
  126. LastCalled = "emitAndFinalize";
  127. }
  128. void expectEmitAndFinalize(ObjSetHandleT H) { MockObjSetHandle = H; }
  129. void verifyEmitAndFinalize() {
  130. EXPECT_EQ("emitAndFinalize", LastCalled);
  131. resetExpectations();
  132. }
  133. void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
  134. llvm::JITTargetAddress TargetAddr) {
  135. EXPECT_EQ(MockObjSetHandle, H);
  136. EXPECT_EQ(MockLocalAddress, LocalAddress);
  137. EXPECT_EQ(MockTargetAddress, TargetAddr);
  138. LastCalled = "mapSectionAddress";
  139. }
  140. void expectMapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
  141. llvm::JITTargetAddress TargetAddr) {
  142. MockObjSetHandle = H;
  143. MockLocalAddress = LocalAddress;
  144. MockTargetAddress = TargetAddr;
  145. }
  146. void verifyMapSectionAddress() {
  147. EXPECT_EQ("mapSectionAddress", LastCalled);
  148. resetExpectations();
  149. }
  150. private:
  151. // Backing fields for remembering parameter/return values
  152. std::string LastCalled;
  153. MockMemoryManager MockManager;
  154. MockSymbolResolver MockResolver;
  155. std::vector<MockObjectFile> MockObjects;
  156. ObjSetHandleT MockObjSetHandle;
  157. std::string MockName;
  158. bool MockBool;
  159. llvm::JITSymbol MockSymbol;
  160. const void *MockLocalAddress;
  161. llvm::JITTargetAddress MockTargetAddress;
  162. MockMemoryBufferSet MockBufferSet;
  163. // Clear remembered parameters between calls
  164. void resetExpectations() {
  165. LastCalled = "nothing";
  166. MockManager = 0;
  167. MockResolver = 0;
  168. MockObjects.clear();
  169. MockObjSetHandle = 0;
  170. MockName = "bogus";
  171. MockSymbol = llvm::JITSymbol(nullptr);
  172. MockLocalAddress = nullptr;
  173. MockTargetAddress = 0;
  174. MockBufferSet = 0;
  175. }
  176. };
  177. // Test each operation on ObjectTransformLayer.
  178. TEST(ObjectTransformLayerTest, Main) {
  179. MockBaseLayer M;
  180. // Create one object transform layer using a transform (as a functor)
  181. // that allocates new objects, and deals in unique pointers.
  182. ObjectTransformLayer<MockBaseLayer, AllocatingTransform> T1(M);
  183. // Create a second object transform layer using a transform (as a lambda)
  184. // that mutates objects in place, and deals in naked pointers
  185. ObjectTransformLayer<MockBaseLayer,
  186. std::function<MockObjectFile *(MockObjectFile *)>>
  187. T2(M, [](MockObjectFile *Obj) {
  188. ++(*Obj);
  189. return Obj;
  190. });
  191. // Instantiate some mock objects to use below
  192. MockObjectFile MockObject1 = 211;
  193. MockObjectFile MockObject2 = 222;
  194. MockMemoryManager MockManager = 233;
  195. MockSymbolResolver MockResolver = 244;
  196. // Test addObjectSet with T1 (allocating, unique pointers)
  197. std::vector<std::unique_ptr<MockObjectFile>> Objs1;
  198. Objs1.push_back(llvm::make_unique<MockObjectFile>(MockObject1));
  199. Objs1.push_back(llvm::make_unique<MockObjectFile>(MockObject2));
  200. auto MM = llvm::make_unique<MockMemoryManager>(MockManager);
  201. auto SR = llvm::make_unique<MockSymbolResolver>(MockResolver);
  202. M.expectAddObjectSet(Objs1, MM.get(), SR.get());
  203. auto H = T1.addObjectSet(std::move(Objs1), std::move(MM), std::move(SR));
  204. M.verifyAddObjectSet(H);
  205. // Test addObjectSet with T2 (mutating, naked pointers)
  206. llvm::SmallVector<MockObjectFile *, 2> Objs2Vec;
  207. Objs2Vec.push_back(&MockObject1);
  208. Objs2Vec.push_back(&MockObject2);
  209. llvm::MutableArrayRef<MockObjectFile *> Objs2(Objs2Vec);
  210. M.expectAddObjectSet(Objs2, &MockManager, &MockResolver);
  211. H = T2.addObjectSet(Objs2, &MockManager, &MockResolver);
  212. M.verifyAddObjectSet(H);
  213. EXPECT_EQ(212, MockObject1) << "Expected mutation";
  214. EXPECT_EQ(223, MockObject2) << "Expected mutation";
  215. // Test removeObjectSet
  216. M.expectRemoveObjectSet(H);
  217. T1.removeObjectSet(H);
  218. M.verifyRemoveObjectSet();
  219. // Test findSymbol
  220. std::string Name = "foo";
  221. bool ExportedOnly = true;
  222. M.expectFindSymbol(Name, ExportedOnly);
  223. llvm::JITSymbol Symbol = T2.findSymbol(Name, ExportedOnly);
  224. M.verifyFindSymbol(Symbol);
  225. // Test findSymbolIn
  226. Name = "bar";
  227. ExportedOnly = false;
  228. M.expectFindSymbolIn(H, Name, ExportedOnly);
  229. Symbol = T1.findSymbolIn(H, Name, ExportedOnly);
  230. M.verifyFindSymbolIn(Symbol);
  231. // Test emitAndFinalize
  232. M.expectEmitAndFinalize(H);
  233. T2.emitAndFinalize(H);
  234. M.verifyEmitAndFinalize();
  235. // Test mapSectionAddress
  236. char Buffer[24];
  237. llvm::JITTargetAddress MockAddress = 255;
  238. M.expectMapSectionAddress(H, Buffer, MockAddress);
  239. T1.mapSectionAddress(H, Buffer, MockAddress);
  240. M.verifyMapSectionAddress();
  241. // Verify transform getter (non-const)
  242. MockObjectFile Mutatee = 277;
  243. MockObjectFile *Out = T2.getTransform()(&Mutatee);
  244. EXPECT_EQ(&Mutatee, Out) << "Expected in-place transform";
  245. EXPECT_EQ(278, Mutatee) << "Expected incrementing transform";
  246. // Verify transform getter (const)
  247. auto OwnedObj = llvm::make_unique<MockObjectFile>(288);
  248. const auto &T1C = T1;
  249. OwnedObj = T1C.getTransform()(std::move(OwnedObj));
  250. EXPECT_EQ(289, *OwnedObj) << "Expected incrementing transform";
  251. volatile bool RunStaticChecks = false;
  252. if (!RunStaticChecks)
  253. return;
  254. // Make sure that ObjectTransformLayer implements the object layer concept
  255. // correctly by sandwitching one between an ObjectLinkingLayer and an
  256. // IRCompileLayer, verifying that it compiles if we have a call to the
  257. // IRComileLayer's addModuleSet that should call the transform layer's
  258. // addObjectSet, and also calling the other public transform layer methods
  259. // directly to make sure the methods they intend to forward to exist on
  260. // the ObjectLinkingLayer.
  261. // We'll need a concrete MemoryManager class.
  262. class NullManager : public llvm::RuntimeDyld::MemoryManager {
  263. public:
  264. uint8_t *allocateCodeSection(uintptr_t, unsigned, unsigned,
  265. llvm::StringRef) override {
  266. return nullptr;
  267. }
  268. uint8_t *allocateDataSection(uintptr_t, unsigned, unsigned, llvm::StringRef,
  269. bool) override {
  270. return nullptr;
  271. }
  272. void registerEHFrames(uint8_t *, uint64_t, size_t) override {}
  273. void deregisterEHFrames() override {}
  274. bool finalizeMemory(std::string *) override { return false; }
  275. };
  276. // Construct the jit layers.
  277. RTDyldObjectLinkingLayer<> BaseLayer;
  278. auto IdentityTransform = [](
  279. std::unique_ptr<llvm::object::OwningBinary<llvm::object::ObjectFile>>
  280. Obj) { return Obj; };
  281. ObjectTransformLayer<decltype(BaseLayer), decltype(IdentityTransform)>
  282. TransformLayer(BaseLayer, IdentityTransform);
  283. auto NullCompiler = [](llvm::Module &) {
  284. return llvm::object::OwningBinary<llvm::object::ObjectFile>();
  285. };
  286. IRCompileLayer<decltype(TransformLayer)> CompileLayer(TransformLayer,
  287. NullCompiler);
  288. // Make sure that the calls from IRCompileLayer to ObjectTransformLayer
  289. // compile.
  290. NullResolver Resolver;
  291. NullManager Manager;
  292. CompileLayer.addModuleSet(std::vector<llvm::Module *>(), &Manager, &Resolver);
  293. // Make sure that the calls from ObjectTransformLayer to ObjectLinkingLayer
  294. // compile.
  295. decltype(TransformLayer)::ObjSetHandleT ObjSet;
  296. TransformLayer.emitAndFinalize(ObjSet);
  297. TransformLayer.findSymbolIn(ObjSet, Name, false);
  298. TransformLayer.findSymbol(Name, true);
  299. TransformLayer.mapSectionAddress(ObjSet, nullptr, 0);
  300. TransformLayer.removeObjectSet(ObjSet);
  301. }
  302. }