1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-01 16:33:37 +01:00
llvm-mirror/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp
Jeffrey Yasskin c5bf1f8ad9 Move the Function*->allocated blocks map from the JITMemoryManager to the
JITEmitter.

I'm gradually making Functions auto-remove themselves from the JIT when they're
destroyed. In this case, the Function needs to be removed from the JITEmitter,
but the map recording which Functions need to be removed lived behind the
JITMemoryManager interface, which made things difficult.

This patch replaces the deallocateMemForFunction(Function*) method with a pair
of methods deallocateFunctionBody(void *) and deallocateExceptionTable(void *)
corresponding to the two startFoo/endFoo pairs.

llvm-svn: 84651
2009-10-20 18:13:21 +00:00

279 lines
9.9 KiB
C++

//===- JITMemoryManagerTest.cpp - Unit tests for the JIT memory manager ---===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "gtest/gtest.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ExecutionEngine/JITMemoryManager.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/GlobalValue.h"
using namespace llvm;
namespace {
Function *makeFakeFunction() {
std::vector<const Type*> params;
const FunctionType *FTy =
FunctionType::get(Type::getVoidTy(getGlobalContext()), params, false);
return Function::Create(FTy, GlobalValue::ExternalLinkage);
}
// Allocate three simple functions that fit in the initial slab. This exercises
// the code in the case that we don't have to allocate more memory to store the
// function bodies.
TEST(JITMemoryManagerTest, NoAllocations) {
OwningPtr<JITMemoryManager> MemMgr(
JITMemoryManager::CreateDefaultMemManager());
uintptr_t size;
std::string Error;
// Allocate the functions.
OwningPtr<Function> F1(makeFakeFunction());
size = 1024;
uint8_t *FunctionBody1 = MemMgr->startFunctionBody(F1.get(), size);
memset(FunctionBody1, 0xFF, 1024);
MemMgr->endFunctionBody(F1.get(), FunctionBody1, FunctionBody1 + 1024);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
OwningPtr<Function> F2(makeFakeFunction());
size = 1024;
uint8_t *FunctionBody2 = MemMgr->startFunctionBody(F2.get(), size);
memset(FunctionBody2, 0xFF, 1024);
MemMgr->endFunctionBody(F2.get(), FunctionBody2, FunctionBody2 + 1024);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
OwningPtr<Function> F3(makeFakeFunction());
size = 1024;
uint8_t *FunctionBody3 = MemMgr->startFunctionBody(F3.get(), size);
memset(FunctionBody3, 0xFF, 1024);
MemMgr->endFunctionBody(F3.get(), FunctionBody3, FunctionBody3 + 1024);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
// Deallocate them out of order, in case that matters.
MemMgr->deallocateFunctionBody(FunctionBody2);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
MemMgr->deallocateFunctionBody(FunctionBody1);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
MemMgr->deallocateFunctionBody(FunctionBody3);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
}
// Make three large functions that take up most of the space in the slab. Then
// try allocating three smaller functions that don't require additional slabs.
TEST(JITMemoryManagerTest, TestCodeAllocation) {
OwningPtr<JITMemoryManager> MemMgr(
JITMemoryManager::CreateDefaultMemManager());
uintptr_t size;
std::string Error;
// Big functions are a little less than the largest block size.
const uintptr_t smallFuncSize = 1024;
const uintptr_t bigFuncSize = (MemMgr->GetDefaultCodeSlabSize() -
smallFuncSize * 2);
// Allocate big functions
OwningPtr<Function> F1(makeFakeFunction());
size = bigFuncSize;
uint8_t *FunctionBody1 = MemMgr->startFunctionBody(F1.get(), size);
ASSERT_LE(bigFuncSize, size);
memset(FunctionBody1, 0xFF, bigFuncSize);
MemMgr->endFunctionBody(F1.get(), FunctionBody1, FunctionBody1 + bigFuncSize);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
OwningPtr<Function> F2(makeFakeFunction());
size = bigFuncSize;
uint8_t *FunctionBody2 = MemMgr->startFunctionBody(F2.get(), size);
ASSERT_LE(bigFuncSize, size);
memset(FunctionBody2, 0xFF, bigFuncSize);
MemMgr->endFunctionBody(F2.get(), FunctionBody2, FunctionBody2 + bigFuncSize);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
OwningPtr<Function> F3(makeFakeFunction());
size = bigFuncSize;
uint8_t *FunctionBody3 = MemMgr->startFunctionBody(F3.get(), size);
ASSERT_LE(bigFuncSize, size);
memset(FunctionBody3, 0xFF, bigFuncSize);
MemMgr->endFunctionBody(F3.get(), FunctionBody3, FunctionBody3 + bigFuncSize);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
// Check that each large function took it's own slab.
EXPECT_EQ(3U, MemMgr->GetNumCodeSlabs());
// Allocate small functions
OwningPtr<Function> F4(makeFakeFunction());
size = smallFuncSize;
uint8_t *FunctionBody4 = MemMgr->startFunctionBody(F4.get(), size);
ASSERT_LE(smallFuncSize, size);
memset(FunctionBody4, 0xFF, smallFuncSize);
MemMgr->endFunctionBody(F4.get(), FunctionBody4,
FunctionBody4 + smallFuncSize);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
OwningPtr<Function> F5(makeFakeFunction());
size = smallFuncSize;
uint8_t *FunctionBody5 = MemMgr->startFunctionBody(F5.get(), size);
ASSERT_LE(smallFuncSize, size);
memset(FunctionBody5, 0xFF, smallFuncSize);
MemMgr->endFunctionBody(F5.get(), FunctionBody5,
FunctionBody5 + smallFuncSize);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
OwningPtr<Function> F6(makeFakeFunction());
size = smallFuncSize;
uint8_t *FunctionBody6 = MemMgr->startFunctionBody(F6.get(), size);
ASSERT_LE(smallFuncSize, size);
memset(FunctionBody6, 0xFF, smallFuncSize);
MemMgr->endFunctionBody(F6.get(), FunctionBody6,
FunctionBody6 + smallFuncSize);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
// Check that the small functions didn't allocate any new slabs.
EXPECT_EQ(3U, MemMgr->GetNumCodeSlabs());
// Deallocate them out of order, in case that matters.
MemMgr->deallocateFunctionBody(FunctionBody2);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
MemMgr->deallocateFunctionBody(FunctionBody1);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
MemMgr->deallocateFunctionBody(FunctionBody4);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
MemMgr->deallocateFunctionBody(FunctionBody3);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
MemMgr->deallocateFunctionBody(FunctionBody5);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
MemMgr->deallocateFunctionBody(FunctionBody6);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
}
// Allocate five global ints of varying widths and alignment, and check their
// alignment and overlap.
TEST(JITMemoryManagerTest, TestSmallGlobalInts) {
OwningPtr<JITMemoryManager> MemMgr(
JITMemoryManager::CreateDefaultMemManager());
uint8_t *a = (uint8_t *)MemMgr->allocateGlobal(8, 0);
uint16_t *b = (uint16_t*)MemMgr->allocateGlobal(16, 2);
uint32_t *c = (uint32_t*)MemMgr->allocateGlobal(32, 4);
uint64_t *d = (uint64_t*)MemMgr->allocateGlobal(64, 8);
// Check the alignment.
EXPECT_EQ(0U, ((uintptr_t)b) & 0x1);
EXPECT_EQ(0U, ((uintptr_t)c) & 0x3);
EXPECT_EQ(0U, ((uintptr_t)d) & 0x7);
// Initialize them each one at a time and make sure they don't overlap.
*a = 0xff;
*b = 0U;
*c = 0U;
*d = 0U;
EXPECT_EQ(0xffU, *a);
EXPECT_EQ(0U, *b);
EXPECT_EQ(0U, *c);
EXPECT_EQ(0U, *d);
*a = 0U;
*b = 0xffffU;
EXPECT_EQ(0U, *a);
EXPECT_EQ(0xffffU, *b);
EXPECT_EQ(0U, *c);
EXPECT_EQ(0U, *d);
*b = 0U;
*c = 0xffffffffU;
EXPECT_EQ(0U, *a);
EXPECT_EQ(0U, *b);
EXPECT_EQ(0xffffffffU, *c);
EXPECT_EQ(0U, *d);
*c = 0U;
*d = 0xffffffffffffffffULL;
EXPECT_EQ(0U, *a);
EXPECT_EQ(0U, *b);
EXPECT_EQ(0U, *c);
EXPECT_EQ(0xffffffffffffffffULL, *d);
// Make sure we didn't allocate any extra slabs for this tiny amount of data.
EXPECT_EQ(1U, MemMgr->GetNumDataSlabs());
}
// Allocate a small global, a big global, and a third global, and make sure we
// only use two slabs for that.
TEST(JITMemoryManagerTest, TestLargeGlobalArray) {
OwningPtr<JITMemoryManager> MemMgr(
JITMemoryManager::CreateDefaultMemManager());
size_t Size = 4 * MemMgr->GetDefaultDataSlabSize();
uint64_t *a = (uint64_t*)MemMgr->allocateGlobal(64, 8);
uint8_t *g = MemMgr->allocateGlobal(Size, 8);
uint64_t *b = (uint64_t*)MemMgr->allocateGlobal(64, 8);
// Check the alignment.
EXPECT_EQ(0U, ((uintptr_t)a) & 0x7);
EXPECT_EQ(0U, ((uintptr_t)g) & 0x7);
EXPECT_EQ(0U, ((uintptr_t)b) & 0x7);
// Initialize them to make sure we don't segfault and make sure they don't
// overlap.
memset(a, 0x1, 8);
memset(g, 0x2, Size);
memset(b, 0x3, 8);
EXPECT_EQ(0x0101010101010101ULL, *a);
// Just check the edges.
EXPECT_EQ(0x02U, g[0]);
EXPECT_EQ(0x02U, g[Size - 1]);
EXPECT_EQ(0x0303030303030303ULL, *b);
// Check the number of slabs.
EXPECT_EQ(2U, MemMgr->GetNumDataSlabs());
}
// Allocate lots of medium globals so that we can test moving the bump allocator
// to a new slab.
TEST(JITMemoryManagerTest, TestManyGlobals) {
OwningPtr<JITMemoryManager> MemMgr(
JITMemoryManager::CreateDefaultMemManager());
size_t SlabSize = MemMgr->GetDefaultDataSlabSize();
size_t Size = 128;
int Iters = (SlabSize / Size) + 1;
// We should start with one slab.
EXPECT_EQ(1U, MemMgr->GetNumDataSlabs());
// After allocating a bunch of globals, we should have two.
for (int I = 0; I < Iters; ++I)
MemMgr->allocateGlobal(Size, 8);
EXPECT_EQ(2U, MemMgr->GetNumDataSlabs());
// And after much more, we should have three.
for (int I = 0; I < Iters; ++I)
MemMgr->allocateGlobal(Size, 8);
EXPECT_EQ(3U, MemMgr->GetNumDataSlabs());
}
// Allocate lots of function stubs so that we can test moving the stub bump
// allocator to a new slab.
TEST(JITMemoryManagerTest, TestManyStubs) {
OwningPtr<JITMemoryManager> MemMgr(
JITMemoryManager::CreateDefaultMemManager());
size_t SlabSize = MemMgr->GetDefaultStubSlabSize();
size_t Size = 128;
int Iters = (SlabSize / Size) + 1;
// We should start with one slab.
EXPECT_EQ(1U, MemMgr->GetNumStubSlabs());
// After allocating a bunch of stubs, we should have two.
for (int I = 0; I < Iters; ++I)
MemMgr->allocateStub(NULL, Size, 8);
EXPECT_EQ(2U, MemMgr->GetNumStubSlabs());
// And after much more, we should have three.
for (int I = 0; I < Iters; ++I)
MemMgr->allocateStub(NULL, Size, 8);
EXPECT_EQ(3U, MemMgr->GetNumStubSlabs());
}
}