Work on heap and space initialization to support image loading

Change-Id: Icab25efa4dee17e4b6c6e97e38f63f5ab8a8a005
diff --git a/src/space.cc b/src/space.cc
index c3d763c..8048f29 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -4,16 +4,19 @@
 
 #include <sys/mman.h>
 
+#include "file.h"
+#include "image.h"
 #include "logging.h"
 #include "mspace.h"
+#include "os.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();
+Space* Space::Create(size_t initial_size, size_t maximum_size, byte* requested_base) {
+  scoped_ptr<Space> space(new Space());
+  bool success = space->Init(initial_size, maximum_size, requested_base);
   if (!success) {
     return NULL;
   } else {
@@ -21,18 +24,31 @@
   }
 }
 
+Space* Space::Create(const char* image_file_name) {
+  CHECK(image_file_name != NULL);
+  scoped_ptr<Space> space(new Space());
+  bool success = space->Init(image_file_name);
+  if (!success) {
+    return NULL;
+  } else {
+    return space.release();
+  }
+}
+
+Space::~Space() {}
+
 void* Space::CreateMallocSpace(void* base,
-                               size_t startup_size,
+                               size_t initial_size,
                                size_t maximum_size) {
   errno = 0;
   bool is_locked = false;
-  size_t commit_size = startup_size / 2;
+  size_t commit_size = initial_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);
+    mspace_set_max_allowed_footprint(msp, initial_size);
   } else {
     // There is no guarantee that errno has meaning when the call
     // fails, but it often does.
@@ -41,35 +57,60 @@
   return msp;
 }
 
-bool Space::Init() {
-  if (!(startup_size_ <= maximum_size_)) {
+bool Space::Init(size_t initial_size, size_t maximum_size, byte* requested_base) {
+  if (!(initial_size <= maximum_size)) {
     return false;
   }
-  size_t length = RoundUp(maximum_size_, kPageSize);
+  size_t length = RoundUp(maximum_size, kPageSize);
   int prot = PROT_READ | PROT_WRITE;
-  int flags = MAP_PRIVATE | MAP_ANONYMOUS;
-  mem_map_.reset(MemMap::Map(length, prot, flags));
-  if (mem_map_ == NULL) {
-    PLOG(ERROR) << "mmap failed";
+  scoped_ptr<MemMap> mem_map(MemMap::Map(requested_base, length, prot));
+  if (mem_map == NULL) {
     return false;
   }
+  Init(mem_map.release());
+  maximum_size_ = maximum_size;
+  mspace_ = CreateMallocSpace(base_, initial_size, maximum_size);
+  return (mspace_ != NULL);
+}
+
+void Space::Init(MemMap* mem_map) {
+  mem_map_.reset(mem_map);
   base_ = mem_map_->GetAddress();
-  limit_ = base_ + length;
-  mspace_ = CreateMallocSpace(base_, startup_size_, maximum_size_);
-  if (mspace_ == NULL) {
-    mem_map_->Unmap();
+  limit_ = base_ + mem_map->GetLength();
+}
+
+
+bool Space::Init(const char* image_file_name) {
+  scoped_ptr<File> file(OS::OpenFile(image_file_name, false));
+  if (file == NULL) {
     return false;
   }
+  ImageHeader image_header;
+  bool success = file->ReadFully(&image_header, sizeof(image_header));
+  if (!success || !image_header.IsValid()) {
+    return false;
+  }
+  scoped_ptr<MemMap> map(MemMap::Map(image_header.GetBaseAddr(),
+                                     file->Length(),
+                                     PROT_READ | PROT_WRITE,
+                                     MAP_PRIVATE | MAP_FIXED,
+                                     file->Fd(),
+                                     0));
+  if (map == NULL) {
+    return false;
+  }
+  CHECK_EQ(image_header.GetBaseAddr(), map->GetAddress());
+  Init(map.release());
   return true;
 }
 
-Space::~Space() {}
-
 Object* Space::AllocWithoutGrowth(size_t num_bytes) {
+  DCHECK(mspace_ != NULL);
   return reinterpret_cast<Object*>(mspace_calloc(mspace_, 1, num_bytes));
 }
 
 Object* Space::AllocWithGrowth(size_t num_bytes) {
+  DCHECK(mspace_ != NULL);
   // Grow as much as possible within the mspace.
   size_t max_allowed = maximum_size_;
   mspace_set_max_allowed_footprint(mspace_, max_allowed);
@@ -83,6 +124,7 @@
 }
 
 size_t Space::Free(void* ptr) {
+  DCHECK(mspace_ != NULL);
   DCHECK(ptr != NULL);
   size_t num_bytes = mspace_usable_size(mspace_, ptr);
   mspace_free(mspace_, ptr);
@@ -90,6 +132,7 @@
 }
 
 size_t Space::AllocationSize(const Object* obj) {
+  DCHECK(mspace_ != NULL);
   return mspace_usable_size(mspace_, obj) + kChunkOverhead;
 }
 
@@ -116,6 +159,7 @@
 }
 
 size_t Space::MaxAllowedFootprint() {
+  DCHECK(mspace_ != NULL);
   return mspace_max_allowed_footprint(mspace_);
 }