Make sure threads allocating are in the kRunnable state

Change-Id: I55a08fcd38b3388698ef571d2d4fa9553210e197
diff --git a/src/dalvik_system_DexFile.cc b/src/dalvik_system_DexFile.cc
index 40a1626..6ad92ba 100644
--- a/src/dalvik_system_DexFile.cc
+++ b/src/dalvik_system_DexFile.cc
@@ -154,6 +154,7 @@
 }
 
 jclass DexFile_defineClass(JNIEnv* env, jclass, jstring javaName, jobject javaLoader, jint cookie) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   const DexFile* dex_file = toDexFile(env, cookie);
   if (dex_file == NULL) {
     return NULL;
diff --git a/src/dalvik_system_VMRuntime.cc b/src/dalvik_system_VMRuntime.cc
index 8334059..d4c1ed2 100644
--- a/src/dalvik_system_VMRuntime.cc
+++ b/src/dalvik_system_VMRuntime.cc
@@ -44,6 +44,7 @@
 }
 
 jobject VMRuntime_newNonMovableArray(JNIEnv* env, jobject, jclass javaElementClass, jint length) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
 #ifdef MOVING_GARBAGE_COLLECTOR
   // TODO: right now, we don't have a copying collector, so there's no need
   // to do anything special here, but we ought to pass the non-movability
@@ -74,6 +75,7 @@
 }
 
 jlong VMRuntime_addressOf(JNIEnv* env, jobject, jobject javaArray) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   Array* array = Decode<Array*>(env, javaArray);
   if (!array->IsArrayInstance()) {
     Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;", "not an array");
diff --git a/src/heap.cc b/src/heap.cc
index bef71ae..9e356d1 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -323,6 +323,10 @@
 Object* Heap::AllocateLocked(Space* space, size_t size) {
   lock_->AssertHeld();
 
+  // Since allocation can cause a GC which will need to SuspendAll,
+  // make sure all allocators are in the kRunnable state.
+  DCHECK_EQ(Thread::Current()->GetState(), Thread::kRunnable);
+
   // Fail impossible allocations.  TODO: collect soft references.
   if (size > maximum_size_) {
     return NULL;
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index ec89a57..81d070f 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -29,6 +29,7 @@
 
 // "name" is in "binary name" format, e.g. "dalvik.system.Debug$1".
 jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean initialize, jobject javaLoader) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   ScopedUtfChars name(env, javaName);
   if (name.c_str() == NULL) {
     return NULL;
@@ -307,6 +308,7 @@
 }
 
 jboolean Class_isAssignableFrom(JNIEnv* env, jobject javaLhs, jclass javaRhs) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   Class* lhs = Decode<Class*>(env, javaLhs);
   Class* rhs = Decode<Class*>(env, javaRhs);
   if (rhs == NULL) {
@@ -365,6 +367,7 @@
 }
 
 jobject Class_newInstanceImpl(JNIEnv* env, jobject javaThis) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   Class* c = Decode<Class*>(env, javaThis);
   if (c->IsPrimitive() || c->IsInterface() || c->IsArrayClass() || c->IsAbstract()) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/InstantiationException;",
diff --git a/src/java_lang_Object.cc b/src/java_lang_Object.cc
index 41ff8b2..30d8223 100644
--- a/src/java_lang_Object.cc
+++ b/src/java_lang_Object.cc
@@ -30,6 +30,7 @@
 }
 
 jobject Object_internalClone(JNIEnv* env, jobject javaThis) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   Object* o = Decode<Object*>(env, javaThis);
   return AddLocalReference<jobject>(env, o->Clone());
 }
diff --git a/src/java_lang_Runtime.cc b/src/java_lang_Runtime.cc
index a2bd399..981db70 100644
--- a/src/java_lang_Runtime.cc
+++ b/src/java_lang_Runtime.cc
@@ -30,6 +30,7 @@
 namespace {
 
 void Runtime_gc(JNIEnv*, jclass) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   Heap::CollectGarbage();
 }
 
diff --git a/src/java_lang_String.cc b/src/java_lang_String.cc
index 9aa5221..ff182e1 100644
--- a/src/java_lang_String.cc
+++ b/src/java_lang_String.cc
@@ -39,6 +39,7 @@
 namespace {
 
 jint String_compareTo(JNIEnv* env, jobject javaThis, jobject javaRhs) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   String* lhs = Decode<String*>(env, javaThis);
   String* rhs = Decode<String*>(env, javaRhs);
 
diff --git a/src/java_lang_System.cc b/src/java_lang_System.cc
index d8e8a5a..45a2aee 100644
--- a/src/java_lang_System.cc
+++ b/src/java_lang_System.cc
@@ -111,6 +111,7 @@
 }
 
 void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject javaDst, jint dstPos, jint length) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   Thread* self = Thread::Current();
 
   // Null pointer checks.
