Merge "Add a SafeMap equivalent to std::map but without the error-prone operator[]." into ics-mr1-plus-art
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index 0011791..3db1667 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -269,7 +269,7 @@
 }
 
 Object* art_initialize_static_storage_from_code(uint32_t type_idx, Method* referrer) {
-  return ResolveVerifyAndClinit(type_idx, referrer, Thread::Current(), true, true);
+  return ResolveVerifyAndClinit(type_idx, referrer, Thread::Current(), true, false);
 }
 
 Object* art_initialize_type_from_code(uint32_t type_idx, Method* referrer) {
diff --git a/src/heap.cc b/src/heap.cc
index e244cf1..eb62807 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -267,24 +267,49 @@
   delete lock_;
 }
 
-Object* Heap::AllocObject(Class* klass, size_t byte_count) {
+static void MSpaceChunkCallback(void* start, void* end, size_t used_bytes, void* arg) {
+  size_t& max_contiguous_allocation = *reinterpret_cast<size_t*>(arg);
+
+  size_t chunk_size = static_cast<size_t>(reinterpret_cast<uint8_t*>(end) - reinterpret_cast<uint8_t*>(start));
+  size_t chunk_free_bytes = 0;
+  if (used_bytes < chunk_size) {
+    chunk_free_bytes = chunk_size - used_bytes;
+  }
+
+  if (chunk_free_bytes > max_contiguous_allocation) {
+    max_contiguous_allocation = chunk_free_bytes;
+  }
+}
+
+Object* Heap::AllocObject(Class* c, size_t byte_count) {
+  // Used in the detail message if we throw an OOME.
+  int64_t total_bytes_free;
+  size_t max_contiguous_allocation;
+
   {
     ScopedHeapLock heap_lock;
-    DCHECK(klass == NULL || (klass->IsClassClass() && byte_count >= sizeof(Class)) ||
-           (klass->IsVariableSize() || klass->GetObjectSize() == byte_count) ||
-           strlen(ClassHelper(klass).GetDescriptor()) == 0);
+    DCHECK(c == NULL || (c->IsClassClass() && byte_count >= sizeof(Class)) ||
+           (c->IsVariableSize() || c->GetObjectSize() == byte_count) ||
+           strlen(ClassHelper(c).GetDescriptor()) == 0);
     DCHECK_GE(byte_count, sizeof(Object));
     Object* obj = AllocateLocked(byte_count);
     if (obj != NULL) {
-      obj->SetClass(klass);
+      obj->SetClass(c);
       if (Dbg::IsAllocTrackingEnabled()) {
-        Dbg::RecordAllocation(klass, byte_count);
+        Dbg::RecordAllocation(c, byte_count);
       }
       return obj;
     }
+    total_bytes_free = GetFreeMemory();
+    max_contiguous_allocation = 0;
+    GetAllocSpace()->Walk(MSpaceChunkCallback, &max_contiguous_allocation);
   }
 
-  Thread::Current()->ThrowOutOfMemoryError(klass, byte_count);
+  std::string msg(StringPrintf("Failed to allocate a %zd-byte %s (%lld total bytes free; largest possible contiguous allocation %zd bytes)",
+                               byte_count,
+                               PrettyDescriptor(c).c_str(),
+                               total_bytes_free, max_contiguous_allocation));
+  Thread::Current()->ThrowOutOfMemoryError(msg.c_str());
   return NULL;
 }
 
@@ -491,11 +516,6 @@
     return ptr;
   }
 
-  LOG(ERROR) << "Out of memory on a " << PrettySize(alloc_size) << " allocation";
-
-  // TODO: tell the HeapSource to dump its state
-  // TODO: dump stack traces for all threads
-
   return NULL;
 }
 
diff --git a/src/thread.cc b/src/thread.cc
index 1a39d99..fbc718c 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1424,12 +1424,6 @@
   }
 }
 
-void Thread::ThrowOutOfMemoryError(Class* c, size_t byte_count) {
-  std::string msg(StringPrintf("Failed to allocate a %zd-byte %s", byte_count,
-      PrettyDescriptor(c).c_str()));
-  ThrowOutOfMemoryError(msg.c_str());
-}
-
 void Thread::ThrowOutOfMemoryError(const char* msg) {
   LOG(ERROR) << StringPrintf("Throwing OutOfMemoryError \"%s\"%s",
       msg, (throwing_OutOfMemoryError_ ? " (recursive case)" : ""));
diff --git a/src/thread.h b/src/thread.h
index a100c03..2cb59d5 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -254,8 +254,8 @@
   void ThrowNewExceptionV(const char* exception_class_descriptor, const char* fmt, va_list ap);
 
   // OutOfMemoryError is special, because we need to pre-allocate an instance.
+  // Only the GC should call this.
   void ThrowOutOfMemoryError(const char* msg);
-  void ThrowOutOfMemoryError(Class* c, size_t byte_count);
 
   Frame FindExceptionHandler(void* throw_pc, void** handler_pc);