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";
   }