1*9880d681SAndroid Build Coastguard Worker //===- MCJITObjectCacheTest.cpp - Unit tests for MCJIT object caching -----===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker // The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker
10*9880d681SAndroid Build Coastguard Worker #include "MCJITTestBase.h"
11*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/SmallVector.h"
12*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/StringMap.h"
13*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/StringSet.h"
14*9880d681SAndroid Build Coastguard Worker #include "llvm/ExecutionEngine/MCJIT.h"
15*9880d681SAndroid Build Coastguard Worker #include "llvm/ExecutionEngine/ObjectCache.h"
16*9880d681SAndroid Build Coastguard Worker #include "llvm/ExecutionEngine/SectionMemoryManager.h"
17*9880d681SAndroid Build Coastguard Worker #include "gtest/gtest.h"
18*9880d681SAndroid Build Coastguard Worker
19*9880d681SAndroid Build Coastguard Worker using namespace llvm;
20*9880d681SAndroid Build Coastguard Worker
21*9880d681SAndroid Build Coastguard Worker namespace {
22*9880d681SAndroid Build Coastguard Worker
23*9880d681SAndroid Build Coastguard Worker class TestObjectCache : public ObjectCache {
24*9880d681SAndroid Build Coastguard Worker public:
TestObjectCache()25*9880d681SAndroid Build Coastguard Worker TestObjectCache() : DuplicateInserted(false) { }
26*9880d681SAndroid Build Coastguard Worker
notifyObjectCompiled(const Module * M,MemoryBufferRef Obj)27*9880d681SAndroid Build Coastguard Worker void notifyObjectCompiled(const Module *M, MemoryBufferRef Obj) override {
28*9880d681SAndroid Build Coastguard Worker // If we've seen this module before, note that.
29*9880d681SAndroid Build Coastguard Worker const std::string ModuleID = M->getModuleIdentifier();
30*9880d681SAndroid Build Coastguard Worker if (ObjMap.find(ModuleID) != ObjMap.end())
31*9880d681SAndroid Build Coastguard Worker DuplicateInserted = true;
32*9880d681SAndroid Build Coastguard Worker // Store a copy of the buffer in our map.
33*9880d681SAndroid Build Coastguard Worker ObjMap[ModuleID] = copyBuffer(Obj);
34*9880d681SAndroid Build Coastguard Worker }
35*9880d681SAndroid Build Coastguard Worker
getObject(const Module * M)36*9880d681SAndroid Build Coastguard Worker std::unique_ptr<MemoryBuffer> getObject(const Module *M) override {
37*9880d681SAndroid Build Coastguard Worker const MemoryBuffer* BufferFound = getObjectInternal(M);
38*9880d681SAndroid Build Coastguard Worker ModulesLookedUp.insert(M->getModuleIdentifier());
39*9880d681SAndroid Build Coastguard Worker if (!BufferFound)
40*9880d681SAndroid Build Coastguard Worker return nullptr;
41*9880d681SAndroid Build Coastguard Worker // Our test cache wants to maintain ownership of its object buffers
42*9880d681SAndroid Build Coastguard Worker // so we make a copy here for the execution engine.
43*9880d681SAndroid Build Coastguard Worker return MemoryBuffer::getMemBufferCopy(BufferFound->getBuffer());
44*9880d681SAndroid Build Coastguard Worker }
45*9880d681SAndroid Build Coastguard Worker
46*9880d681SAndroid Build Coastguard Worker // Test-harness-specific functions
wereDuplicatesInserted()47*9880d681SAndroid Build Coastguard Worker bool wereDuplicatesInserted() { return DuplicateInserted; }
48*9880d681SAndroid Build Coastguard Worker
wasModuleLookedUp(const Module * M)49*9880d681SAndroid Build Coastguard Worker bool wasModuleLookedUp(const Module *M) {
50*9880d681SAndroid Build Coastguard Worker return ModulesLookedUp.find(M->getModuleIdentifier())
51*9880d681SAndroid Build Coastguard Worker != ModulesLookedUp.end();
52*9880d681SAndroid Build Coastguard Worker }
53*9880d681SAndroid Build Coastguard Worker
getObjectInternal(const Module * M)54*9880d681SAndroid Build Coastguard Worker const MemoryBuffer* getObjectInternal(const Module* M) {
55*9880d681SAndroid Build Coastguard Worker // Look for the module in our map.
56*9880d681SAndroid Build Coastguard Worker const std::string ModuleID = M->getModuleIdentifier();
57*9880d681SAndroid Build Coastguard Worker StringMap<const MemoryBuffer *>::iterator it = ObjMap.find(ModuleID);
58*9880d681SAndroid Build Coastguard Worker if (it == ObjMap.end())
59*9880d681SAndroid Build Coastguard Worker return nullptr;
60*9880d681SAndroid Build Coastguard Worker return it->second;
61*9880d681SAndroid Build Coastguard Worker }
62*9880d681SAndroid Build Coastguard Worker
63*9880d681SAndroid Build Coastguard Worker private:
copyBuffer(MemoryBufferRef Buf)64*9880d681SAndroid Build Coastguard Worker MemoryBuffer *copyBuffer(MemoryBufferRef Buf) {
65*9880d681SAndroid Build Coastguard Worker // Create a local copy of the buffer.
66*9880d681SAndroid Build Coastguard Worker std::unique_ptr<MemoryBuffer> NewBuffer =
67*9880d681SAndroid Build Coastguard Worker MemoryBuffer::getMemBufferCopy(Buf.getBuffer());
68*9880d681SAndroid Build Coastguard Worker MemoryBuffer *Ret = NewBuffer.get();
69*9880d681SAndroid Build Coastguard Worker AllocatedBuffers.push_back(std::move(NewBuffer));
70*9880d681SAndroid Build Coastguard Worker return Ret;
71*9880d681SAndroid Build Coastguard Worker }
72*9880d681SAndroid Build Coastguard Worker
73*9880d681SAndroid Build Coastguard Worker StringMap<const MemoryBuffer *> ObjMap;
74*9880d681SAndroid Build Coastguard Worker StringSet<> ModulesLookedUp;
75*9880d681SAndroid Build Coastguard Worker SmallVector<std::unique_ptr<MemoryBuffer>, 2> AllocatedBuffers;
76*9880d681SAndroid Build Coastguard Worker bool DuplicateInserted;
77*9880d681SAndroid Build Coastguard Worker };
78*9880d681SAndroid Build Coastguard Worker
79*9880d681SAndroid Build Coastguard Worker class MCJITObjectCacheTest : public testing::Test, public MCJITTestBase {
80*9880d681SAndroid Build Coastguard Worker protected:
81*9880d681SAndroid Build Coastguard Worker enum {
82*9880d681SAndroid Build Coastguard Worker OriginalRC = 6,
83*9880d681SAndroid Build Coastguard Worker ReplacementRC = 7
84*9880d681SAndroid Build Coastguard Worker };
85*9880d681SAndroid Build Coastguard Worker
SetUp()86*9880d681SAndroid Build Coastguard Worker void SetUp() override {
87*9880d681SAndroid Build Coastguard Worker M.reset(createEmptyModule("<main>"));
88*9880d681SAndroid Build Coastguard Worker Main = insertMainFunction(M.get(), OriginalRC);
89*9880d681SAndroid Build Coastguard Worker }
90*9880d681SAndroid Build Coastguard Worker
compileAndRun(int ExpectedRC=OriginalRC)91*9880d681SAndroid Build Coastguard Worker void compileAndRun(int ExpectedRC = OriginalRC) {
92*9880d681SAndroid Build Coastguard Worker // This function shouldn't be called until after SetUp.
93*9880d681SAndroid Build Coastguard Worker ASSERT_TRUE(bool(TheJIT));
94*9880d681SAndroid Build Coastguard Worker ASSERT_TRUE(nullptr != Main);
95*9880d681SAndroid Build Coastguard Worker
96*9880d681SAndroid Build Coastguard Worker // We may be using a null cache, so ensure compilation is valid.
97*9880d681SAndroid Build Coastguard Worker TheJIT->finalizeObject();
98*9880d681SAndroid Build Coastguard Worker void *vPtr = TheJIT->getPointerToFunction(Main);
99*9880d681SAndroid Build Coastguard Worker
100*9880d681SAndroid Build Coastguard Worker EXPECT_TRUE(nullptr != vPtr)
101*9880d681SAndroid Build Coastguard Worker << "Unable to get pointer to main() from JIT";
102*9880d681SAndroid Build Coastguard Worker
103*9880d681SAndroid Build Coastguard Worker int (*FuncPtr)() = (int(*)())(intptr_t)vPtr;
104*9880d681SAndroid Build Coastguard Worker int returnCode = FuncPtr();
105*9880d681SAndroid Build Coastguard Worker EXPECT_EQ(returnCode, ExpectedRC);
106*9880d681SAndroid Build Coastguard Worker }
107*9880d681SAndroid Build Coastguard Worker
108*9880d681SAndroid Build Coastguard Worker Function *Main;
109*9880d681SAndroid Build Coastguard Worker };
110*9880d681SAndroid Build Coastguard Worker
TEST_F(MCJITObjectCacheTest,SetNullObjectCache)111*9880d681SAndroid Build Coastguard Worker TEST_F(MCJITObjectCacheTest, SetNullObjectCache) {
112*9880d681SAndroid Build Coastguard Worker SKIP_UNSUPPORTED_PLATFORM;
113*9880d681SAndroid Build Coastguard Worker
114*9880d681SAndroid Build Coastguard Worker createJIT(std::move(M));
115*9880d681SAndroid Build Coastguard Worker
116*9880d681SAndroid Build Coastguard Worker TheJIT->setObjectCache(nullptr);
117*9880d681SAndroid Build Coastguard Worker
118*9880d681SAndroid Build Coastguard Worker compileAndRun();
119*9880d681SAndroid Build Coastguard Worker }
120*9880d681SAndroid Build Coastguard Worker
TEST_F(MCJITObjectCacheTest,VerifyBasicObjectCaching)121*9880d681SAndroid Build Coastguard Worker TEST_F(MCJITObjectCacheTest, VerifyBasicObjectCaching) {
122*9880d681SAndroid Build Coastguard Worker SKIP_UNSUPPORTED_PLATFORM;
123*9880d681SAndroid Build Coastguard Worker
124*9880d681SAndroid Build Coastguard Worker std::unique_ptr<TestObjectCache> Cache(new TestObjectCache);
125*9880d681SAndroid Build Coastguard Worker
126*9880d681SAndroid Build Coastguard Worker // Save a copy of the module pointer before handing it off to MCJIT.
127*9880d681SAndroid Build Coastguard Worker const Module * SavedModulePointer = M.get();
128*9880d681SAndroid Build Coastguard Worker
129*9880d681SAndroid Build Coastguard Worker createJIT(std::move(M));
130*9880d681SAndroid Build Coastguard Worker
131*9880d681SAndroid Build Coastguard Worker TheJIT->setObjectCache(Cache.get());
132*9880d681SAndroid Build Coastguard Worker
133*9880d681SAndroid Build Coastguard Worker // Verify that our object cache does not contain the module yet.
134*9880d681SAndroid Build Coastguard Worker const MemoryBuffer *ObjBuffer = Cache->getObjectInternal(SavedModulePointer);
135*9880d681SAndroid Build Coastguard Worker EXPECT_EQ(nullptr, ObjBuffer);
136*9880d681SAndroid Build Coastguard Worker
137*9880d681SAndroid Build Coastguard Worker compileAndRun();
138*9880d681SAndroid Build Coastguard Worker
139*9880d681SAndroid Build Coastguard Worker // Verify that MCJIT tried to look-up this module in the cache.
140*9880d681SAndroid Build Coastguard Worker EXPECT_TRUE(Cache->wasModuleLookedUp(SavedModulePointer));
141*9880d681SAndroid Build Coastguard Worker
142*9880d681SAndroid Build Coastguard Worker // Verify that our object cache now contains the module.
143*9880d681SAndroid Build Coastguard Worker ObjBuffer = Cache->getObjectInternal(SavedModulePointer);
144*9880d681SAndroid Build Coastguard Worker EXPECT_TRUE(nullptr != ObjBuffer);
145*9880d681SAndroid Build Coastguard Worker
146*9880d681SAndroid Build Coastguard Worker // Verify that the cache was only notified once.
147*9880d681SAndroid Build Coastguard Worker EXPECT_FALSE(Cache->wereDuplicatesInserted());
148*9880d681SAndroid Build Coastguard Worker }
149*9880d681SAndroid Build Coastguard Worker
TEST_F(MCJITObjectCacheTest,VerifyLoadFromCache)150*9880d681SAndroid Build Coastguard Worker TEST_F(MCJITObjectCacheTest, VerifyLoadFromCache) {
151*9880d681SAndroid Build Coastguard Worker SKIP_UNSUPPORTED_PLATFORM;
152*9880d681SAndroid Build Coastguard Worker
153*9880d681SAndroid Build Coastguard Worker std::unique_ptr<TestObjectCache> Cache(new TestObjectCache);
154*9880d681SAndroid Build Coastguard Worker
155*9880d681SAndroid Build Coastguard Worker // Compile this module with an MCJIT engine
156*9880d681SAndroid Build Coastguard Worker createJIT(std::move(M));
157*9880d681SAndroid Build Coastguard Worker TheJIT->setObjectCache(Cache.get());
158*9880d681SAndroid Build Coastguard Worker TheJIT->finalizeObject();
159*9880d681SAndroid Build Coastguard Worker
160*9880d681SAndroid Build Coastguard Worker // Destroy the MCJIT engine we just used
161*9880d681SAndroid Build Coastguard Worker TheJIT.reset();
162*9880d681SAndroid Build Coastguard Worker
163*9880d681SAndroid Build Coastguard Worker // Create a new memory manager.
164*9880d681SAndroid Build Coastguard Worker MM.reset(new SectionMemoryManager());
165*9880d681SAndroid Build Coastguard Worker
166*9880d681SAndroid Build Coastguard Worker // Create a new module and save it. Use a different return code so we can
167*9880d681SAndroid Build Coastguard Worker // tell if MCJIT compiled this module or used the cache.
168*9880d681SAndroid Build Coastguard Worker M.reset(createEmptyModule("<main>"));
169*9880d681SAndroid Build Coastguard Worker Main = insertMainFunction(M.get(), ReplacementRC);
170*9880d681SAndroid Build Coastguard Worker const Module * SecondModulePointer = M.get();
171*9880d681SAndroid Build Coastguard Worker
172*9880d681SAndroid Build Coastguard Worker // Create a new MCJIT instance to load this module then execute it.
173*9880d681SAndroid Build Coastguard Worker createJIT(std::move(M));
174*9880d681SAndroid Build Coastguard Worker TheJIT->setObjectCache(Cache.get());
175*9880d681SAndroid Build Coastguard Worker compileAndRun();
176*9880d681SAndroid Build Coastguard Worker
177*9880d681SAndroid Build Coastguard Worker // Verify that MCJIT tried to look-up this module in the cache.
178*9880d681SAndroid Build Coastguard Worker EXPECT_TRUE(Cache->wasModuleLookedUp(SecondModulePointer));
179*9880d681SAndroid Build Coastguard Worker
180*9880d681SAndroid Build Coastguard Worker // Verify that MCJIT didn't try to cache this again.
181*9880d681SAndroid Build Coastguard Worker EXPECT_FALSE(Cache->wereDuplicatesInserted());
182*9880d681SAndroid Build Coastguard Worker }
183*9880d681SAndroid Build Coastguard Worker
TEST_F(MCJITObjectCacheTest,VerifyNonLoadFromCache)184*9880d681SAndroid Build Coastguard Worker TEST_F(MCJITObjectCacheTest, VerifyNonLoadFromCache) {
185*9880d681SAndroid Build Coastguard Worker SKIP_UNSUPPORTED_PLATFORM;
186*9880d681SAndroid Build Coastguard Worker
187*9880d681SAndroid Build Coastguard Worker std::unique_ptr<TestObjectCache> Cache(new TestObjectCache);
188*9880d681SAndroid Build Coastguard Worker
189*9880d681SAndroid Build Coastguard Worker // Compile this module with an MCJIT engine
190*9880d681SAndroid Build Coastguard Worker createJIT(std::move(M));
191*9880d681SAndroid Build Coastguard Worker TheJIT->setObjectCache(Cache.get());
192*9880d681SAndroid Build Coastguard Worker TheJIT->finalizeObject();
193*9880d681SAndroid Build Coastguard Worker
194*9880d681SAndroid Build Coastguard Worker // Destroy the MCJIT engine we just used
195*9880d681SAndroid Build Coastguard Worker TheJIT.reset();
196*9880d681SAndroid Build Coastguard Worker
197*9880d681SAndroid Build Coastguard Worker // Create a new memory manager.
198*9880d681SAndroid Build Coastguard Worker MM.reset(new SectionMemoryManager());
199*9880d681SAndroid Build Coastguard Worker
200*9880d681SAndroid Build Coastguard Worker // Create a new module and save it. Use a different return code so we can
201*9880d681SAndroid Build Coastguard Worker // tell if MCJIT compiled this module or used the cache. Note that we use
202*9880d681SAndroid Build Coastguard Worker // a new module name here so the module shouldn't be found in the cache.
203*9880d681SAndroid Build Coastguard Worker M.reset(createEmptyModule("<not-main>"));
204*9880d681SAndroid Build Coastguard Worker Main = insertMainFunction(M.get(), ReplacementRC);
205*9880d681SAndroid Build Coastguard Worker const Module * SecondModulePointer = M.get();
206*9880d681SAndroid Build Coastguard Worker
207*9880d681SAndroid Build Coastguard Worker // Create a new MCJIT instance to load this module then execute it.
208*9880d681SAndroid Build Coastguard Worker createJIT(std::move(M));
209*9880d681SAndroid Build Coastguard Worker TheJIT->setObjectCache(Cache.get());
210*9880d681SAndroid Build Coastguard Worker
211*9880d681SAndroid Build Coastguard Worker // Verify that our object cache does not contain the module yet.
212*9880d681SAndroid Build Coastguard Worker const MemoryBuffer *ObjBuffer = Cache->getObjectInternal(SecondModulePointer);
213*9880d681SAndroid Build Coastguard Worker EXPECT_EQ(nullptr, ObjBuffer);
214*9880d681SAndroid Build Coastguard Worker
215*9880d681SAndroid Build Coastguard Worker // Run the function and look for the replacement return code.
216*9880d681SAndroid Build Coastguard Worker compileAndRun(ReplacementRC);
217*9880d681SAndroid Build Coastguard Worker
218*9880d681SAndroid Build Coastguard Worker // Verify that MCJIT tried to look-up this module in the cache.
219*9880d681SAndroid Build Coastguard Worker EXPECT_TRUE(Cache->wasModuleLookedUp(SecondModulePointer));
220*9880d681SAndroid Build Coastguard Worker
221*9880d681SAndroid Build Coastguard Worker // Verify that our object cache now contains the module.
222*9880d681SAndroid Build Coastguard Worker ObjBuffer = Cache->getObjectInternal(SecondModulePointer);
223*9880d681SAndroid Build Coastguard Worker EXPECT_TRUE(nullptr != ObjBuffer);
224*9880d681SAndroid Build Coastguard Worker
225*9880d681SAndroid Build Coastguard Worker // Verify that MCJIT didn't try to cache this again.
226*9880d681SAndroid Build Coastguard Worker EXPECT_FALSE(Cache->wereDuplicatesInserted());
227*9880d681SAndroid Build Coastguard Worker }
228*9880d681SAndroid Build Coastguard Worker
229*9880d681SAndroid Build Coastguard Worker } // end anonymous namespace
230