blob: 9e091f2f8184c48588d08923a4ca27950646c439 [file] [log] [blame]
// Copyright 2011 Google Inc. All Rights Reserved.
// Author: cshapiro@google.com (Carl Shapiro)
#include "space.h"
#include <sys/mman.h>
#include "logging.h"
#include "mspace.h"
#include "scoped_ptr.h"
#include "utils.h"
namespace art {
Space* Space::Create(size_t startup_size, size_t maximum_size) {
scoped_ptr<Space> space(new Space(startup_size, maximum_size));
bool success = space->Init();
if (!success) {
return NULL;
} else {
return space.release();
}
}
void* Space::CreateMallocSpace(void* base,
size_t startup_size,
size_t maximum_size) {
errno = 0;
bool is_locked = false;
size_t commit_size = startup_size / 2;
void* msp = create_contiguous_mspace_with_base(commit_size, maximum_size,
is_locked, base);
if (msp != NULL) {
// Do not permit the heap grow past the starting size without our
// intervention.
mspace_set_max_allowed_footprint(msp, startup_size);
} else {
// There is no guarantee that errno has meaning when the call
// fails, but it often does.
PLOG(ERROR) << "create_contiguous_mspace_with_base failed";
}
return msp;
}
bool Space::Init() {
if (!(startup_size_ <= maximum_size_)) {
return false;
}
size_t length = RoundUp(maximum_size_, 4096);
int prot = PROT_READ | PROT_WRITE;
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
void* base = mmap(NULL, length, prot, flags, -1, 0);
if (base == MAP_FAILED) {
PLOG(ERROR) << "mmap failed";
return false;
}
base_ = static_cast<byte*>(base);
limit_ = base_ + length;
mspace_ = CreateMallocSpace(base, startup_size_, maximum_size_);
if (mspace_ == NULL) {
munmap(base_, length);
return false;
}
return true;
}
Space::~Space() {
if (base_ == NULL) {
return;
}
int result = munmap(base_, limit_ - base_);
if (result == -1) {
PLOG(WARNING) << "munmap failed";
}
}
Object* Space::AllocWithoutGrowth(size_t num_bytes) {
return reinterpret_cast<Object*>(mspace_calloc(mspace_, 1, num_bytes));
}
Object* Space::AllocWithGrowth(size_t num_bytes) {
// Grow as much as possible within the mspace.
size_t max_allowed = maximum_size_;
mspace_set_max_allowed_footprint(mspace_, max_allowed);
// Try the allocation.
void* ptr = AllocWithoutGrowth(num_bytes);
// Shrink back down as small as possible.
size_t footprint = mspace_footprint(mspace_);
mspace_set_max_allowed_footprint(mspace_, footprint);
// Return the new allocation or NULL.
return reinterpret_cast<Object*>(ptr);
}
size_t Space::Free(void* ptr) {
DCHECK(ptr != NULL);
size_t num_bytes = mspace_usable_size(mspace_, ptr);
mspace_free(mspace_, ptr);
return num_bytes;
}
void Space::DontNeed(void* start, void* end, void* num_bytes) {
start = (void*)RoundUp((uintptr_t)start, 4096);
end = (void*)RoundDown((uintptr_t)end, 4096);
if (start >= end) {
return;
}
size_t length = reinterpret_cast<byte*>(end) - reinterpret_cast<byte*>(start);
int result = madvise(start, length, MADV_DONTNEED);
if (result == -1) {
PLOG(WARNING) << "madvise failed";
} else {
*reinterpret_cast<size_t*>(num_bytes) += length;
}
}
void Space::Trim() {
CHECK(mspace_ != NULL);
mspace_trim(mspace_, 0);
size_t num_bytes_released = 0;
mspace_walk_free_pages(mspace_, DontNeed, &num_bytes_released);
}
size_t Space::MaxAllowedFootprint() {
return mspace_max_allowed_footprint(mspace_);
}
void Space::Grow(size_t new_size) {
}
} // namespace art