| //===--------------- gcmapper.cc - Mvm allocator ---------------------------===// |
| // |
| // Mvm |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "gcmapper.h" |
| #include <string.h> |
| #include <sys/mman.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| |
| |
| GCMinAllocStack GCMinAlloc::_stacks[GCMinAlloc::max_min_alloc >> log_step]; |
| GCMinAllocStack *GCMinAlloc::stacks[GCMinAlloc::max_min_alloc+1]; |
| GCMappedArea GCMinAlloc::base_area; |
| |
| |
| |
| #if defined(__MACH__) |
| #define DO_MMAP(sz) mmap(0, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0) |
| #else |
| #define DO_MMAP(sz) mmap(0, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0) |
| #endif |
| |
| #define DO_MUNMAP(ptr, sz) munmap(ptr, sz) |
| |
| #if defined(__MACH__) |
| static inline void* manual_mremap(void * addr, int old_size, int new_size, int flags) |
| { |
| void * res = addr; |
| if (new_size < old_size) |
| DO_MUNMAP((void*)((intptr_t)addr + new_size), old_size - new_size); |
| else if (new_size > old_size) |
| // Use of MAP_FIXED is discouraged... |
| // res = mmap(addr, new_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, MAP_FIXED); |
| res=(void*)-1; |
| |
| return res; |
| } |
| #endif |
| |
| static inline void *do_mmap(size_t sz) { |
| void *res = DO_MMAP(sz); |
| //printf("mmap %d bytes at %d\n", sz, res); |
| if(res == MAP_FAILED) { |
| if (errno == ENOMEM) |
| (*onMemoryError)(sz); |
| else |
| { |
| gcfatal("unable to mmap %d bytes", sz); |
| } |
| } |
| return res; |
| } |
| |
| static inline void do_munmap(void *ptr, size_t sz) { |
| // printf("munmap %d bytes at %p\n", sz, ptr); |
| DO_MUNMAP(ptr, sz); |
| } |
| |
| void *GCMappedArea::do_mmap(size_t sz) { return ::do_mmap(sz); } |
| void GCMappedArea::do_munmap(void *ptr, size_t sz) { ::do_munmap(ptr, sz); } |
| |
| GCMappedArea *GCMappedArea::munmap() { |
| ::do_munmap(_mapped_area, _mapped_nbb); |
| return this; |
| } |
| |
| GCMappedArea *GCMappedArea::mmap(size_t n) { |
| _mapped_area = ::do_mmap(_mapped_nbb = n); |
| return this; |
| } |
| |
| int GCMappedArea::mremap(size_t n) { |
| #if defined(__MACH__) |
| void *res = manual_mremap(_mapped_area, _mapped_nbb, n, 0); |
| #else |
| void *res = ::mremap(_mapped_area, _mapped_nbb, n, 0); |
| #endif |
| |
| if((intptr_t)res == -1) |
| return -1; |
| _mapped_area = res; |
| _mapped_nbb = n; |
| return 0; |
| } |
| |
| void *GCMinAlloc::alloc_area(GCMinAllocStack *s) { |
| GCMinAllocStack *area_stack = stacks[sizeof(GCMappedArea)]; |
| GCMappedArea *area = (GCMappedArea *)area_stack->alloc(); |
| |
| if(!area) { |
| /* pbm : on n'a vraiment plus rien :) */ |
| area = (GCMappedArea *)::do_mmap(PAGE_SIZE); |
| area->initialise(area, PAGE_SIZE); |
| area_stack->fill((uintptr_t)(area + 1), PAGE_SIZE - sizeof(GCMappedArea)); |
| area->append(&base_area); |
| area = (GCMappedArea *)area_stack->alloc(); |
| } |
| area->mmap(PAGE_SIZE); |
| area->append(&base_area); |
| s->fill((uintptr_t)area->area(), area->nbb()); |
| |
| return s->alloc(); |
| } |
| |
| void GCMinAlloc::initialise() { |
| unsigned int i, j, m; |
| size_t nb_stacks = max_min_alloc >> log_step; |
| |
| stacks[0] = _stacks; |
| for(i=0; i<nb_stacks; i++) { |
| m = i<<log_step; |
| _stacks[i].initialise(m + (1<<log_step)); |
| for(j=0; j<(1<<log_step); j++) |
| stacks[m+j+1] = _stacks + i; |
| } |
| } |
| |
| void GCMinAlloc::destroy() { |
| unsigned int nb_area, i; |
| GCMappedArea *cur; |
| |
| for(nb_area=0, cur=base_area.next(); cur!=&base_area; cur=cur->next(), nb_area++) {} |
| |
| GCMappedArea* areas = (GCMappedArea*)alloca(sizeof(GCMappedArea) * nb_area); |
| |
| for(i=0, cur=base_area.next(); cur!=&base_area; cur=cur->next(), i++) |
| areas[i] = *cur; |
| |
| for(i=0; i<nb_area; i++) |
| areas[i].munmap(); |
| } |