blob: c0f3b47fff36d3266130ee5b6cfdfd6f834fa1b5 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Intel, Mikhail Y. Fursov
*
*/
#ifdef WIN32
#include <malloc.h>
#else
#include <stdlib.h>
#include <string.h>
#endif
#include <iostream>
#include <stdio.h>
#include <assert.h>
#include "MemoryManager.h"
//#define JIT_MEM_CHECK
#ifdef JIT_MEM_CHECK
#include "mkernel.h"
#endif
namespace Jitrino {
#ifdef JIT_MEM_CHECK
#define JIT_MEM_CHECK_PADDING_SIZE 8
#define JIT_MEM_CHECK_DEFAULT_VAL 'x'
#define JIT_MEM_CHECK_PADDING_VAL 'p'
static Mutex checkPointsMutex;
typedef std::map<const Arena*, std::vector<size_t>*> CheckPointsByArena;
static CheckPointsByArena checkPointsByArena;
static void _check_arena_paddings(const Arena* a) ;
static void _check_arena_default_val_on_alloc(const Arena* a, size_t offset, size_t len) ;
static inline void m_assert(bool cond);
#endif //JIT_MEM_CHECK
#define BITS_TO_CLEAR (sizeof(void*)-1)
//
// For tracing
//
#ifdef USE_TRACE_MEM_MANANGER
static int traceId = 0;
static ::std::ostream& traceStream = ::std::cerr;
#endif
static const U_32 mm_default_next_arena_size = 4096-ARENA_HEADER_SIZE;
MemoryManager::MemoryManager(const char* name)
{
_arena = NULL;
_bytes_allocated = 0;
_bytes_arena = 0;
_name = name;
_numArenas = 0;
#ifdef USE_TRACE_MEM_MANANGER
// get start time for this MemoryManager
_startTraceId = traceId++;
#ifdef DEBUG_MEMORY_MANAGER
traceStream << "### MemoryManager," << _name << ", START" << ::std::endl;
#endif //DEBUG_MEMORY_MANAGER
#endif //USE_TRACE_MEM_MANANGER
}
#ifdef DEBUG_MEMORY_MANAGER
static size_t totalAllocated = 0;
#endif
MemoryManager::~MemoryManager()
{
#ifdef USE_TRACE_MEM_MANANGER
// get end time for this MemoryManager
_endTraceId = traceId++;
#ifdef DEBUG_MEMORY_MANAGER
// print out trace
traceStream << "### MemoryManager," << _name
<< "," << _startTraceId
<< "," << (_endTraceId - _startTraceId)
<< "," << (int)_bytes_allocated
<< "," << (int)_bytes_arena
<< "," << _numArenas
<< ::std::endl;
traceStream << "### TotalMalloced=" << (int) totalAllocated << ::std::endl;
#endif //DEBUG_MEMORY_MANAGER
#endif //USE_TRACE_MEM_MANANGER
_free_arenas(_arena);
_arena = 0;
}
void MemoryManager::_alloc_arena(size_t size)
{
_numArenas++;
_bytes_arena += size;
_arena = alloc_arena(_arena,size);
assert(((POINTER_SIZE_INT)_arena->next_byte & BITS_TO_CLEAR) == 0);
#ifdef JIT_MEM_CHECK
checkPointsMutex.lock();
checkPointsByArena[_arena] = new std::vector<size_t>();
checkPointsMutex.unlock();
size_t allocated_size = _arena->last_byte - _arena->bytes;
memset(_arena->bytes, JIT_MEM_CHECK_DEFAULT_VAL, allocated_size);
#endif
}
void MemoryManager::_free_arenas(Arena *a)
{
while(a != NULL) {
Arena* last = a;
a = a->next_arena;
#ifdef JIT_MEM_CHECK
checkPointsMutex.lock();
_check_arena_paddings(last);
CheckPointsByArena::iterator it = checkPointsByArena.find(last);
m_assert(it!=checkPointsByArena.end());
std::vector<size_t>* v = it->second;
checkPointsByArena.erase(it);
delete v;
checkPointsMutex.unlock();
#endif
free_arena(last);
}
}
#ifdef JIT_MEM_CHECK
static inline void m_assert(bool cond) {
#ifdef _DEBUG
assert(cond);
#else
#ifdef WIN32
if (!cond) {
__asm {
int 3;
}
}
#endif
#endif
}
void _check_arena_paddings(const Arena* a) {
CheckPointsByArena::const_iterator ait = checkPointsByArena.find(a);
m_assert(ait!=checkPointsByArena.end());
std::vector<size_t>* t = ait->second;
for (std::vector<size_t>::const_iterator it = t->begin(), end = t->end(); it!=end; ++it) {
size_t offset = *it;
const char* borderStart = a->bytes + offset;
for (int j=0; j<JIT_MEM_CHECK_PADDING_SIZE; j++) {
char c = borderStart[j];
m_assert(c == JIT_MEM_CHECK_PADDING_VAL);
}
}
}
void _check_arena_default_val_on_alloc(const Arena* a, size_t offset, size_t len) {
const char* mem = a->bytes + offset;
for (size_t j=0; j<len; j++) {
char c = mem[j];
m_assert(c == JIT_MEM_CHECK_DEFAULT_VAL);
}
}
#endif //JIT_MEM_CHECK
void *MemoryManager::alloc(size_t size)
{
if (size == 0)
return NULL;
// _arena=>next_byte is guaranteed to be aligned initially
// to maintain the above, make sure that size is rounded up
// if necessary
#ifdef JIT_MEM_CHECK
size+=JIT_MEM_CHECK_PADDING_SIZE;
#endif
size = (size + BITS_TO_CLEAR) & ~BITS_TO_CLEAR;
_bytes_allocated += size;
if (_arena == NULL || _arena->next_byte + size > _arena->last_byte) {
//
// allocate another arena
//
size_t arena_size;
if (size < mm_default_next_arena_size) {
arena_size = mm_default_next_arena_size;
} else {
arena_size = size;
}
_alloc_arena(arena_size);
assert(((POINTER_SIZE_INT)_arena->next_byte & BITS_TO_CLEAR) == 0);
}
//
// already aligned
//
char *mem = _arena->next_byte;
//
// still aligned
//
_arena->next_byte += size;
assert(((POINTER_SIZE_INT)_arena->next_byte & BITS_TO_CLEAR) == 0);
#ifdef JIT_MEM_CHECK
checkPointsMutex.lock();
_check_arena_default_val_on_alloc(_arena, mem - _arena->bytes, size);
CheckPointsByArena::iterator it = checkPointsByArena.find(_arena);
assert(it!=checkPointsByArena.end());
std::vector<size_t>* v = it->second;
//push offset of the current padding from the start of arena
v->push_back((_arena->next_byte - _arena->bytes) - JIT_MEM_CHECK_PADDING_SIZE);
memset(mem + size - JIT_MEM_CHECK_PADDING_SIZE, JIT_MEM_CHECK_PADDING_VAL, JIT_MEM_CHECK_PADDING_SIZE);
checkPointsMutex.unlock();
#endif
return (void*)mem;
}
char*
MemoryManager::copy(const char* str) {
if (!str) return NULL;
size_t len = strlen(str);
char* cp = (char*)alloc(len + 1);
return strcpy(cp, str);
}
} //namespace Jitrino
#ifdef DEBUG_MEMORY_MANAGER
void* operator new (size_t sz) {
Jitrino::totalAllocated += sz;
return malloc(sz);
}
#endif