Fix compiler class initialization to properly deal with super classes

Also moving active parts of compiler_test to be oat tests including
IntMath and Invoke. Added an interface invocation test case to Invoke
test. Changed Compiler to CHECK that it is not used once the
Runtime::IsStarted, forcing some jni_compiler_test to have two phases,
one for compiling before Runtime::Start and one for JNI operations
after the Runtime::IsStarted.

Finally, fixed Class::CanPutArrayElementFromCode by removing
CanPutArrayElement and calling IsAssignableFrom directly.

Change-Id: I52ca4dbc0e02db65f274ccc3ca7468dce365a44e
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 0f02d09..6832b84 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1192,7 +1192,7 @@
   klass->SetStatus(Class::kStatusVerified);
 }
 
-bool ClassLinker::InitializeClass(Class* klass) {
+bool ClassLinker::InitializeClass(Class* klass, bool can_run_clinit) {
   CHECK(klass->GetStatus() == Class::kStatusResolved ||
       klass->GetStatus() == Class::kStatusVerified ||
       klass->GetStatus() == Class::kStatusInitializing ||
@@ -1201,6 +1201,7 @@
 
   Thread* self = Thread::Current();
 
+  Method* clinit = NULL;
   {
     ObjectLock lock(klass);
 
@@ -1220,6 +1221,12 @@
       return true;
     }
 
+    clinit = klass->FindDeclaredDirectMethod("<clinit>", "()V");
+    if (clinit != NULL && !can_run_clinit) {
+      // if the class has a <clinit>, don't bother going to initializing
+      return false;
+    }
+
     while (klass->GetStatus() == Class::kStatusInitializing) {
       // We caught somebody else in the act; was it us?
       if (klass->GetClinitThreadId() == self->GetTid()) {
@@ -1268,19 +1275,18 @@
       return false;
     }
 
-    DCHECK(klass->GetStatus() < Class::kStatusInitializing);
+    DCHECK_LT(klass->GetStatus(), Class::kStatusInitializing);
 
     klass->SetClinitThreadId(self->GetTid());
     klass->SetStatus(Class::kStatusInitializing);
   }
 
-  if (!InitializeSuperClass(klass)) {
+  if (!InitializeSuperClass(klass, can_run_clinit)) {
     return false;
   }
 
   InitializeStaticFields(klass);
 
-  Method* clinit = klass->FindDeclaredDirectMethod("<clinit>", "()V");
   if (clinit != NULL) {
     clinit->Invoke(self, NULL, NULL, NULL);
   }
@@ -1385,7 +1391,7 @@
   return true;
 }
 
-bool ClassLinker::InitializeSuperClass(Class* klass) {
+bool ClassLinker::InitializeSuperClass(Class* klass, bool can_run_clinit) {
   CHECK(klass != NULL);
   if (!klass->IsInterface() && klass->HasSuperClass()) {
     Class* super_class = klass->GetSuperClass();
@@ -1393,10 +1399,16 @@
       CHECK(!super_class->IsInterface());
       Thread* self = Thread::Current();
       klass->MonitorEnter(self);
-      bool super_initialized = InitializeClass(super_class);
+      bool super_initialized = InitializeClass(super_class, can_run_clinit);
       klass->MonitorExit(self);
       // TODO: check for a pending exception
       if (!super_initialized) {
+        if (!can_run_clinit) {
+         // Don't set status to error when we can't run <clinit>.
+         CHECK_EQ(klass->GetStatus(), Class::kStatusInitializing);
+         klass->SetStatus(Class::kStatusVerified);
+         return false;
+        }
         klass->SetStatus(Class::kStatusError);
         klass->NotifyAll();
         return false;
@@ -1406,7 +1418,7 @@
   return true;
 }
 
-bool ClassLinker::EnsureInitialized(Class* c) {
+bool ClassLinker::EnsureInitialized(Class* c, bool can_run_clinit) {
   CHECK(c != NULL);
   if (c->IsInitialized()) {
     return true;
@@ -1414,7 +1426,7 @@
 
   Thread* self = Thread::Current();
   c->MonitorEnter(self);
-  InitializeClass(c);
+  InitializeClass(c, can_run_clinit);
   c->MonitorExit(self);
   return !self->IsExceptionPending();
 }
@@ -1433,7 +1445,7 @@
   if (klass == referrer->GetDeclaringClass() && referrer->GetName()->Equals("<clinit>")) {
     return klass;
   }
-  if (!class_linker->EnsureInitialized(klass)) {
+  if (!class_linker->EnsureInitialized(klass, true)) {
     CHECK(Thread::Current()->IsExceptionPending());
     UNIMPLEMENTED(FATAL) << "throw exception due to class initialization problem";
   }
diff --git a/src/class_linker.h b/src/class_linker.h
index 02e6d6f..18bd9d6 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -134,7 +134,9 @@
                       bool is_static);
 
   // Returns true on success, false if there's an exception pending.
-  bool EnsureInitialized(Class* c);
+  // can_run_clinit=false allows the compiler to attempt to init a class,
+  // given the restriction that no <clinit> execution is possible.
+  bool EnsureInitialized(Class* c, bool can_run_clinit);
 
   void RegisterDexFile(const DexFile& dex_file);
   void RegisterDexFile(const DexFile& dex_file, DexCache* dex_cache);
@@ -172,7 +174,7 @@
 
   void FinishInit();
 
-  bool InitializeClass(Class* klass);
+  bool InitializeClass(Class* klass, bool can_run_clinit);
 
   // For early bootstrapping by Init
   Class* AllocClass(Class* java_lang_Class, size_t class_size);
@@ -238,7 +240,7 @@
   // was inserted.
   bool InsertClass(const StringPiece& descriptor, Class* klass);
 
-  bool InitializeSuperClass(Class* klass);
+  bool InitializeSuperClass(Class* klass, bool can_run_clinit);
 
   void InitializeStaticFields(Class* klass);
 
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 5e605c4..25fea16 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -37,10 +37,12 @@
     EXPECT_TRUE(primitive->GetSuperClass() == NULL);
     EXPECT_FALSE(primitive->HasSuperClass());
     EXPECT_TRUE(primitive->GetClassLoader() == NULL);
-    EXPECT_TRUE(primitive->GetStatus() == Class::kStatusInitialized);
+    EXPECT_EQ(Class::kStatusInitialized, primitive->GetStatus());
     EXPECT_FALSE(primitive->IsErroneous());
-    EXPECT_TRUE(primitive->IsVerified());
+    EXPECT_TRUE(primitive->IsLoaded());
     EXPECT_TRUE(primitive->IsResolved());
+    EXPECT_TRUE(primitive->IsVerified());
+    EXPECT_TRUE(primitive->IsInitialized());
     EXPECT_FALSE(primitive->IsArrayInstance());
     EXPECT_FALSE(primitive->IsArrayClass());
     EXPECT_TRUE(primitive->GetComponentType() == NULL);
@@ -79,10 +81,12 @@
     EXPECT_TRUE(array->HasSuperClass());
     ASSERT_TRUE(array->GetComponentType() != NULL);
     ASSERT_TRUE(array->GetComponentType()->GetDescriptor() != NULL);
-    EXPECT_TRUE(array->GetStatus() == Class::kStatusInitialized);
+    EXPECT_EQ(Class::kStatusInitialized, array->GetStatus());
     EXPECT_FALSE(array->IsErroneous());
-    EXPECT_TRUE(array->IsVerified());
+    EXPECT_TRUE(array->IsLoaded());
     EXPECT_TRUE(array->IsResolved());
+    EXPECT_TRUE(array->IsVerified());
+    EXPECT_TRUE(array->IsInitialized());
     EXPECT_FALSE(array->IsArrayInstance());
     EXPECT_TRUE(array->IsArrayClass());
     EXPECT_FALSE(array->IsInterface());
@@ -148,10 +152,9 @@
     EXPECT_TRUE(klass->GetClass() != NULL);
     EXPECT_EQ(klass->GetClass(), klass->GetClass()->GetClass());
     EXPECT_TRUE(klass->GetDexCache() != NULL);
+    EXPECT_TRUE(klass->IsLoaded());
     EXPECT_TRUE(klass->IsResolved());
     EXPECT_FALSE(klass->IsErroneous());
-    EXPECT_TRUE(klass->IsResolved());
-    EXPECT_TRUE(klass->IsLoaded());
     EXPECT_FALSE(klass->IsArrayClass());
     EXPECT_TRUE(klass->GetComponentType() == NULL);
     EXPECT_TRUE(klass->IsInSamePackage(klass));
@@ -714,9 +717,12 @@
   EXPECT_TRUE(JavaLangObject->GetSuperClass() == NULL);
   EXPECT_FALSE(JavaLangObject->HasSuperClass());
   EXPECT_TRUE(JavaLangObject->GetClassLoader() == NULL);
+  EXPECT_EQ(Class::kStatusResolved, JavaLangObject->GetStatus());
   EXPECT_FALSE(JavaLangObject->IsErroneous());
-  EXPECT_TRUE(JavaLangObject->IsVerified());
+  EXPECT_TRUE(JavaLangObject->IsLoaded());
   EXPECT_TRUE(JavaLangObject->IsResolved());
+  EXPECT_FALSE(JavaLangObject->IsVerified());
+  EXPECT_FALSE(JavaLangObject->IsInitialized());
   EXPECT_FALSE(JavaLangObject->IsArrayInstance());
   EXPECT_FALSE(JavaLangObject->IsArrayClass());
   EXPECT_TRUE(JavaLangObject->GetComponentType() == NULL);
@@ -745,10 +751,12 @@
   EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
   EXPECT_TRUE(MyClass->HasSuperClass());
   EXPECT_EQ(class_loader, MyClass->GetClassLoader());
-  EXPECT_TRUE(MyClass->GetStatus() == Class::kStatusResolved);
+  EXPECT_EQ(Class::kStatusResolved, MyClass->GetStatus());
   EXPECT_FALSE(MyClass->IsErroneous());
-  EXPECT_FALSE(MyClass->IsVerified());
+  EXPECT_TRUE(MyClass->IsLoaded());
   EXPECT_TRUE(MyClass->IsResolved());
+  EXPECT_FALSE(MyClass->IsVerified());
+  EXPECT_FALSE(MyClass->IsInitialized());
   EXPECT_FALSE(MyClass->IsArrayInstance());
   EXPECT_FALSE(MyClass->IsArrayClass());
   EXPECT_TRUE(MyClass->GetComponentType() == NULL);
@@ -812,7 +820,7 @@
   // TODO: uncomment expectations of initial values when InitializeClass works
   const ClassLoader* class_loader = LoadDex("Statics");
   Class* statics = class_linker_->FindClass("LStatics;", class_loader);
-  class_linker_->EnsureInitialized(statics);
+  class_linker_->EnsureInitialized(statics, true);
 
   EXPECT_EQ(10U, statics->NumStaticFields());
 
diff --git a/src/common_test.h b/src/common_test.h
index fefbbda..a291976 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -106,7 +106,6 @@
     options.push_back(std::make_pair("-Xcheck:jni", reinterpret_cast<void*>(NULL)));
     runtime_.reset(Runtime::Create(options, false));
     ASSERT_TRUE(runtime_.get() != NULL);
-    runtime_->Start();
     class_linker_ = runtime_->GetClassLinker();
 
 #if defined(__i386__)
diff --git a/src/compiler.cc b/src/compiler.cc
index 017861f..4d7ad19 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -24,6 +24,7 @@
 
 Compiler::Compiler(InstructionSet insns) : instruction_set_(insns), jni_compiler_(insns),
     verbose_(false) {
+  CHECK(!Runtime::Current()->IsStarted());
   if (insns == kArm || insns == kThumb2) {
     abstract_method_error_stub_ = arm::CreateAbstractMethodErrorStub();
   } else if (insns == kX86) {
@@ -32,6 +33,7 @@
 }
 
 void Compiler::CompileAll(const ClassLoader* class_loader) {
+  DCHECK(!Runtime::Current()->IsStarted());
   Resolve(class_loader);
   Verify(class_loader);
   InitializeClassesWithoutClinit(class_loader);
@@ -40,6 +42,7 @@
 }
 
 void Compiler::CompileOne(Method* method) {
+  DCHECK(!Runtime::Current()->IsStarted());
   const ClassLoader* class_loader = method->GetDeclaringClass()->GetClassLoader();
   Resolve(class_loader);
   Verify(class_loader);
@@ -124,19 +127,7 @@
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
     const char* descriptor = dex_file.GetClassDescriptor(class_def);
     Class* klass = class_linker->FindClass(descriptor, class_loader);
-    CHECK(klass != NULL);
-    if (klass->IsInitialized()) {
-      continue;
-    }
-    CHECK(klass->IsVerified() || klass->IsErroneous());
-    if (!klass->IsVerified()) {
-      continue;
-    }
-    Method* clinit = klass->FindDirectMethod("<clinit>", "()V");
-    if (clinit != NULL) {
-      continue;
-    }
-    klass->SetStatus(Class::kStatusInitialized);
+    class_linker->EnsureInitialized(klass, false);
   }
 
   DexCache* dex_cache = class_linker->FindDexCache(dex_file);
diff --git a/src/compiler_test.cc b/src/compiler_test.cc
index fd8a0ec..7886e60 100644
--- a/src/compiler_test.cc
+++ b/src/compiler_test.cc
@@ -163,11 +163,6 @@
   }
 }
 
-TEST_F(CompilerTest, ByBillion) {
-  CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
-  AssertStaticLongMethod(123, LoadDex("IntMath"), "IntMath", "divideLongByBillion", "(J)J", 123000000000LL);
-}
-
 TEST_F(CompilerTest, DISABLED_AbstractMethodErrorStub) {
   const ClassLoader* class_loader = LoadDex("AbstractMethod");
   EnsureCompiled(class_loader, "AbstractMethod", "callme", "()V", true);
@@ -184,165 +179,6 @@
 #endif  // __arm__
 }
 
-// TODO: need stub for InstanceofNonTrivialFromCode
-TEST_F(CompilerTest, InstanceTest) {
-  CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
-  AssertStaticIntMethod(1352, LoadDex("IntMath"), "IntMath", "instanceTest", "(I)I", 10);
-}
-
 // TODO: need check-cast test (when stub complete & we can throw/catch
 
-// TODO: Need invoke-interface test
-
-TEST_F(CompilerTest, SuperTest) {
-  CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
-  AssertStaticIntMethod(4175, LoadDex("IntMath"), "IntMath", "superTest", "(I)I", 4141);
-}
-
-TEST_F(CompilerTest, ConstStringTest) {
-  CompileDirectMethod(NULL, "java.lang.String", "<clinit>", "()V");
-  CompileDirectMethod(NULL, "java.lang.String", "<init>", "(II[C)V");
-  CompileDirectMethod(NULL, "java.lang.String", "<init>", "([CII)V");
-  CompileVirtualMethod(NULL, "java.lang.String", "_getChars", "(II[CI)V");
-  CompileVirtualMethod(NULL, "java.lang.String", "charAt", "(I)C");
-  CompileVirtualMethod(NULL, "java.lang.String", "length", "()I");
-  AssertStaticIntMethod(1246, LoadDex("IntMath"), "IntMath", "constStringTest", "(I)I", 1234);
-}
-
-TEST_F(CompilerTest, ConstClassTest) {
-  AssertStaticIntMethod(2222, LoadDex("IntMath"), "IntMath", "constClassTest", "(I)I", 1111);
-}
-
-TEST_F(CompilerTest, CatchTest) {
-  CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
-  CompileDirectMethod(NULL, "java.lang.NullPointerException", "<init>", "()V");
-  CompileDirectMethod(NULL, "java.lang.RuntimeException", "<init>", "()V");
-  CompileDirectMethod(NULL, "java.lang.Exception", "<init>", "()V");
-  CompileDirectMethod(NULL, "java.lang.Throwable","<init>", "()V");
-  CompileDirectMethod(NULL, "java.util.ArrayList","<init>","()V");
-  CompileDirectMethod(NULL, "java.util.AbstractList","<init>","()V");
-  CompileDirectMethod(NULL, "java.util.AbstractCollection","<init>","()V");
-  CompileVirtualMethod(NULL, "java.lang.Throwable","fillInStackTrace","()Ljava/lang/Throwable;");
-  CompileDirectMethod(NULL, "java.lang.Throwable","nativeFillInStackTrace","()Ljava/lang/Object;");
-  AssertStaticIntMethod(1579, LoadDex("IntMath"), "IntMath", "catchBlock", "(I)I", 1000);
-  AssertStaticIntMethod(7777, LoadDex("IntMath"), "IntMath", "catchBlock", "(I)I", 7000);
-}
-
-TEST_F(CompilerTest, CatchTestNoThrow) {
-  AssertStaticIntMethod(1123, LoadDex("IntMath"), "IntMath", "catchBlockNoThrow", "(I)I", 1000);
-}
-
-TEST_F(CompilerTest, StaticFieldTest) {
-  AssertStaticIntMethod(1404, LoadDex("IntMath"), "IntMath", "staticFieldTest", "(I)I", 404);
-}
-
-TEST_F(CompilerTest, UnopTest) {
-  AssertStaticIntMethod(37, LoadDex("IntMath"), "IntMath", "unopTest", "(I)I", 38);
-}
-
-TEST_F(CompilerTest, ShiftTest1) {
-  AssertStaticIntMethod(0, LoadDex("IntMath"), "IntMath", "shiftTest1", "()I");
-}
-
-TEST_F(CompilerTest, ShiftTest2) {
-  AssertStaticIntMethod(0, LoadDex("IntMath"), "IntMath", "shiftTest2", "()I");
-}
-
-TEST_F(CompilerTest, UnsignedShiftTest) {
-  AssertStaticIntMethod(0, LoadDex("IntMath"), "IntMath", "unsignedShiftTest", "()I");
-}
-
-TEST_F(CompilerTest, ConvTest) {
-  AssertStaticIntMethod(0, LoadDex("IntMath"), "IntMath", "convTest", "()I");
-}
-
-TEST_F(CompilerTest, CharSubTest) {
-  AssertStaticIntMethod(0, LoadDex("IntMath"), "IntMath", "charSubTest", "()I");
-}
-
-TEST_F(CompilerTest, IntOperTest) {
-  AssertStaticIntMethod(0, LoadDex("IntMath"), "IntMath", "intOperTest", "(II)I", 70000, -3);
-}
-
-TEST_F(CompilerTest, Lit16Test) {
-  AssertStaticIntMethod(0, LoadDex("IntMath"), "IntMath", "lit16Test", "(I)I", 77777);
-}
-
-TEST_F(CompilerTest, Lit8Test) {
-  AssertStaticIntMethod(0, LoadDex("IntMath"), "IntMath", "lit8Test", "(I)I", -55555);
-}
-
-TEST_F(CompilerTest, IntShiftTest) {
-  AssertStaticIntMethod(0, LoadDex("IntMath"), "IntMath", "intShiftTest", "(II)I", 0xff00aa01, 8);
-}
-
-TEST_F(CompilerTest, LongOperTest) {
-  AssertStaticIntMethod(0, LoadDex("IntMath"), "IntMath", "longOperTest", "(JJ)I",
-                        70000000000LL, -3LL);
-}
-
-TEST_F(CompilerTest, LongShiftTest) {
-  AssertStaticLongMethod(0x96deff00aa010000LL,
-      LoadDex("IntMath"), "IntMath", "longShiftTest", "(JI)J", 0xd5aa96deff00aa01LL, 16);
-}
-
-TEST_F(CompilerTest, SwitchTest1) {
-  AssertStaticIntMethod(1234, LoadDex("IntMath"), "IntMath", "switchTest", "(I)I", 1);
-}
-
-TEST_F(CompilerTest, IntCompare) {
-  AssertStaticIntMethod(1111, LoadDex("IntMath"), "IntMath", "testIntCompare", "(IIII)I",
-                        -5, 4, 4, 0);
-}
-
-TEST_F(CompilerTest, LongCompare) {
-  AssertStaticIntMethod(2222, LoadDex("IntMath"), "IntMath", "testLongCompare", "(JJJJ)I",
-                        -5LL, -4294967287LL, 4LL, 8LL);
-}
-
-TEST_F(CompilerTest, FloatCompare) {
-  AssertStaticIntMethod(3333, LoadDex("IntMath"), "IntMath", "testFloatCompare", "(FFFF)I",
-                        -5.0f, 4.0f, 4.0f,
-                        (1.0f/0.0f) / (1.0f/0.0f));
-}
-
-TEST_F(CompilerTest, DoubleCompare) {
-  AssertStaticIntMethod(4444, LoadDex("IntMath"), "IntMath", "testDoubleCompare", "(DDDD)I",
-                                    -5.0, 4.0, 4.0,
-                                    (1.0/0.0) / (1.0/0.0));
-}
-
-TEST_F(CompilerTest, RecursiveFibonacci) {
-  AssertStaticIntMethod(55, LoadDex("IntMath"), "IntMath", "fibonacci", "(I)I", 10);
-}
-
-#if 0 // Need to complete try/catch block handling
-TEST_F(CompilerTest, ThrowAndCatch) {
-  AssertStaticIntMethod(4, LoadDex("IntMath"), "IntMath", "throwAndCatch", "()I");
-}
-#endif
-
-TEST_F(CompilerTest, ManyArgs) {
-  AssertStaticIntMethod(-1, LoadDex("IntMath"), "IntMath", "manyArgs",
-                        "(IJIJIJIIDFDSICIIBZIIJJIIIII)I",
-                        0, 1LL, 2, 3LL, 4, 5LL, 6, 7, 8.0, 9.0f, 10.0,
-                        (short)11, 12, (char)13, 14, 15, (int8_t)-16, true, 18,
-                        19, 20LL, 21LL, 22, 23, 24, 25, 26);
-}
-
-TEST_F(CompilerTest, VirtualCall) {
-  CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
-  AssertStaticIntMethod(6, LoadDex("IntMath"), "IntMath", "staticCall", "(I)I", 3);
-}
-
-TEST_F(CompilerTest, TestIGetPut) {
-  CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
-  AssertStaticIntMethod(333, LoadDex("IntMath"), "IntMath", "testIGetPut", "(I)I", 111);
-}
-
-TEST_F(CompilerTest, InvokeTest) {
-  CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
-  AssertStaticIntMethod(20664, LoadDex("Invoke"), "Invoke", "test0", "(I)I", 912);
-}
-
 }  // namespace art
diff --git a/src/exception_test.cc b/src/exception_test.cc
index 8816530..6c48f5f 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -133,6 +133,8 @@
 }
 
 TEST_F(ExceptionTest, StackTraceElement) {
+  runtime_->Start();
+
   enum {STACK_SIZE = 1000};
   uint32_t top_of_stack = 0;
   uintptr_t fake_stack[STACK_SIZE];
diff --git a/src/java_lang_System.cc b/src/java_lang_System.cc
index 8aeefcd..42bae22 100644
--- a/src/java_lang_System.cc
+++ b/src/java_lang_System.cc
@@ -207,19 +207,19 @@
   // and cause us to copy incompatible elements.
 
   Object* const * srcObj = reinterpret_cast<Object* const *>(srcBytes + srcPos * width);
-  Class* dstClass = dstArray->GetClass();
+  Class* dstClass = dstArray->GetClass()->GetComponentType();
 
   Class* initialElementClass = NULL;
   if (length > 0 && srcObj[0] != NULL) {
     initialElementClass = srcObj[0]->GetClass();
-    if (!Class::CanPutArrayElement(initialElementClass, dstClass)) {
+    if (!dstClass->IsAssignableFrom(initialElementClass)) {
       initialElementClass = NULL;
     }
   }
 
   int copyCount;
   for (copyCount = 0; copyCount < length; copyCount++) {
-    if (srcObj[copyCount] != NULL && srcObj[copyCount]->GetClass() != initialElementClass && !Class::CanPutArrayElement(srcObj[copyCount]->GetClass(), dstClass)) {
+    if (srcObj[copyCount] != NULL && srcObj[copyCount]->GetClass() != initialElementClass && !dstClass->IsAssignableFrom(srcObj[copyCount]->GetClass())) {
       // Can't put this element into the array.
       // We'll copy up to this point, then throw.
       break;
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 482ddcb..4f862d6 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -26,13 +26,8 @@
     class_loader_ = LoadDex("MyClassNatives");
   }
 
-  void SetupForTest(bool direct, const char* method_name,
-                    const char* method_sig, void* native_fnptr) {
-    env_ = Thread::Current()->GetJniEnv();
-
-    jklass_ = env_->FindClass("MyClass");
-    ASSERT_TRUE(jklass_ != NULL);
-
+  void CompileForTest(bool direct, const char* method_name, const char* method_sig) {
+    // Compile the native method before starting the runtime
     Class* c = class_linker_->FindClass("LMyClass;", class_loader_);
     Method* method;
     if (direct) {
@@ -41,10 +36,24 @@
       method = c->FindVirtualMethod(method_name, method_sig);
     }
     ASSERT_TRUE(method != NULL);
-
-    // Compile the native method
+    if (method->GetCode() != NULL) {
+      return;
+    }
     CompileMethod(method);
     ASSERT_TRUE(method->GetCode() != NULL);
+  }
+
+  void SetupForTest(bool direct, const char* method_name, const char* method_sig,
+                    void* native_fnptr) {
+    CompileForTest(direct, method_name, method_sig);
+    if (!runtime_->IsStarted()) {
+      runtime_->Start();
+    }
+
+    // JNI operations after runtime start
+    env_ = Thread::Current()->GetJniEnv();
+    jklass_ = env_->FindClass("MyClass");
+    ASSERT_TRUE(jklass_ != NULL);
 
     if (direct) {
       jmethod_ = env_->GetStaticMethodID(jklass_, method_name, method_sig);
@@ -420,6 +429,11 @@
 }
 
 TEST_F(JniCompilerTest, ExceptionHandling) {
+  // all compilation needs to happen before SetupForTest calls Runtime::Start
+  CompileForTest(false, "foo", "()V");
+  CompileForTest(false, "throwException", "()V");
+  CompileForTest(false, "foo", "()V");
+
   gJava_MyClass_foo_calls = 0;
 
   // Check a single call of a JNI method is ok
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 94ef729..6c25f6e 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -271,7 +271,7 @@
 
 jmethodID FindMethodID(ScopedJniThreadState& ts, jclass jni_class, const char* name, const char* sig, bool is_static) {
   Class* c = Decode<Class*>(ts, jni_class);
-  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c)) {
+  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
     return NULL;
   }
 
@@ -303,7 +303,7 @@
 
 jfieldID FindFieldID(ScopedJniThreadState& ts, jclass jni_class, const char* name, const char* sig, bool is_static) {
   Class* c = Decode<Class*>(ts, jni_class);
-  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c)) {
+  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
     return NULL;
   }
 
@@ -899,7 +899,7 @@
   static jobject AllocObject(JNIEnv* env, jclass java_class) {
     ScopedJniThreadState ts(env);
     Class* c = Decode<Class*>(ts, java_class);
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c)) {
+    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
       return NULL;
     }
     return AddLocalReference<jobject>(env, c->AllocObject());
@@ -917,7 +917,7 @@
   static jobject NewObjectV(JNIEnv* env, jclass java_class, jmethodID mid, va_list args) {
     ScopedJniThreadState ts(env);
     Class* c = Decode<Class*>(ts, java_class);
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c)) {
+    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
       return NULL;
     }
     Object* result = c->AllocObject();
@@ -929,7 +929,7 @@
   static jobject NewObjectA(JNIEnv* env, jclass java_class, jmethodID mid, jvalue* args) {
     ScopedJniThreadState ts(env);
     Class* c = Decode<Class*>(ts, java_class);
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c)) {
+    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
       return NULL;
     }
     Object* result = c->AllocObject();
@@ -2828,7 +2828,7 @@
   // If this is a static method, it could be called before the class
   // has been initialized.
   if (m->IsStatic()) {
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c)) {
+    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
       return NULL;
     }
   } else {
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index 067d36b..b3e5c79 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -648,6 +648,7 @@
 
 TEST_F(JniInternalTest, GetPrimitiveField_SetPrimitiveField) {
   LoadDex("AllFields");
+  runtime_->Start();
 
   jclass c = env_->FindClass("AllFields");
   ASSERT_TRUE(c != NULL);
@@ -675,6 +676,7 @@
 
 TEST_F(JniInternalTest, GetObjectField_SetObjectField) {
   LoadDex("AllFields");
+  runtime_->Start();
 
   jclass c = env_->FindClass("AllFields");
   ASSERT_TRUE(c != NULL);
diff --git a/src/object.cc b/src/object.cc
index 91c4b3d..b0a6745 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -113,7 +113,7 @@
     Class* c = f->GetDeclaringClass();
     // If the class is already initializing, we must be inside <clinit>, or
     // we'd still be waiting for the lock.
-    if (c->GetStatus() == Class::kStatusInitializing || class_linker->EnsureInitialized(c)) {
+    if (c->GetStatus() == Class::kStatusInitializing || class_linker->EnsureInitialized(c, true)) {
       return f;
     }
   }
@@ -789,19 +789,12 @@
   return false;
 }
 
-bool Class::CanPutArrayElement(const Class* object_class, const Class* array_class) {
-  if (object_class->IsArrayClass()) {
-    return array_class->IsArrayAssignableFromArray(object_class);
-  } else {
-    return array_class->GetComponentType()->IsAssignableFrom(object_class);
-  }
-}
-
 void Class::CanPutArrayElementFromCode(const Object* element, const Class* array_class) {
+  DCHECK(array_class != NULL);
   if (element == NULL) {
     return;
   }
-  if (!CanPutArrayElement(element->GetClass(), array_class)) {
+  if (!array_class->GetComponentType()->IsAssignableFrom(element->GetClass())) {
     LOG(ERROR) << "Can't put a " << PrettyClass(element->GetClass())
                << " into a " << PrettyClass(array_class);
     UNIMPLEMENTED(FATAL) << "need to throw ArrayStoreException and unwind stack";
diff --git a/src/object.h b/src/object.h
index 2adee04..efdb424 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1406,11 +1406,8 @@
     return !IsPrimitive() && GetSuperClass() == NULL;
   }
 
-  // Tests whether an element of type 'object_class' can be
+  // Tests whether a possibly null 'element' can be
   // assigned into an array of type 'array_class'.
-  static bool CanPutArrayElement(const Class* object_class, const Class* array_class);
-  // Like CanPutArrayElement, but throws an exception and
-  // unwinds the stack instead of returning false.
   static void CanPutArrayElementFromCode(const Object* element, const Class* array_class);
 
   // Given the context of a calling Method, use its DexCache to
@@ -2526,7 +2523,7 @@
   // circularity issue during loading the names of its members
   DCHECK(IsLoaded() || this == String::GetJavaLangString() ||
          this == Field::GetJavaLangReflectField() ||
-         this == Method::GetJavaLangReflectMethod());
+         this == Method::GetJavaLangReflectMethod()) << PrettyClass(this);
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), false);
 }
 
diff --git a/src/runtime.cc b/src/runtime.cc
index 99f5e3a..1f6a06a 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -370,7 +370,7 @@
 void Runtime::RunImageClinits() {
   Class* Field_class = class_linker_->FindSystemClass("Ljava/lang/reflect/Field;");
   CHECK(Field_class->FindDeclaredDirectMethod("<clinit>", "()V") != NULL);
-  class_linker_->EnsureInitialized(Field_class);
+  class_linker_->EnsureInitialized(Field_class, true);
   CHECK(!Thread::Current()->IsExceptionPending());
 }
 
diff --git a/src/thread.cc b/src/thread.cc
index 9525a1c..153f20f 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1053,6 +1053,7 @@
 
   virtual void VisitFrame(const Frame& frame, uintptr_t pc) {
     // We want to skip frames up to and including the exception's constructor.
+    DCHECK(gThrowable != NULL);
     if (skipping_ && !gThrowable->IsAssignableFrom(frame.GetMethod()->GetDeclaringClass())) {
       skipping_ = false;
     }