Don't pre-allocate one OOME per thread.

There's no associated stack trace, so we can share one between all
threads, saving a little memory and thread start-up time. Speaking
of stack traces: dump the stack to the log at the point where we
realize we're not going to be able to throw an exception with a
stack, so the developer has _something_ to work with.

Change-Id: I2246d291855bd9b9ee13f2be5b1ce14f669e9410
diff --git a/src/runtime.cc b/src/runtime.cc
index 1a66951..dda8f62 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -63,6 +63,7 @@
       class_linker_(NULL),
       signal_catcher_(NULL),
       java_vm_(NULL),
+      pre_allocated_OutOfMemoryError_(NULL),
       jni_stub_array_(NULL),
       abstract_method_error_stub_array_(NULL),
       resolution_method_(NULL),
@@ -82,7 +83,7 @@
     resolution_stub_array_[i] = NULL;
   }
   for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
-    callee_save_method_[i] = NULL;
+    callee_save_methods_[i] = NULL;
   }
 }
 
@@ -549,11 +550,18 @@
 
   CHECK(host_prefix_.empty()) << host_prefix_;
 
-  // Relocate the OatFiles (ELF images)
+  // Relocate the OatFiles (ELF images).
   class_linker_->RelocateExecutable();
 
-  // Restore main thread state to kNative as expected by native code
-  Thread::Current()->SetState(kNative);
+  // Restore main thread state to kNative as expected by native code.
+  Thread* self = Thread::Current();
+  self->SetState(kNative);
+
+  // Pre-allocate an OutOfMemoryError for the double-OOME case.
+  self->ThrowNewException("Ljava/lang/OutOfMemoryError;",
+                          "OutOfMemoryError thrown while trying to throw OutOfMemoryError; no stack available");
+  pre_allocated_OutOfMemoryError_ = self->GetException();
+  self->ClearException();
 
   started_ = true;
 
@@ -571,7 +579,7 @@
 
   CreateSystemClassLoader();
 
-  Thread::Current()->GetJniEnv()->locals.AssertEmpty();
+  self->GetJniEnv()->locals.AssertEmpty();
 
   VLOG(startup) << "Runtime::Start exiting";
 
@@ -851,6 +859,9 @@
   intern_table_->VisitRoots(visitor, arg);
   java_vm_->VisitRoots(visitor, arg);
   thread_list_->VisitRoots(visitor, arg);
+  if (pre_allocated_OutOfMemoryError_ != NULL) {
+    visitor(pre_allocated_OutOfMemoryError_, arg);
+  }
   visitor(jni_stub_array_, arg);
   visitor(abstract_method_error_stub_array_, arg);
   for (int i = 0; i < Runtime::kLastTrampolineMethodType; i++) {
@@ -858,7 +869,7 @@
   }
   visitor(resolution_method_, arg);
   for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
-    visitor(callee_save_method_[i], arg);
+    visitor(callee_save_methods_[i], arg);
   }
 }
 
@@ -943,7 +954,7 @@
 
 void Runtime::SetCalleeSaveMethod(Method* method, CalleeSaveType type) {
   DCHECK_LT(static_cast<int>(type), static_cast<int>(kLastCalleeSaveType));
-  callee_save_method_[type] = method;
+  callee_save_methods_[type] = method;
 }
 
 void Runtime::EnableMethodTracing(Trace* tracer) {