LegacyRTDyldObjectLinkingLayerTest.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. //===- RTDyldObjectLinkingLayerTest.cpp - RTDyld linking layer unit tests -===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
  9. #include "OrcTestCommon.h"
  10. #include "llvm/ExecutionEngine/ExecutionEngine.h"
  11. #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
  12. #include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
  13. #include "llvm/ExecutionEngine/Orc/Legacy.h"
  14. #include "llvm/ExecutionEngine/Orc/NullResolver.h"
  15. #include "llvm/ExecutionEngine/SectionMemoryManager.h"
  16. #include "llvm/IR/Constants.h"
  17. #include "llvm/IR/LLVMContext.h"
  18. #include "gtest/gtest.h"
  19. using namespace llvm;
  20. using namespace llvm::orc;
  21. namespace {
  22. class LegacyRTDyldObjectLinkingLayerExecutionTest : public testing::Test,
  23. public OrcExecutionTest {
  24. };
  25. class SectionMemoryManagerWrapper : public SectionMemoryManager {
  26. public:
  27. int FinalizationCount = 0;
  28. int NeedsToReserveAllocationSpaceCount = 0;
  29. bool needsToReserveAllocationSpace() override {
  30. ++NeedsToReserveAllocationSpaceCount;
  31. return SectionMemoryManager::needsToReserveAllocationSpace();
  32. }
  33. bool finalizeMemory(std::string *ErrMsg = nullptr) override {
  34. ++FinalizationCount;
  35. return SectionMemoryManager::finalizeMemory(ErrMsg);
  36. }
  37. };
  38. TEST(LegacyRTDyldObjectLinkingLayerTest, TestSetProcessAllSections) {
  39. class MemoryManagerWrapper : public SectionMemoryManager {
  40. public:
  41. MemoryManagerWrapper(bool &DebugSeen) : DebugSeen(DebugSeen) {}
  42. uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
  43. unsigned SectionID,
  44. StringRef SectionName,
  45. bool IsReadOnly) override {
  46. if (SectionName == ".debug_str")
  47. DebugSeen = true;
  48. return SectionMemoryManager::allocateDataSection(Size, Alignment,
  49. SectionID,
  50. SectionName,
  51. IsReadOnly);
  52. }
  53. private:
  54. bool &DebugSeen;
  55. };
  56. bool DebugSectionSeen = false;
  57. auto MM = std::make_shared<MemoryManagerWrapper>(DebugSectionSeen);
  58. ExecutionSession ES;
  59. LegacyRTDyldObjectLinkingLayer ObjLayer(
  60. AcknowledgeORCv1Deprecation, ES, [&MM](VModuleKey) {
  61. return LegacyRTDyldObjectLinkingLayer::Resources{
  62. MM, std::make_shared<NullResolver>()};
  63. });
  64. LLVMContext Context;
  65. auto M = std::make_unique<Module>("", Context);
  66. M->setTargetTriple("x86_64-unknown-linux-gnu");
  67. Type *Int32Ty = IntegerType::get(Context, 32);
  68. GlobalVariable *GV =
  69. new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage,
  70. ConstantInt::get(Int32Ty, 42), "foo");
  71. GV->setSection(".debug_str");
  72. // Initialize the native target in case this is the first unit test
  73. // to try to build a TM.
  74. OrcNativeTarget::initialize();
  75. std::unique_ptr<TargetMachine> TM(
  76. EngineBuilder().selectTarget(Triple(M->getTargetTriple()), "", "",
  77. SmallVector<std::string, 1>()));
  78. if (!TM)
  79. return;
  80. auto Obj = SimpleCompiler(*TM)(*M);
  81. {
  82. // Test with ProcessAllSections = false (the default).
  83. auto K = ES.allocateVModule();
  84. cantFail(ObjLayer.addObject(
  85. K, MemoryBuffer::getMemBufferCopy(Obj->getBuffer())));
  86. cantFail(ObjLayer.emitAndFinalize(K));
  87. EXPECT_EQ(DebugSectionSeen, false)
  88. << "Unexpected debug info section";
  89. cantFail(ObjLayer.removeObject(K));
  90. }
  91. {
  92. // Test with ProcessAllSections = true.
  93. ObjLayer.setProcessAllSections(true);
  94. auto K = ES.allocateVModule();
  95. cantFail(ObjLayer.addObject(K, std::move(Obj)));
  96. cantFail(ObjLayer.emitAndFinalize(K));
  97. EXPECT_EQ(DebugSectionSeen, true)
  98. << "Expected debug info section not seen";
  99. cantFail(ObjLayer.removeObject(K));
  100. }
  101. }
  102. TEST_F(LegacyRTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
  103. if (!SupportsJIT)
  104. return;
  105. Type *Int32Ty = IntegerType::get(Context, 32);
  106. ExecutionSession ES;
  107. auto MM = std::make_shared<SectionMemoryManagerWrapper>();
  108. std::map<orc::VModuleKey, std::shared_ptr<orc::SymbolResolver>> Resolvers;
  109. LegacyRTDyldObjectLinkingLayer ObjLayer(
  110. AcknowledgeORCv1Deprecation, ES, [&](VModuleKey K) {
  111. auto I = Resolvers.find(K);
  112. assert(I != Resolvers.end() && "Missing resolver");
  113. auto R = std::move(I->second);
  114. Resolvers.erase(I);
  115. return LegacyRTDyldObjectLinkingLayer::Resources{MM, std::move(R)};
  116. });
  117. SimpleCompiler Compile(*TM);
  118. // Create a pair of modules that will trigger recursive finalization:
  119. // Module 1:
  120. // int bar() { return 42; }
  121. // Module 2:
  122. // int bar();
  123. // int foo() { return bar(); }
  124. //
  125. // Verify that the memory manager is only finalized once (for Module 2).
  126. // Failure suggests that finalize is being called on the inner RTDyld
  127. // instance (for Module 1) which is unsafe, as it will prevent relocation of
  128. // Module 2.
  129. ModuleBuilder MB1(Context, "", "dummy");
  130. {
  131. MB1.getModule()->setDataLayout(TM->createDataLayout());
  132. Function *BarImpl =
  133. MB1.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "bar");
  134. BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
  135. IRBuilder<> Builder(BarEntry);
  136. IntegerType *Int32Ty = IntegerType::get(Context, 32);
  137. Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
  138. Builder.CreateRet(FourtyTwo);
  139. }
  140. auto Obj1 = Compile(*MB1.getModule());
  141. ModuleBuilder MB2(Context, "", "dummy");
  142. {
  143. MB2.getModule()->setDataLayout(TM->createDataLayout());
  144. Function *BarDecl =
  145. MB2.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "bar");
  146. Function *FooImpl =
  147. MB2.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "foo");
  148. BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl);
  149. IRBuilder<> Builder(FooEntry);
  150. Builder.CreateRet(Builder.CreateCall(BarDecl));
  151. }
  152. auto Obj2 = Compile(*MB2.getModule());
  153. auto K1 = ES.allocateVModule();
  154. Resolvers[K1] = std::make_shared<NullResolver>();
  155. cantFail(ObjLayer.addObject(K1, std::move(Obj1)));
  156. auto K2 = ES.allocateVModule();
  157. auto LegacyLookup = [&](const std::string &Name) {
  158. return ObjLayer.findSymbol(Name, true);
  159. };
  160. Resolvers[K2] = createSymbolResolver(
  161. [&](const SymbolNameSet &Symbols) {
  162. return cantFail(
  163. getResponsibilitySetWithLegacyFn(Symbols, LegacyLookup));
  164. },
  165. [&](std::shared_ptr<AsynchronousSymbolQuery> Query,
  166. const SymbolNameSet &Symbols) {
  167. return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
  168. });
  169. cantFail(ObjLayer.addObject(K2, std::move(Obj2)));
  170. cantFail(ObjLayer.emitAndFinalize(K2));
  171. cantFail(ObjLayer.removeObject(K2));
  172. // Finalization of module 2 should trigger finalization of module 1.
  173. // Verify that finalize on SMMW is only called once.
  174. EXPECT_EQ(MM->FinalizationCount, 1)
  175. << "Extra call to finalize";
  176. }
  177. TEST_F(LegacyRTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
  178. if (!SupportsJIT)
  179. return;
  180. Type *Int32Ty = IntegerType::get(Context, 32);
  181. ExecutionSession ES;
  182. auto MM = std::make_shared<SectionMemoryManagerWrapper>();
  183. LegacyRTDyldObjectLinkingLayer ObjLayer(
  184. AcknowledgeORCv1Deprecation, ES, [&MM](VModuleKey K) {
  185. return LegacyRTDyldObjectLinkingLayer::Resources{
  186. MM, std::make_shared<NullResolver>()};
  187. });
  188. SimpleCompiler Compile(*TM);
  189. // Create a pair of unrelated modules:
  190. //
  191. // Module 1:
  192. // int foo() { return 42; }
  193. // Module 2:
  194. // int bar() { return 7; }
  195. //
  196. // Both modules will share a memory manager. We want to verify that the
  197. // second object is not loaded before the first one is finalized. To do this
  198. // in a portable way, we abuse the
  199. // RuntimeDyld::MemoryManager::needsToReserveAllocationSpace hook, which is
  200. // called once per object before any sections are allocated.
  201. ModuleBuilder MB1(Context, "", "dummy");
  202. {
  203. MB1.getModule()->setDataLayout(TM->createDataLayout());
  204. Function *BarImpl =
  205. MB1.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "foo");
  206. BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
  207. IRBuilder<> Builder(BarEntry);
  208. IntegerType *Int32Ty = IntegerType::get(Context, 32);
  209. Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
  210. Builder.CreateRet(FourtyTwo);
  211. }
  212. auto Obj1 = Compile(*MB1.getModule());
  213. ModuleBuilder MB2(Context, "", "dummy");
  214. {
  215. MB2.getModule()->setDataLayout(TM->createDataLayout());
  216. Function *BarImpl =
  217. MB2.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "bar");
  218. BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
  219. IRBuilder<> Builder(BarEntry);
  220. IntegerType *Int32Ty = IntegerType::get(Context, 32);
  221. Value *Seven = ConstantInt::getSigned(Int32Ty, 7);
  222. Builder.CreateRet(Seven);
  223. }
  224. auto Obj2 = Compile(*MB2.getModule());
  225. auto K = ES.allocateVModule();
  226. cantFail(ObjLayer.addObject(K, std::move(Obj1)));
  227. cantFail(ObjLayer.addObject(ES.allocateVModule(), std::move(Obj2)));
  228. cantFail(ObjLayer.emitAndFinalize(K));
  229. cantFail(ObjLayer.removeObject(K));
  230. // Only one call to needsToReserveAllocationSpace should have been made.
  231. EXPECT_EQ(MM->NeedsToReserveAllocationSpaceCount, 1)
  232. << "More than one call to needsToReserveAllocationSpace "
  233. "(multiple unrelated objects loaded prior to finalization)";
  234. }
  235. TEST_F(LegacyRTDyldObjectLinkingLayerExecutionTest, TestNotifyLoadedSignature) {
  236. ExecutionSession ES;
  237. LegacyRTDyldObjectLinkingLayer ObjLayer(
  238. AcknowledgeORCv1Deprecation, ES,
  239. [](VModuleKey) {
  240. return LegacyRTDyldObjectLinkingLayer::Resources{
  241. nullptr, std::make_shared<NullResolver>()};
  242. },
  243. [](VModuleKey, const object::ObjectFile &obj,
  244. const RuntimeDyld::LoadedObjectInfo &info) {});
  245. }
  246. } // end anonymous namespace