Alloc stack using MemMap and -Xss

Change-Id: Ib6d52e41e62bf9cd111b2f03257ead53673d3e81
diff --git a/src/mem_map.h b/src/mem_map.h
index 9357b9b..8645f44 100644
--- a/src/mem_map.h
+++ b/src/mem_map.h
@@ -91,6 +91,10 @@
     return length_;
   }
 
+  byte* GetLimit() const {
+    return addr_ + length_;
+  }
+
  private:
   MemMap(byte* addr, size_t length, void* base_addr, size_t base_length)
       : addr_(addr), length_(length), base_addr_(base_addr), base_length_(base_length) {
diff --git a/src/runtime.cc b/src/runtime.cc
index de76bb3..6108fe8 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -326,6 +326,7 @@
   exit_ = options->hook_exit_;
   abort_ = options->hook_abort_;
 
+  stack_size_ = options->stack_size_;
   thread_list_ = ThreadList::Create();
 
   Heap::Init(options->heap_initial_size_,
diff --git a/src/runtime.h b/src/runtime.h
index 0aa0cb5..4a5063c 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -75,7 +75,11 @@
 
   ~Runtime();
 
-  ClassLinker* GetClassLinker() {
+  size_t GetStackSize() const {
+    return stack_size_;
+  }
+
+  ClassLinker* GetClassLinker() const {
     return class_linker_;
   }
 
@@ -86,11 +90,14 @@
  private:
   static void PlatformAbort(const char*, int);
 
-  Runtime() : thread_list_(NULL), class_linker_(NULL) {}
+  Runtime() : stack_size_(0), thread_list_(NULL), class_linker_(NULL) {}
 
   // Initializes a new uninitialized runtime.
   bool Init(const Options& options, bool ignore_unrecognized);
 
+  // The default stack size for managed threads created by the runtime.
+  size_t stack_size_;
+
   ThreadList* thread_list_;
 
   ClassLinker* class_linker_;
diff --git a/src/thread.cc b/src/thread.cc
index 71cd877..aa3fe95 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -53,20 +53,21 @@
   return NULL;
 }
 
-Thread* Thread::Create(size_t stack_size) {
-  int prot = PROT_READ | PROT_WRITE;
-  // TODO: require the stack size to be page aligned?
-  size_t length = RoundUp(stack_size, kPageSize);
-  void* stack_limit = mmap(NULL, length, prot, MAP_PRIVATE, -1, 0);
-  if (stack_limit == MAP_FAILED) {
-    LOG(FATAL) << "mmap";
-    return false;
+Thread* Thread::Create(const Runtime* runtime) {
+  size_t stack_size = runtime->GetStackSize();
+  scoped_ptr<MemMap> stack(MemMap::Map(stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE));
+  if (stack == NULL) {
+    LOG(FATAL) << "failed to allocate thread stack";
+    // notreached
+    return NULL;
   }
 
   Thread* new_thread = new Thread;
   new_thread->InitCpu();
-  new_thread->stack_limit_ = static_cast<byte*>(stack_limit);
-  new_thread->stack_base_ = new_thread->stack_limit_ + length;
+  new_thread->stack_.reset(stack.release());
+  // Since stacks are assumed to grown downward the base is the limit and the limit is the base.
+  new_thread->stack_limit_ = stack->GetAddress();
+  new_thread->stack_base_ = stack->GetLimit();
 
   pthread_attr_t attr;
   int result = pthread_attr_init(&attr);
diff --git a/src/thread.h b/src/thread.h
index de5893e..4264a1a 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -10,6 +10,7 @@
 #include "jni_internal.h"
 #include "logging.h"
 #include "macros.h"
+#include "mem_map.h"
 #include "offsets.h"
 #include "runtime.h"
 
@@ -115,7 +116,7 @@
   static const size_t kDefaultStackSize = 64 * KB;
 
   // Creates a new thread.
-  static Thread* Create(size_t stack_size);
+  static Thread* Create(const Runtime* runtime);
 
   // Creates a new thread from the calling thread.
   static Thread* Attach(const Runtime* runtime);
@@ -292,6 +293,9 @@
   // at the next poll.
   int suspend_count_;
 
+  // The memory mapping of the stack for non-attached threads.
+  scoped_ptr<MemMap> stack_;
+
   // The inclusive base of the control stack.
   byte* stack_base_;