diff --git a/src/java_lang_Thread.cc b/src/java_lang_Thread.cc
index 9a91f77..891238e 100644
--- a/src/java_lang_Thread.cc
+++ b/src/java_lang_Thread.cc
@@ -55,12 +55,13 @@
 }
 
 jboolean Thread_nativeHoldsLock(JNIEnv* env, jobject javaThread, jobject javaObject) {
-  ThreadListLock lock;
   Object* object = Decode<Object*>(env, javaObject);
   if (object == NULL) {
+    ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
     Thread::Current()->ThrowNewException("Ljava/lang/NullPointerException;", "object == null");
     return JNI_FALSE;
   }
+  ThreadListLock lock;
   Thread* thread = Thread::FromManagedThread(env, javaThread);
   return thread->HoldsLock(object);
 }
diff --git a/src/java_lang_reflect_Array.cc b/src/java_lang_reflect_Array.cc
index d157282..08960b1 100644
--- a/src/java_lang_reflect_Array.cc
+++ b/src/java_lang_reflect_Array.cc
@@ -72,6 +72,7 @@
 // subtract pieces off.  Besides, we want to start with the outermost
 // piece and work our way in.
 jobject Array_createMultiArray(JNIEnv* env, jclass, jclass javaElementClass, jobject javaDimArray) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   DCHECK(javaElementClass != NULL);
   Class* element_class = Decode<Class*>(env, javaElementClass);
   DCHECK(element_class->IsClass());
@@ -120,6 +121,7 @@
 
 jobject Array_createObjectArray(JNIEnv* env, jclass, jclass javaElementClass, jint length)
 {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   DCHECK(javaElementClass != NULL);
   Class* element_class = Decode<Class*>(env, javaElementClass);
   if (length < 0) {
diff --git a/src/java_lang_reflect_Constructor.cc b/src/java_lang_reflect_Constructor.cc
index 4d42450..f730543 100644
--- a/src/java_lang_reflect_Constructor.cc
+++ b/src/java_lang_reflect_Constructor.cc
@@ -33,6 +33,7 @@
  * with an interface, array, or primitive class.
  */
 jobject Constructor_constructNative(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs, jclass javaDeclaringClass, jobjectArray javaParams, jint, jboolean) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   Class* c = Decode<Class*>(env, javaDeclaringClass);
   if (c->IsAbstract()) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/InstantiationException;",
diff --git a/src/java_lang_reflect_Field.cc b/src/java_lang_reflect_Field.cc
index a2f09e7..727866b 100644
--- a/src/java_lang_reflect_Field.cc
+++ b/src/java_lang_reflect_Field.cc
@@ -30,6 +30,7 @@
 }
 
 bool GetFieldValue(Object* o, Field* f, JValue& value, bool allow_references) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   switch (f->GetPrimitiveType()) {
   case Primitive::kPrimBoolean:
     value.z = f->GetBoolean(o);
@@ -187,6 +188,7 @@
 }
 
 void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jchar src_descriptor, const JValue& new_value) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   Field* f = DecodeField(env->FromReflectedField(javaField));
   Object* o = NULL;
   if (!CheckReceiver(env, javaObj, javaDeclaringClass, f, o)) {
@@ -254,6 +256,7 @@
 }
 
 void Field_setField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jobject javaValue) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   Field* f = DecodeField(env->FromReflectedField(javaField));
 
   // Unbox the value, if necessary.
diff --git a/src/thread.cc b/src/thread.cc
index 68acb9b..d9edd60 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -647,6 +647,11 @@
 }
 
 void Thread::FinishStartup() {
+  Thread* self = Thread::Current();
+
+  // Need to be kRunnable for FindClass
+  ScopedThreadStateChange tsc(self, Thread::kRunnable);
+
   // Now the ClassLinker is ready, we can find the various Class*, Field*, and Method*s we need.
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
@@ -672,7 +677,6 @@
       "uncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V");
 
   // Finish attaching the main thread.
-  Thread* self = Thread::Current();
   self->CreatePeer("main", false);
 
   const Field* Thread_contextClassLoader = FindFieldOrDie(Thread_class , "contextClassLoader", "Ljava/lang/ClassLoader;");