Add allocation and garbage collection infrastructure.
Change-Id: I4b04cdfdf18afb75a7b0df87b509e8156b4a932b
diff --git a/src/space.cc b/src/space.cc
new file mode 100644
index 0000000..dc9950c
--- /dev/null
+++ b/src/space.cc
@@ -0,0 +1,130 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+// Author: cshapiro@google.com (Carl Shapiro)
+
+#include "src/space.h"
+
+#include <sys/mman.h>
+
+#include "src/logging.h"
+#include "src/mspace.h"
+#include "src/scoped_ptr.h"
+#include "src/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