blob: b0c2f24f0800bf74cc00c2513d70eb344e09c3c6 [file] [log] [blame]
Reid Kleckner4b1511b2009-07-18 00:42:18 +00001//===- JITTest.cpp - Unit tests for the JIT -------------------------------===//
Jeffrey Yasskin489393d2009-07-08 21:59:57 +00002//
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
10#include "gtest/gtest.h"
11#include "llvm/ADT/OwningPtr.h"
Jeffrey Yasskin7a9034c2009-10-27 00:03:05 +000012#include "llvm/ADT/SmallPtrSet.h"
Jeffrey Yasskin23e5fcf2009-10-23 22:37:43 +000013#include "llvm/Assembly/Parser.h"
Jeffrey Yasskin489393d2009-07-08 21:59:57 +000014#include "llvm/BasicBlock.h"
15#include "llvm/Constant.h"
16#include "llvm/Constants.h"
17#include "llvm/DerivedTypes.h"
18#include "llvm/ExecutionEngine/JIT.h"
19#include "llvm/ExecutionEngine/JITMemoryManager.h"
20#include "llvm/Function.h"
21#include "llvm/GlobalValue.h"
22#include "llvm/GlobalVariable.h"
Reid Kleckner4b1511b2009-07-18 00:42:18 +000023#include "llvm/LLVMContext.h"
Jeffrey Yasskin489393d2009-07-08 21:59:57 +000024#include "llvm/Module.h"
25#include "llvm/ModuleProvider.h"
26#include "llvm/Support/IRBuilder.h"
Jeffrey Yasskin23e5fcf2009-10-23 22:37:43 +000027#include "llvm/Support/SourceMgr.h"
Jeffrey Yasskinea5ed002009-10-06 00:35:55 +000028#include "llvm/Support/TypeBuilder.h"
Jeffrey Yasskind1ba06b2009-11-16 22:41:33 +000029#include "llvm/Target/TargetMachine.h"
Jeffrey Yasskin489393d2009-07-08 21:59:57 +000030#include "llvm/Target/TargetSelect.h"
31#include "llvm/Type.h"
32
Jeffrey Yasskin7a9034c2009-10-27 00:03:05 +000033#include <vector>
Jeffrey Yasskind1ba06b2009-11-16 22:41:33 +000034#include <string.h>
35
36#if HAVE_ERRNO_H
37#include <errno.h>
38#endif
39#if HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42#if _POSIX_MAPPED_FILES > 0
43#include <sys/mman.h>
44#endif
Jeffrey Yasskin7a9034c2009-10-27 00:03:05 +000045
Jeffrey Yasskin489393d2009-07-08 21:59:57 +000046using namespace llvm;
47
48namespace {
49
50Function *makeReturnGlobal(std::string Name, GlobalVariable *G, Module *M) {
51 std::vector<const Type*> params;
Owen Andersondebcb012009-07-29 22:17:13 +000052 const FunctionType *FTy = FunctionType::get(G->getType()->getElementType(),
Dan Gohmanc6f40b62009-07-11 13:56:14 +000053 params, false);
Jeffrey Yasskin489393d2009-07-08 21:59:57 +000054 Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage, Name, M);
Owen Anderson1d0be152009-08-13 21:58:54 +000055 BasicBlock *Entry = BasicBlock::Create(M->getContext(), "entry", F);
Jeffrey Yasskin489393d2009-07-08 21:59:57 +000056 IRBuilder<> builder(Entry);
57 Value *Load = builder.CreateLoad(G);
58 const Type *GTy = G->getType()->getElementType();
Owen Andersoneed707b2009-07-24 23:12:02 +000059 Value *Add = builder.CreateAdd(Load, ConstantInt::get(GTy, 1LL));
Jeffrey Yasskin489393d2009-07-08 21:59:57 +000060 builder.CreateStore(Add, G);
61 builder.CreateRet(Add);
62 return F;
63}
64
Jeffrey Yasskin7a9034c2009-10-27 00:03:05 +000065std::string DumpFunction(const Function *F) {
66 std::string Result;
67 raw_string_ostream(Result) << "" << *F;
68 return Result;
69}
70
71class RecordingJITMemoryManager : public JITMemoryManager {
72 const OwningPtr<JITMemoryManager> Base;
73public:
74 RecordingJITMemoryManager()
75 : Base(JITMemoryManager::CreateDefaultMemManager()) {
Eric Christopher116664a2009-11-12 03:12:18 +000076 stubsAllocated = 0;
Jeffrey Yasskin7a9034c2009-10-27 00:03:05 +000077 }
78
79 virtual void setMemoryWritable() { Base->setMemoryWritable(); }
80 virtual void setMemoryExecutable() { Base->setMemoryExecutable(); }
81 virtual void setPoisonMemory(bool poison) { Base->setPoisonMemory(poison); }
82 virtual void AllocateGOT() { Base->AllocateGOT(); }
83 virtual uint8_t *getGOTBase() const { return Base->getGOTBase(); }
Jeffrey Yasskin7a9034c2009-10-27 00:03:05 +000084 struct StartFunctionBodyCall {
85 StartFunctionBodyCall(uint8_t *Result, const Function *F,
86 uintptr_t ActualSize, uintptr_t ActualSizeResult)
87 : Result(Result), F(F), F_dump(DumpFunction(F)),
88 ActualSize(ActualSize), ActualSizeResult(ActualSizeResult) {}
89 uint8_t *Result;
90 const Function *F;
91 std::string F_dump;
92 uintptr_t ActualSize;
93 uintptr_t ActualSizeResult;
94 };
95 std::vector<StartFunctionBodyCall> startFunctionBodyCalls;
96 virtual uint8_t *startFunctionBody(const Function *F,
97 uintptr_t &ActualSize) {
98 uintptr_t InitialActualSize = ActualSize;
99 uint8_t *Result = Base->startFunctionBody(F, ActualSize);
100 startFunctionBodyCalls.push_back(
101 StartFunctionBodyCall(Result, F, InitialActualSize, ActualSize));
102 return Result;
103 }
Eric Christopher116664a2009-11-12 03:12:18 +0000104 int stubsAllocated;
Jeffrey Yasskin7a9034c2009-10-27 00:03:05 +0000105 virtual uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,
106 unsigned Alignment) {
Eric Christopher116664a2009-11-12 03:12:18 +0000107 stubsAllocated++;
Jeffrey Yasskin7a9034c2009-10-27 00:03:05 +0000108 return Base->allocateStub(F, StubSize, Alignment);
109 }
110 struct EndFunctionBodyCall {
111 EndFunctionBodyCall(const Function *F, uint8_t *FunctionStart,
112 uint8_t *FunctionEnd)
113 : F(F), F_dump(DumpFunction(F)),
114 FunctionStart(FunctionStart), FunctionEnd(FunctionEnd) {}
115 const Function *F;
116 std::string F_dump;
117 uint8_t *FunctionStart;
118 uint8_t *FunctionEnd;
119 };
120 std::vector<EndFunctionBodyCall> endFunctionBodyCalls;
121 virtual void endFunctionBody(const Function *F, uint8_t *FunctionStart,
122 uint8_t *FunctionEnd) {
123 endFunctionBodyCalls.push_back(
124 EndFunctionBodyCall(F, FunctionStart, FunctionEnd));
125 Base->endFunctionBody(F, FunctionStart, FunctionEnd);
126 }
127 virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) {
128 return Base->allocateSpace(Size, Alignment);
129 }
130 virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) {
131 return Base->allocateGlobal(Size, Alignment);
132 }
133 struct DeallocateFunctionBodyCall {
134 DeallocateFunctionBodyCall(const void *Body) : Body(Body) {}
135 const void *Body;
136 };
137 std::vector<DeallocateFunctionBodyCall> deallocateFunctionBodyCalls;
138 virtual void deallocateFunctionBody(void *Body) {
139 deallocateFunctionBodyCalls.push_back(DeallocateFunctionBodyCall(Body));
140 Base->deallocateFunctionBody(Body);
141 }
142 struct DeallocateExceptionTableCall {
143 DeallocateExceptionTableCall(const void *ET) : ET(ET) {}
144 const void *ET;
145 };
146 std::vector<DeallocateExceptionTableCall> deallocateExceptionTableCalls;
147 virtual void deallocateExceptionTable(void *ET) {
148 deallocateExceptionTableCalls.push_back(DeallocateExceptionTableCall(ET));
149 Base->deallocateExceptionTable(ET);
150 }
151 struct StartExceptionTableCall {
152 StartExceptionTableCall(uint8_t *Result, const Function *F,
153 uintptr_t ActualSize, uintptr_t ActualSizeResult)
154 : Result(Result), F(F), F_dump(DumpFunction(F)),
155 ActualSize(ActualSize), ActualSizeResult(ActualSizeResult) {}
156 uint8_t *Result;
157 const Function *F;
158 std::string F_dump;
159 uintptr_t ActualSize;
160 uintptr_t ActualSizeResult;
161 };
162 std::vector<StartExceptionTableCall> startExceptionTableCalls;
163 virtual uint8_t* startExceptionTable(const Function* F,
164 uintptr_t &ActualSize) {
165 uintptr_t InitialActualSize = ActualSize;
166 uint8_t *Result = Base->startExceptionTable(F, ActualSize);
167 startExceptionTableCalls.push_back(
168 StartExceptionTableCall(Result, F, InitialActualSize, ActualSize));
169 return Result;
170 }
171 struct EndExceptionTableCall {
172 EndExceptionTableCall(const Function *F, uint8_t *TableStart,
173 uint8_t *TableEnd, uint8_t* FrameRegister)
174 : F(F), F_dump(DumpFunction(F)),
175 TableStart(TableStart), TableEnd(TableEnd),
176 FrameRegister(FrameRegister) {}
177 const Function *F;
178 std::string F_dump;
179 uint8_t *TableStart;
180 uint8_t *TableEnd;
181 uint8_t *FrameRegister;
182 };
183 std::vector<EndExceptionTableCall> endExceptionTableCalls;
184 virtual void endExceptionTable(const Function *F, uint8_t *TableStart,
185 uint8_t *TableEnd, uint8_t* FrameRegister) {
186 endExceptionTableCalls.push_back(
187 EndExceptionTableCall(F, TableStart, TableEnd, FrameRegister));
188 return Base->endExceptionTable(F, TableStart, TableEnd, FrameRegister);
189 }
190};
191
Jeffrey Yasskind1ba06b2009-11-16 22:41:33 +0000192void LoadAssemblyInto(Module *M, const char *assembly) {
193 SMDiagnostic Error;
194 bool success = NULL != ParseAssemblyString(assembly, M, Error, M->getContext());
195 std::string errMsg;
196 raw_string_ostream os(errMsg);
197 Error.Print("", os);
198 ASSERT_TRUE(success) << os.str();
199}
200
Jeffrey Yasskinea5ed002009-10-06 00:35:55 +0000201class JITTest : public testing::Test {
202 protected:
203 virtual void SetUp() {
204 M = new Module("<main>", Context);
Jeffrey Yasskin23e5fcf2009-10-23 22:37:43 +0000205 MP = new ExistingModuleProvider(M);
Jeffrey Yasskin7a9034c2009-10-27 00:03:05 +0000206 RJMM = new RecordingJITMemoryManager;
Jeffrey Yasskinea5ed002009-10-06 00:35:55 +0000207 std::string Error;
Jeffrey Yasskin23e5fcf2009-10-23 22:37:43 +0000208 TheJIT.reset(EngineBuilder(MP).setEngineKind(EngineKind::JIT)
Jeffrey Yasskin7a9034c2009-10-27 00:03:05 +0000209 .setJITMemoryManager(RJMM)
Jeffrey Yasskinea5ed002009-10-06 00:35:55 +0000210 .setErrorStr(&Error).create());
211 ASSERT_TRUE(TheJIT.get() != NULL) << Error;
212 }
213
Jeffrey Yasskin23e5fcf2009-10-23 22:37:43 +0000214 void LoadAssembly(const char *assembly) {
Jeffrey Yasskind1ba06b2009-11-16 22:41:33 +0000215 LoadAssemblyInto(M, assembly);
Jeffrey Yasskin23e5fcf2009-10-23 22:37:43 +0000216 }
217
Jeffrey Yasskinea5ed002009-10-06 00:35:55 +0000218 LLVMContext Context;
Jeffrey Yasskin23e5fcf2009-10-23 22:37:43 +0000219 Module *M; // Owned by MP.
220 ModuleProvider *MP; // Owned by ExecutionEngine.
Jeffrey Yasskin7a9034c2009-10-27 00:03:05 +0000221 RecordingJITMemoryManager *RJMM;
Jeffrey Yasskinea5ed002009-10-06 00:35:55 +0000222 OwningPtr<ExecutionEngine> TheJIT;
223};
224
Jeffrey Yasskin489393d2009-07-08 21:59:57 +0000225// Regression test for a bug. The JIT used to allocate globals inside the same
226// memory block used for the function, and when the function code was freed,
227// the global was left in the same place. This test allocates a function
228// that uses and global, deallocates it, and then makes sure that the global
229// stays alive after that.
230TEST(JIT, GlobalInFunction) {
231 LLVMContext context;
232 Module *M = new Module("<main>", context);
233 ExistingModuleProvider *MP = new ExistingModuleProvider(M);
234
235 JITMemoryManager *MemMgr = JITMemoryManager::CreateDefaultMemManager();
236 // Tell the memory manager to poison freed memory so that accessing freed
237 // memory is more easily tested.
238 MemMgr->setPoisonMemory(true);
239 std::string Error;
Reid Kleckner4b1511b2009-07-18 00:42:18 +0000240 OwningPtr<ExecutionEngine> JIT(EngineBuilder(MP)
Daniel Dunbard370d772009-07-18 06:08:49 +0000241 .setEngineKind(EngineKind::JIT)
Reid Kleckner4b1511b2009-07-18 00:42:18 +0000242 .setErrorStr(&Error)
243 .setJITMemoryManager(MemMgr)
244 // The next line enables the fix:
245 .setAllocateGVsWithCode(false)
246 .create());
Jeffrey Yasskin489393d2009-07-08 21:59:57 +0000247 ASSERT_EQ(Error, "");
248
249 // Create a global variable.
Owen Anderson1d0be152009-08-13 21:58:54 +0000250 const Type *GTy = Type::getInt32Ty(context);
Jeffrey Yasskin489393d2009-07-08 21:59:57 +0000251 GlobalVariable *G = new GlobalVariable(
252 *M,
253 GTy,
254 false, // Not constant.
255 GlobalValue::InternalLinkage,
Benjamin Kramerfeba7562009-07-31 20:56:31 +0000256 Constant::getNullValue(GTy),
Jeffrey Yasskin489393d2009-07-08 21:59:57 +0000257 "myglobal");
258
259 // Make a function that points to a global.
260 Function *F1 = makeReturnGlobal("F1", G, M);
261
262 // Get the pointer to the native code to force it to JIT the function and
263 // allocate space for the global.
Jeffrey Yasskin0f2ba782009-10-06 19:06:16 +0000264 void (*F1Ptr)() =
265 reinterpret_cast<void(*)()>((intptr_t)JIT->getPointerToFunction(F1));
Jeffrey Yasskin489393d2009-07-08 21:59:57 +0000266
267 // Since F1 was codegen'd, a pointer to G should be available.
268 int32_t *GPtr = (int32_t*)JIT->getPointerToGlobalIfAvailable(G);
269 ASSERT_NE((int32_t*)NULL, GPtr);
270 EXPECT_EQ(0, *GPtr);
271
272 // F1() should increment G.
273 F1Ptr();
274 EXPECT_EQ(1, *GPtr);
275
276 // Make a second function identical to the first, referring to the same
277 // global.
278 Function *F2 = makeReturnGlobal("F2", G, M);
Jeffrey Yasskin0f2ba782009-10-06 19:06:16 +0000279 void (*F2Ptr)() =
280 reinterpret_cast<void(*)()>((intptr_t)JIT->getPointerToFunction(F2));
Jeffrey Yasskin489393d2009-07-08 21:59:57 +0000281
282 // F2() should increment G.
283 F2Ptr();
284 EXPECT_EQ(2, *GPtr);
285
286 // Deallocate F1.
287 JIT->freeMachineCodeForFunction(F1);
288
289 // F2() should *still* increment G.
290 F2Ptr();
291 EXPECT_EQ(3, *GPtr);
292}
293
Jeffrey Yasskinea5ed002009-10-06 00:35:55 +0000294int PlusOne(int arg) {
295 return arg + 1;
296}
297
298TEST_F(JITTest, FarCallToKnownFunction) {
299 // x86-64 can only make direct calls to functions within 32 bits of
300 // the current PC. To call anything farther away, we have to load
301 // the address into a register and call through the register. The
302 // current JIT does this by allocating a stub for any far call.
303 // There was a bug in which the JIT tried to emit a direct call when
304 // the target was already in the JIT's global mappings and lazy
305 // compilation was disabled.
306
307 Function *KnownFunction = Function::Create(
308 TypeBuilder<int(int), false>::get(Context),
309 GlobalValue::ExternalLinkage, "known", M);
310 TheJIT->addGlobalMapping(KnownFunction, (void*)(intptr_t)PlusOne);
311
312 // int test() { return known(7); }
313 Function *TestFunction = Function::Create(
314 TypeBuilder<int(), false>::get(Context),
315 GlobalValue::ExternalLinkage, "test", M);
316 BasicBlock *Entry = BasicBlock::Create(Context, "entry", TestFunction);
317 IRBuilder<> Builder(Entry);
318 Value *result = Builder.CreateCall(
319 KnownFunction,
320 ConstantInt::get(TypeBuilder<int, false>::get(Context), 7));
321 Builder.CreateRet(result);
322
Jeffrey Yasskin18fec732009-10-27 22:39:42 +0000323 TheJIT->DisableLazyCompilation(true);
Jeffrey Yasskinea5ed002009-10-06 00:35:55 +0000324 int (*TestFunctionPtr)() = reinterpret_cast<int(*)()>(
325 (intptr_t)TheJIT->getPointerToFunction(TestFunction));
326 // This used to crash in trying to call PlusOne().
327 EXPECT_EQ(8, TestFunctionPtr());
328}
329
Daniel Dunbarb576bea2009-10-20 05:33:23 +0000330#if !defined(__arm__) && !defined(__powerpc__) && !defined(__ppc__)
Jeffrey Yasskine5f87982009-10-13 21:32:57 +0000331// Test a function C which calls A and B which call each other.
332TEST_F(JITTest, NonLazyCompilationStillNeedsStubs) {
Jeffrey Yasskin18fec732009-10-27 22:39:42 +0000333 TheJIT->DisableLazyCompilation(true);
Jeffrey Yasskine5f87982009-10-13 21:32:57 +0000334
335 const FunctionType *Func1Ty =
336 cast<FunctionType>(TypeBuilder<void(void), false>::get(Context));
337 std::vector<const Type*> arg_types;
338 arg_types.push_back(Type::getInt1Ty(Context));
339 const FunctionType *FuncTy = FunctionType::get(
340 Type::getVoidTy(Context), arg_types, false);
341 Function *Func1 = Function::Create(Func1Ty, Function::ExternalLinkage,
342 "func1", M);
343 Function *Func2 = Function::Create(FuncTy, Function::InternalLinkage,
344 "func2", M);
345 Function *Func3 = Function::Create(FuncTy, Function::InternalLinkage,
346 "func3", M);
347 BasicBlock *Block1 = BasicBlock::Create(Context, "block1", Func1);
348 BasicBlock *Block2 = BasicBlock::Create(Context, "block2", Func2);
349 BasicBlock *True2 = BasicBlock::Create(Context, "cond_true", Func2);
350 BasicBlock *False2 = BasicBlock::Create(Context, "cond_false", Func2);
351 BasicBlock *Block3 = BasicBlock::Create(Context, "block3", Func3);
352 BasicBlock *True3 = BasicBlock::Create(Context, "cond_true", Func3);
353 BasicBlock *False3 = BasicBlock::Create(Context, "cond_false", Func3);
354
355 // Make Func1 call Func2(0) and Func3(0).
356 IRBuilder<> Builder(Block1);
357 Builder.CreateCall(Func2, ConstantInt::getTrue(Context));
358 Builder.CreateCall(Func3, ConstantInt::getTrue(Context));
359 Builder.CreateRetVoid();
360
361 // void Func2(bool b) { if (b) { Func3(false); return; } return; }
362 Builder.SetInsertPoint(Block2);
363 Builder.CreateCondBr(Func2->arg_begin(), True2, False2);
364 Builder.SetInsertPoint(True2);
365 Builder.CreateCall(Func3, ConstantInt::getFalse(Context));
366 Builder.CreateRetVoid();
367 Builder.SetInsertPoint(False2);
368 Builder.CreateRetVoid();
369
370 // void Func3(bool b) { if (b) { Func2(false); return; } return; }
371 Builder.SetInsertPoint(Block3);
372 Builder.CreateCondBr(Func3->arg_begin(), True3, False3);
373 Builder.SetInsertPoint(True3);
374 Builder.CreateCall(Func2, ConstantInt::getFalse(Context));
375 Builder.CreateRetVoid();
376 Builder.SetInsertPoint(False3);
377 Builder.CreateRetVoid();
378
379 // Compile the function to native code
380 void (*F1Ptr)() =
381 reinterpret_cast<void(*)()>((intptr_t)TheJIT->getPointerToFunction(Func1));
382
383 F1Ptr();
384}
385
386// Regression test for PR5162. This used to trigger an AssertingVH inside the
387// JIT's Function to stub mapping.
388TEST_F(JITTest, NonLazyLeaksNoStubs) {
Jeffrey Yasskin18fec732009-10-27 22:39:42 +0000389 TheJIT->DisableLazyCompilation(true);
Jeffrey Yasskine5f87982009-10-13 21:32:57 +0000390
391 // Create two functions with a single basic block each.
392 const FunctionType *FuncTy =
393 cast<FunctionType>(TypeBuilder<int(), false>::get(Context));
394 Function *Func1 = Function::Create(FuncTy, Function::ExternalLinkage,
395 "func1", M);
396 Function *Func2 = Function::Create(FuncTy, Function::InternalLinkage,
397 "func2", M);
398 BasicBlock *Block1 = BasicBlock::Create(Context, "block1", Func1);
399 BasicBlock *Block2 = BasicBlock::Create(Context, "block2", Func2);
400
401 // The first function calls the second and returns the result
402 IRBuilder<> Builder(Block1);
403 Value *Result = Builder.CreateCall(Func2);
404 Builder.CreateRet(Result);
405
406 // The second function just returns a constant
407 Builder.SetInsertPoint(Block2);
408 Builder.CreateRet(ConstantInt::get(TypeBuilder<int, false>::get(Context),42));
409
410 // Compile the function to native code
411 (void)TheJIT->getPointerToFunction(Func1);
412
413 // Free the JIT state for the functions
414 TheJIT->freeMachineCodeForFunction(Func1);
415 TheJIT->freeMachineCodeForFunction(Func2);
416
417 // Delete the first function (and show that is has no users)
418 EXPECT_EQ(Func1->getNumUses(), 0u);
419 Func1->eraseFromParent();
420
421 // Delete the second function (and show that it has no users - it had one,
422 // func1 but that's gone now)
423 EXPECT_EQ(Func2->getNumUses(), 0u);
424 Func2->eraseFromParent();
425}
Benjamin Kramer06b386a2009-10-15 16:49:16 +0000426#endif
Jeffrey Yasskine5f87982009-10-13 21:32:57 +0000427
Jeffrey Yasskin23e5fcf2009-10-23 22:37:43 +0000428TEST_F(JITTest, ModuleDeletion) {
Jeffrey Yasskinb2352242009-10-28 00:28:31 +0000429 TheJIT->DisableLazyCompilation(false);
Jeffrey Yasskin23e5fcf2009-10-23 22:37:43 +0000430 LoadAssembly("define void @main() { "
431 " call i32 @computeVal() "
432 " ret void "
433 "} "
434 " "
435 "define internal i32 @computeVal() { "
436 " ret i32 0 "
437 "} ");
438 Function *func = M->getFunction("main");
439 TheJIT->getPointerToFunction(func);
440 TheJIT->deleteModuleProvider(MP);
Jeffrey Yasskin7a9034c2009-10-27 00:03:05 +0000441
442 SmallPtrSet<const void*, 2> FunctionsDeallocated;
443 for (unsigned i = 0, e = RJMM->deallocateFunctionBodyCalls.size();
444 i != e; ++i) {
445 FunctionsDeallocated.insert(RJMM->deallocateFunctionBodyCalls[i].Body);
446 }
447 for (unsigned i = 0, e = RJMM->startFunctionBodyCalls.size(); i != e; ++i) {
448 EXPECT_TRUE(FunctionsDeallocated.count(
449 RJMM->startFunctionBodyCalls[i].Result))
450 << "Function leaked: \n" << RJMM->startFunctionBodyCalls[i].F_dump;
451 }
452 EXPECT_EQ(RJMM->startFunctionBodyCalls.size(),
453 RJMM->deallocateFunctionBodyCalls.size());
454
455 SmallPtrSet<const void*, 2> ExceptionTablesDeallocated;
Jeffrey Yasskinb069c912009-11-11 05:30:02 +0000456 unsigned NumTablesDeallocated = 0;
Jeffrey Yasskin7a9034c2009-10-27 00:03:05 +0000457 for (unsigned i = 0, e = RJMM->deallocateExceptionTableCalls.size();
458 i != e; ++i) {
459 ExceptionTablesDeallocated.insert(
460 RJMM->deallocateExceptionTableCalls[i].ET);
Jeffrey Yasskinb069c912009-11-11 05:30:02 +0000461 if (RJMM->deallocateExceptionTableCalls[i].ET != NULL) {
462 // If JITEmitDebugInfo is off, we'll "deallocate" NULL, which doesn't
463 // appear in startExceptionTableCalls.
464 NumTablesDeallocated++;
465 }
Jeffrey Yasskin7a9034c2009-10-27 00:03:05 +0000466 }
467 for (unsigned i = 0, e = RJMM->startExceptionTableCalls.size(); i != e; ++i) {
468 EXPECT_TRUE(ExceptionTablesDeallocated.count(
469 RJMM->startExceptionTableCalls[i].Result))
470 << "Function's exception table leaked: \n"
471 << RJMM->startExceptionTableCalls[i].F_dump;
472 }
473 EXPECT_EQ(RJMM->startExceptionTableCalls.size(),
Jeffrey Yasskinb069c912009-11-11 05:30:02 +0000474 NumTablesDeallocated);
Jeffrey Yasskin23e5fcf2009-10-23 22:37:43 +0000475}
476
Benjamin Kramer74c10e72009-11-14 15:15:39 +0000477#if !defined(__arm__) && !defined(__powerpc__) && !defined(__ppc__)
Eric Christopher116664a2009-11-12 03:12:18 +0000478typedef int (*FooPtr) ();
479
480TEST_F(JITTest, NoStubs) {
481 LoadAssembly("define void @bar() {"
482 "entry: "
483 "ret void"
484 "}"
485 " "
486 "define i32 @foo() {"
487 "entry:"
488 "call void @bar()"
489 "ret i32 undef"
490 "}"
491 " "
492 "define i32 @main() {"
493 "entry:"
494 "%0 = call i32 @foo()"
495 "call void @bar()"
496 "ret i32 undef"
497 "}");
498 Function *foo = M->getFunction("foo");
499 uintptr_t tmp = (uintptr_t)(TheJIT->getPointerToFunction(foo));
500 FooPtr ptr = (FooPtr)(tmp);
501
502 (ptr)();
503
504 // We should now allocate no more stubs, we have the code to foo
505 // and the existing stub for bar.
506 int stubsBefore = RJMM->stubsAllocated;
507 Function *func = M->getFunction("main");
508 TheJIT->getPointerToFunction(func);
509
510 Function *bar = M->getFunction("bar");
511 TheJIT->getPointerToFunction(bar);
512
513 ASSERT_EQ(stubsBefore, RJMM->stubsAllocated);
514}
Bill Wendling0c2749f2009-11-13 21:58:54 +0000515#endif
Eric Christopher116664a2009-11-12 03:12:18 +0000516
Jeffrey Yasskind1ba06b2009-11-16 22:41:33 +0000517#if _POSIX_MAPPED_FILES > 0 && (defined (__x86_64__) || defined (_M_AMD64) || defined (_M_X64))
518class FarCallMemMgr : public RecordingJITMemoryManager {
519 void *MmapRegion;
520 size_t MmapSize;
521 uint8_t *NextStub;
522 uint8_t *NextFunction;
523
524 public:
525 FarCallMemMgr()
526 : MmapSize(16ULL << 30) { // 16GB
527 MmapRegion = mmap(NULL, MmapSize, PROT_READ | PROT_WRITE | PROT_EXEC,
528 MAP_PRIVATE | MAP_ANON, -1, 0);
529 if (MmapRegion == MAP_FAILED) {
530 ADD_FAILURE() << "mmap failed: " << strerror(errno);
531 }
532 // Set up the 16GB mapped region in several chunks:
533 // Stubs / ~5GB empty space / Function 1 / ~5GB empty space / Function 2
534 // This way no two entities can use a 32-bit relative call to reach each other.
535 NextStub = static_cast<uint8_t*>(MmapRegion);
536 NextFunction = NextStub + (5ULL << 30);
537
538 // Next, poison some of the memory so a wild call will eventually crash,
539 // even if memory was initialized by the OS to 0. We can't poison all of
540 // the memory because we want to be able to run on systems with less than
541 // 16GB of physical ram.
542 int TrapInstr = 0xCC; // INT 3
543 memset(NextStub, TrapInstr, 1<<10);
544 for (size_t Offset = 1<<30; Offset < MmapSize; Offset += 1<<30) {
545 // Fill the 2KB around each GB boundary with trap instructions. This
546 // should ensure that we can't run into emitted functions without hitting
547 // the trap.
548 memset(NextStub + Offset - (1<<10), TrapInstr, 2<<10);
549 }
550 }
551
552 ~FarCallMemMgr() {
553 EXPECT_EQ(0, munmap(MmapRegion, MmapSize));
554 }
555
556 virtual void setMemoryWritable() {}
557 virtual void setMemoryExecutable() {}
558 virtual uint8_t *startFunctionBody(const Function *F,
559 uintptr_t &ActualSize) {
560 ActualSize = 1 << 30;
561 uint8_t *Result = NextFunction;
562 NextFunction += 5ULL << 30;
563 return Result;
564 }
565 virtual void endFunctionBody(const Function*, uint8_t*, uint8_t*) {}
566 virtual uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,
567 unsigned Alignment) {
568 NextStub = reinterpret_cast<uint8_t*>(
569 uintptr_t(NextStub + Alignment - 1) &~ uintptr_t(Alignment - 1));
570 uint8_t *Result = NextStub;
571 NextStub += StubSize;
572 return Result;
573 }
574};
575
576class FarTargetTest : public ::testing::TestWithParam<CodeGenOpt::Level> {
577 protected:
578 FarTargetTest() : SavedCodeModel(TargetMachine::getCodeModel()) {}
579 ~FarTargetTest() {
580 TargetMachine::setCodeModel(SavedCodeModel);
581 }
582
583 const CodeModel::Model SavedCodeModel;
584};
585INSTANTIATE_TEST_CASE_P(CodeGenOpt,
586 FarTargetTest,
587 ::testing::Values(CodeGenOpt::None,
588 CodeGenOpt::Default));
589
590TEST_P(FarTargetTest, CallToFarTarget) {
591 // x86-64 can only make direct calls to functions within 32 bits of
592 // the current PC. To call anything farther away, we have to load
593 // the address into a register and call through the register. The
594 // old JIT did this by allocating a stub for any far call. However,
595 // that stub needed to be within 32 bits of the callsite. Here we
596 // test that the JIT correctly deals with stubs and calls more than
597 // 32 bits away from the callsite.
598
599 // Make sure the code generator is assuming code might be far away.
600 //TargetMachine::setCodeModel(CodeModel::Large);
601
602 LLVMContext Context;
603 Module *M = new Module("<main>", Context);
604 ExistingModuleProvider *MP = new ExistingModuleProvider(M);
605
606 JITMemoryManager *MemMgr = new FarCallMemMgr();
607 std::string Error;
608 OwningPtr<ExecutionEngine> JIT(EngineBuilder(MP)
609 .setEngineKind(EngineKind::JIT)
610 .setErrorStr(&Error)
611 .setJITMemoryManager(MemMgr)
612 .setOptLevel(GetParam())
613 .create());
614 ASSERT_EQ(Error, "");
615 TargetMachine::setCodeModel(CodeModel::Large);
616
617 LoadAssemblyInto(M,
618 "define i32 @test() { "
619 " ret i32 7 "
620 "} "
621 " "
622 "define i32 @test_far() { "
623 " %result = call i32 @test() "
624 " ret i32 %result "
625 "} ");
626 // First, lay out a function early in memory.
627 Function *TestFunction = M->getFunction("test");
628 int32_t (*TestFunctionPtr)() = reinterpret_cast<int32_t(*)()>(
629 (intptr_t)JIT->getPointerToFunction(TestFunction));
630 ASSERT_EQ(7, TestFunctionPtr());
631
632 // We now lay out the far-away function. This should land >4GB away from test().
633 Function *FarFunction = M->getFunction("test_far");
634 int32_t (*FarFunctionPtr)() = reinterpret_cast<int32_t(*)()>(
635 (intptr_t)JIT->getPointerToFunction(FarFunction));
636
637 EXPECT_LT(1LL << 32, llabs(intptr_t(FarFunctionPtr) - intptr_t(TestFunctionPtr)))
638 << "Functions must be >32 bits apart or the test is meaningless.";
639
640 // This used to result in a segfault in FarFunction, when its call instruction
641 // jumped to the wrong address.
642 EXPECT_EQ(7, FarFunctionPtr());
643}
644#endif // Platform has far-call problem.
645
Reid Kleckner4b1511b2009-07-18 00:42:18 +0000646// This code is copied from JITEventListenerTest, but it only runs once for all
647// the tests in this directory. Everything seems fine, but that's strange
648// behavior.
Jeffrey Yasskin489393d2009-07-08 21:59:57 +0000649class JITEnvironment : public testing::Environment {
650 virtual void SetUp() {
Reid Kleckner4b1511b2009-07-18 00:42:18 +0000651 // Required to create a JIT.
Jeffrey Yasskin489393d2009-07-08 21:59:57 +0000652 InitializeNativeTarget();
653 }
654};
655testing::Environment* const jit_env =
656 testing::AddGlobalTestEnvironment(new JITEnvironment);
657
658}