blob: 5eebddb496951e83c7d6bd09f13be7da39f452e3 [file] [log] [blame]
Andrew Kaylorced4e8f2013-04-25 21:02:36 +00001//===- MCJITObjectCacheTest.cpp - Unit tests for MCJIT object caching -----===//
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
Chandler Carruth8a8cd2b2014-01-07 11:48:04 +000010#include "MCJITTestBase.h"
Andrew Kaylorced4e8f2013-04-25 21:02:36 +000011#include "llvm/ADT/SmallVector.h"
12#include "llvm/ADT/StringMap.h"
13#include "llvm/ADT/StringSet.h"
Eric Christopherb9fd9ed2014-08-07 22:02:54 +000014#include "llvm/ExecutionEngine/JIT.h"
Andrew Kaylorced4e8f2013-04-25 21:02:36 +000015#include "llvm/ExecutionEngine/MCJIT.h"
16#include "llvm/ExecutionEngine/ObjectCache.h"
17#include "llvm/ExecutionEngine/SectionMemoryManager.h"
Andrew Kaylorced4e8f2013-04-25 21:02:36 +000018#include "gtest/gtest.h"
19
20using namespace llvm;
21
22namespace {
23
24class TestObjectCache : public ObjectCache {
25public:
26 TestObjectCache() : DuplicateInserted(false) { }
27
Andrew Kaylorced4e8f2013-04-25 21:02:36 +000028 virtual void notifyObjectCompiled(const Module *M, const MemoryBuffer *Obj) {
29 // If we've seen this module before, note that.
30 const std::string ModuleID = M->getModuleIdentifier();
31 if (ObjMap.find(ModuleID) != ObjMap.end())
32 DuplicateInserted = true;
33 // Store a copy of the buffer in our map.
34 ObjMap[ModuleID] = copyBuffer(Obj);
35 }
36
Rafael Espindola5f2bb7d2014-08-13 18:49:01 +000037 virtual std::unique_ptr<MemoryBuffer> getObject(const Module* M) {
Andrew Kaylorb595f532013-06-28 21:40:16 +000038 const MemoryBuffer* BufferFound = getObjectInternal(M);
39 ModulesLookedUp.insert(M->getModuleIdentifier());
40 if (!BufferFound)
Craig Topper66f09ad2014-06-08 22:29:17 +000041 return nullptr;
Andrew Kaylorb595f532013-06-28 21:40:16 +000042 // Our test cache wants to maintain ownership of its object buffers
43 // so we make a copy here for the execution engine.
Rafael Espindola5f2bb7d2014-08-13 18:49:01 +000044 return std::unique_ptr<MemoryBuffer>(
45 MemoryBuffer::getMemBufferCopy(BufferFound->getBuffer()));
Andrew Kaylorb595f532013-06-28 21:40:16 +000046 }
47
Andrew Kaylorced4e8f2013-04-25 21:02:36 +000048 // Test-harness-specific functions
49 bool wereDuplicatesInserted() { return DuplicateInserted; }
50
51 bool wasModuleLookedUp(const Module *M) {
52 return ModulesLookedUp.find(M->getModuleIdentifier())
53 != ModulesLookedUp.end();
54 }
55
56 const MemoryBuffer* getObjectInternal(const Module* M) {
57 // Look for the module in our map.
58 const std::string ModuleID = M->getModuleIdentifier();
59 StringMap<const MemoryBuffer *>::iterator it = ObjMap.find(ModuleID);
60 if (it == ObjMap.end())
Craig Topper66f09ad2014-06-08 22:29:17 +000061 return nullptr;
Andrew Kaylorced4e8f2013-04-25 21:02:36 +000062 return it->second;
63 }
64
Andrew Kaylorced4e8f2013-04-25 21:02:36 +000065private:
66 MemoryBuffer *copyBuffer(const MemoryBuffer *Buf) {
67 // Create a local copy of the buffer.
Rafael Espindolabb415ea2014-08-13 18:59:01 +000068 std::unique_ptr<MemoryBuffer> NewBuffer(
69 MemoryBuffer::getMemBufferCopy(Buf->getBuffer()));
70 MemoryBuffer *Ret = NewBuffer.get();
71 AllocatedBuffers.push_back(std::move(NewBuffer));
72 return Ret;
Andrew Kaylorced4e8f2013-04-25 21:02:36 +000073 }
74
75 StringMap<const MemoryBuffer *> ObjMap;
76 StringSet<> ModulesLookedUp;
Rafael Espindolabb415ea2014-08-13 18:59:01 +000077 SmallVector<std::unique_ptr<MemoryBuffer>, 2> AllocatedBuffers;
Andrew Kaylorced4e8f2013-04-25 21:02:36 +000078 bool DuplicateInserted;
79};
80
81class MCJITObjectCacheTest : public testing::Test, public MCJITTestBase {
82protected:
83
84 enum {
85 OriginalRC = 6,
86 ReplacementRC = 7
87 };
88
89 virtual void SetUp() {
90 M.reset(createEmptyModule("<main>"));
91 Main = insertMainFunction(M.get(), OriginalRC);
92 }
93
94 void compileAndRun(int ExpectedRC = OriginalRC) {
95 // This function shouldn't be called until after SetUp.
Ahmed Charles56440fd2014-03-06 05:51:42 +000096 ASSERT_TRUE(bool(TheJIT));
Craig Topper66f09ad2014-06-08 22:29:17 +000097 ASSERT_TRUE(nullptr != Main);
Andrew Kaylorced4e8f2013-04-25 21:02:36 +000098
David Tweed2e7efed2013-05-17 10:01:46 +000099 // We may be using a null cache, so ensure compilation is valid.
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000100 TheJIT->finalizeObject();
101 void *vPtr = TheJIT->getPointerToFunction(Main);
102
Craig Topper66f09ad2014-06-08 22:29:17 +0000103 EXPECT_TRUE(nullptr != vPtr)
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000104 << "Unable to get pointer to main() from JIT";
105
106 int (*FuncPtr)(void) = (int(*)(void))(intptr_t)vPtr;
107 int returnCode = FuncPtr();
108 EXPECT_EQ(returnCode, ExpectedRC);
109 }
110
111 Function *Main;
112};
113
114TEST_F(MCJITObjectCacheTest, SetNullObjectCache) {
115 SKIP_UNSUPPORTED_PLATFORM;
116
Rafael Espindola2a8a2792014-08-19 04:04:25 +0000117 createJIT(std::move(M));
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000118
Craig Topper66f09ad2014-06-08 22:29:17 +0000119 TheJIT->setObjectCache(nullptr);
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000120
121 compileAndRun();
122}
123
124
125TEST_F(MCJITObjectCacheTest, VerifyBasicObjectCaching) {
126 SKIP_UNSUPPORTED_PLATFORM;
127
Ahmed Charles56440fd2014-03-06 05:51:42 +0000128 std::unique_ptr<TestObjectCache> Cache(new TestObjectCache);
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000129
130 // Save a copy of the module pointer before handing it off to MCJIT.
131 const Module * SavedModulePointer = M.get();
132
Rafael Espindola2a8a2792014-08-19 04:04:25 +0000133 createJIT(std::move(M));
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000134
135 TheJIT->setObjectCache(Cache.get());
136
137 // Verify that our object cache does not contain the module yet.
138 const MemoryBuffer *ObjBuffer = Cache->getObjectInternal(SavedModulePointer);
Craig Topper66f09ad2014-06-08 22:29:17 +0000139 EXPECT_EQ(nullptr, ObjBuffer);
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000140
141 compileAndRun();
142
143 // Verify that MCJIT tried to look-up this module in the cache.
144 EXPECT_TRUE(Cache->wasModuleLookedUp(SavedModulePointer));
145
146 // Verify that our object cache now contains the module.
147 ObjBuffer = Cache->getObjectInternal(SavedModulePointer);
Craig Topper66f09ad2014-06-08 22:29:17 +0000148 EXPECT_TRUE(nullptr != ObjBuffer);
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000149
150 // Verify that the cache was only notified once.
151 EXPECT_FALSE(Cache->wereDuplicatesInserted());
152}
153
154TEST_F(MCJITObjectCacheTest, VerifyLoadFromCache) {
155 SKIP_UNSUPPORTED_PLATFORM;
156
Ahmed Charles56440fd2014-03-06 05:51:42 +0000157 std::unique_ptr<TestObjectCache> Cache(new TestObjectCache);
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000158
159 // Compile this module with an MCJIT engine
Rafael Espindola2a8a2792014-08-19 04:04:25 +0000160 createJIT(std::move(M));
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000161 TheJIT->setObjectCache(Cache.get());
162 TheJIT->finalizeObject();
163
164 // Destroy the MCJIT engine we just used
165 TheJIT.reset();
166
167 // Create a new memory manager.
168 MM = new SectionMemoryManager;
169
170 // Create a new module and save it. Use a different return code so we can
171 // tell if MCJIT compiled this module or used the cache.
172 M.reset(createEmptyModule("<main>"));
173 Main = insertMainFunction(M.get(), ReplacementRC);
174 const Module * SecondModulePointer = M.get();
175
176 // Create a new MCJIT instance to load this module then execute it.
Rafael Espindola2a8a2792014-08-19 04:04:25 +0000177 createJIT(std::move(M));
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000178 TheJIT->setObjectCache(Cache.get());
179 compileAndRun();
180
181 // Verify that MCJIT tried to look-up this module in the cache.
182 EXPECT_TRUE(Cache->wasModuleLookedUp(SecondModulePointer));
183
184 // Verify that MCJIT didn't try to cache this again.
185 EXPECT_FALSE(Cache->wereDuplicatesInserted());
186}
187
188TEST_F(MCJITObjectCacheTest, VerifyNonLoadFromCache) {
189 SKIP_UNSUPPORTED_PLATFORM;
190
Ahmed Charles56440fd2014-03-06 05:51:42 +0000191 std::unique_ptr<TestObjectCache> Cache(new TestObjectCache);
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000192
193 // Compile this module with an MCJIT engine
Rafael Espindola2a8a2792014-08-19 04:04:25 +0000194 createJIT(std::move(M));
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000195 TheJIT->setObjectCache(Cache.get());
196 TheJIT->finalizeObject();
197
198 // Destroy the MCJIT engine we just used
199 TheJIT.reset();
200
201 // Create a new memory manager.
202 MM = new SectionMemoryManager;
203
204 // Create a new module and save it. Use a different return code so we can
205 // tell if MCJIT compiled this module or used the cache. Note that we use
206 // a new module name here so the module shouldn't be found in the cache.
207 M.reset(createEmptyModule("<not-main>"));
208 Main = insertMainFunction(M.get(), ReplacementRC);
209 const Module * SecondModulePointer = M.get();
210
211 // Create a new MCJIT instance to load this module then execute it.
Rafael Espindola2a8a2792014-08-19 04:04:25 +0000212 createJIT(std::move(M));
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000213 TheJIT->setObjectCache(Cache.get());
214
215 // Verify that our object cache does not contain the module yet.
216 const MemoryBuffer *ObjBuffer = Cache->getObjectInternal(SecondModulePointer);
Craig Topper66f09ad2014-06-08 22:29:17 +0000217 EXPECT_EQ(nullptr, ObjBuffer);
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000218
219 // Run the function and look for the replacement return code.
220 compileAndRun(ReplacementRC);
221
222 // Verify that MCJIT tried to look-up this module in the cache.
223 EXPECT_TRUE(Cache->wasModuleLookedUp(SecondModulePointer));
224
225 // Verify that our object cache now contains the module.
226 ObjBuffer = Cache->getObjectInternal(SecondModulePointer);
Craig Topper66f09ad2014-06-08 22:29:17 +0000227 EXPECT_TRUE(nullptr != ObjBuffer);
Andrew Kaylorced4e8f2013-04-25 21:02:36 +0000228
229 // Verify that MCJIT didn't try to cache this again.
230 EXPECT_FALSE(Cache->wereDuplicatesInserted());
231}
232
233} // Namespace
234