Various runtime/JNI related fixes.

NewObject returns NULL if exception is thrown in constructor.
Allocate the peer then call constructor to ensure peer_ field is
initialized.
Change thread state for AddFinalizer and pass current thread through for
ease.

Change-Id: Ib578b6d44b08aef10fde5d8bc27cc6a2acbf6fae
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 9b6c74e..80b21e2 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -144,6 +144,7 @@
   }
 
   // Check early that the result of compilation can be written
+  // TODO: implement a proper locking scheme here, probably hold onto the open file..
   if (OS::FileExists(oat_filename.c_str())) {
     // File exists, check we can write to it
     UniquePtr<File> file(OS::OpenFile(oat_filename.c_str(), true));
diff --git a/src/heap.cc b/src/heap.cc
index 9561c48..57a3ce2 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -734,12 +734,13 @@
   return ref;
 }
 
-void Heap::AddFinalizerReference(Object* object) {
+void Heap::AddFinalizerReference(Thread* self, Object* object) {
+  ScopedThreadStateChange tsc(self, Thread::kRunnable);
   static Method* FinalizerReference_add =
       java_lang_ref_FinalizerReference_->FindDirectMethod("add", "(Ljava/lang/Object;)V");
   DCHECK(FinalizerReference_add != NULL);
   Object* args[] = { object };
-  FinalizerReference_add->Invoke(Thread::Current(), NULL, reinterpret_cast<byte*>(&args), NULL);
+  FinalizerReference_add->Invoke(self, NULL, reinterpret_cast<byte*>(&args), NULL);
 }
 
 void Heap::EnqueueClearedReferences(Object** cleared) {
diff --git a/src/heap.h b/src/heap.h
index 923b015..8897405 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -32,6 +32,7 @@
 class Mutex;
 class Object;
 class Space;
+class Thread;
 class HeapBitmap;
 
 class Heap {
@@ -194,7 +195,7 @@
   // dlmalloc_walk_heap-compatible heap walker.
   static void WalkHeap(void(*callback)(const void*, size_t, const void*, size_t, void*), void* arg);
 
-  static void AddFinalizerReference(Object* object);
+  static void AddFinalizerReference(Thread* self, Object* object);
 
   static size_t GetBytesAllocated() { return num_bytes_allocated_; }
   static size_t GetObjectsAllocated() { return num_objects_allocated_; }
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 5052773..1f3124c 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -965,7 +965,11 @@
     }
     jobject local_result = AddLocalReference<jobject>(env, result);
     CallNonvirtualVoidMethodV(env, local_result, java_class, mid, args);
-    return local_result;
+    if (!ts.Self()->IsExceptionPending()) {
+      return local_result;
+    } else {
+      return NULL;
+    }
   }
 
   static jobject NewObjectA(JNIEnv* env, jclass java_class, jmethodID mid, jvalue* args) {
@@ -980,7 +984,11 @@
     }
     jobject local_result = AddLocalReference<jobjectArray>(env, result);
     CallNonvirtualVoidMethodA(env, local_result, java_class, mid, args);
-    return local_result;
+    if (!ts.Self()->IsExceptionPending()) {
+      return local_result;
+    } else {
+      return NULL;
+    }
   }
 
   static jmethodID GetMethodID(JNIEnv* env, jclass c, const char* name, const char* sig) {
diff --git a/src/object.cc b/src/object.cc
index 2bb6d2d..9cc0e3a 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -43,7 +43,7 @@
   memcpy(dst_bytes + offset, src_bytes + offset, num_bytes - offset);
 
   if (c->IsFinalizable()) {
-    Heap::AddFinalizerReference(copy.get());
+    Heap::AddFinalizerReference(Thread::Current(), copy.get());
   }
 
   return copy.get();
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 3c10fc3..9653d28 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -44,7 +44,7 @@
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   Class* c = o->GetClass();
   if (UNLIKELY(c->IsFinalizable())) {
-    Heap::AddFinalizerReference(o);
+    Heap::AddFinalizerReference(self, o);
   }
   /*
    * NOTE: once debugger/profiler support is added, we'll need to check
diff --git a/src/thread.cc b/src/thread.cc
index 983486a..af48c35 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -295,11 +295,16 @@
   jboolean thread_is_daemon = as_daemon;
 
   ScopedLocalRef<jclass> c(env, env->FindClass("java/lang/Thread"));
-  jmethodID mid = env->GetMethodID(c.get(), "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
-
-  ScopedLocalRef<jobject> peer(env,
-      env->NewObject(c.get(), mid, thread_group.get(), thread_name.get(), thread_priority, thread_is_daemon));
+  ScopedLocalRef<jobject> peer(env, env->AllocObject(c.get()));
   peer_ = DecodeJObject(peer.get());
+  if (peer_ == NULL) {
+    CHECK(IsExceptionPending());
+    // TODO: signal failure to caller
+    return;
+  }
+  jmethodID mid = env->GetMethodID(c.get(), "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
+  env->CallNonvirtualVoidMethod(peer.get(), c.get(), mid, thread_group.get(), thread_name.get(), thread_priority, thread_is_daemon);
+  CHECK(!IsExceptionPending());
   SetVmData(peer_, Thread::Current());
 
   SirtRef<String> peer_thread_name(GetName());