Add missing class initialization during compilation and tests

Adds missing class initialization during compilation and tests, especially
java.lang.Class. Otherwise, we'd be able to execute code while the referring
class is not initialized or initializing.

Also adds mirror::Class::AssertInitializedOrInitializingInThread method to
check class initialization when entering the interpreter: the called method's
declaring class must either be initialized or be initializing by the current
thread (other threads must be waiting for the class initialization to complete
holding its lock). Note we only do this check in debug build.

Bump oat version to force compilation.

Bug: 15899971
Change-Id: I9a4edd3739a3ca4cf1c4929dcbb44cdf7a1ca1fe
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 289dc1d..ac6d44b 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -206,6 +206,7 @@
     runtime_.reset(Runtime::Current());
     class_linker_ = runtime_->GetClassLinker();
     class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
+    class_linker_->RunRootClinits();
 
     // Runtime::Create acquired the mutator_lock_ that is normally given away when we
     // Runtime::Start, give it away now and then switch to a more managable ScopedObjectAccess.
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index cb4d444..9cc1441 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -354,6 +354,7 @@
          shadow_frame.GetMethod()->GetDeclaringClass()->IsProxyClass());
   DCHECK(!shadow_frame.GetMethod()->IsAbstract());
   DCHECK(!shadow_frame.GetMethod()->IsNative());
+  shadow_frame.GetMethod()->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
 
   bool transaction_active = Runtime::Current()->IsActiveTransaction();
   if (LIKELY(shadow_frame.GetMethod()->IsPreverified())) {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 9f04b90..5a03601 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -35,6 +35,7 @@
     CHECK(self->IsExceptionPending());
     return false;
   }
+  f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
   Object* obj;
   if (is_static) {
     obj = f->GetDeclaringClass();
@@ -210,6 +211,7 @@
     CHECK(self->IsExceptionPending());
     return false;
   }
+  f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
   Object* obj;
   if (is_static) {
     obj = f->GetDeclaringClass();
@@ -757,40 +759,64 @@
   }
 }
 
+// Helper function to deal with class loading in an unstarted runtime.
+static void UnstartedRuntimeFindClass(Thread* self, Handle<mirror::String> className,
+                                      Handle<mirror::ClassLoader> class_loader, JValue* result,
+                                      const std::string& method_name, bool initialize_class,
+                                      bool abort_if_not_found)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  CHECK(className.Get() != nullptr);
+  std::string descriptor(DotToDescriptor(className->ToModifiedUtf8().c_str()));
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+  Class* found = class_linker->FindClass(self, descriptor.c_str(), class_loader);
+  if (found == nullptr && abort_if_not_found) {
+    if (!self->IsExceptionPending()) {
+      AbortTransaction(self, "%s failed in un-started runtime for class: %s",
+                       method_name.c_str(), PrettyDescriptor(descriptor).c_str());
+    }
+    return;
+  }
+  if (found != nullptr && initialize_class) {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> h_class(hs.NewHandle(found));
+    if (!class_linker->EnsureInitialized(h_class, true, true)) {
+      CHECK(self->IsExceptionPending());
+      return;
+    }
+  }
+  result->SetL(found);
+}
+
 static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
                                    const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
                                    JValue* result, size_t arg_offset) {
   // In a runtime that's not started we intercept certain methods to avoid complicated dependency
   // problems in core libraries.
   std::string name(PrettyMethod(shadow_frame->GetMethod()));
-  if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)"
-      || name == "java.lang.Class java.lang.VMClassLoader.loadClass(java.lang.String, boolean)") {
-    // TODO Class#forName should actually call Class::EnsureInitialized always. Support for the
-    // other variants that take more arguments should also be added.
-    std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset)->AsString()->ToModifiedUtf8().c_str()));
-
-    // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader();
-    Class* found = Runtime::Current()->GetClassLinker()->FindClass(
-        self, descriptor.c_str(), NullHandle<mirror::ClassLoader>());
-    if (found == NULL) {
-      if (!self->IsExceptionPending()) {
-        AbortTransaction(self, "Class.forName failed in un-started runtime for class: %s",
-                         PrettyDescriptor(descriptor).c_str());
-      }
-      return;
-    }
-    result->SetL(found);
+  if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") {
+    // TODO: Support for the other variants that take more arguments should also be added.
+    mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString();
+    StackHandleScope<1> hs(self);
+    Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
+    UnstartedRuntimeFindClass(self, h_class_name, NullHandle<mirror::ClassLoader>(), result, name,
+                              true, true);
+  } else if (name == "java.lang.Class java.lang.VMClassLoader.loadClass(java.lang.String, boolean)") {
+    mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString();
+    StackHandleScope<1> hs(self);
+    Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
+    UnstartedRuntimeFindClass(self, h_class_name, NullHandle<mirror::ClassLoader>(), result, name,
+                              false, true);
+  } else if (name == "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") {
+    mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset + 1)->AsString();
+    mirror::ClassLoader* class_loader =
+        down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset));
+    StackHandleScope<2> hs(self);
+    Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
+    Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(class_loader));
+    UnstartedRuntimeFindClass(self, h_class_name, h_class_loader, result, name, false, false);
   } else if (name == "java.lang.Class java.lang.Void.lookupType()") {
     result->SetL(Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V'));
-  } else if (name == "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") {
-    StackHandleScope<1> hs(self);
-    Handle<ClassLoader> class_loader(
-        hs.NewHandle(down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset))));
-    std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset + 1)->AsString()->ToModifiedUtf8().c_str()));
-
-    Class* found = Runtime::Current()->GetClassLinker()->FindClass(self, descriptor.c_str(),
-                                                                   class_loader);
-    result->SetL(found);
   } else if (name == "java.lang.Object java.lang.Class.newInstance()") {
     Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
     ArtMethod* c = klass->FindDeclaredDirectMethod("<init>", "()V");
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index cb4868c..abd4b44 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -536,6 +536,7 @@
     if (UNLIKELY(obj == NULL)) {
       HANDLE_PENDING_EXCEPTION();
     } else {
+      obj->GetClass()->AssertInitializedOrInitializingInThread(self);
       // Don't allow finalizable objects to be allocated during a transaction since these can't be
       // finalized without a started runtime.
       if (transaction_active && obj->GetClass()->IsFinalizable()) {
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index bdf2a20..c635648 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -449,6 +449,7 @@
         if (UNLIKELY(obj == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
+          obj->GetClass()->AssertInitializedOrInitializingInThread(self);
           // Don't allow finalizable objects to be allocated during a transaction since these can't
           // be finalized without a started runtime.
           if (transaction_active && obj->GetClass()->IsFinalizable()) {
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 451235c..2daa6e4 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -546,6 +546,14 @@
   }
 }
 
+inline void Class::AssertInitializedOrInitializingInThread(Thread* self) {
+  if (kIsDebugBuild && !IsInitialized()) {
+    CHECK(IsInitializing()) << PrettyClass(this) << " is not initializing: " << GetStatus();
+    CHECK_EQ(GetClinitThreadId(), self->GetTid()) << PrettyClass(this)
+                                                  << " is initializing in a different thread";
+  }
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index e735c45..7ac53ea 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -880,6 +880,10 @@
   const DexFile& GetDexFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const DexFile::TypeList* GetInterfaceTypeList() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Asserts we are initialized or initializing in the given thread.
+  void AssertInitializedOrInitializingInThread(Thread* self)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  private:
   void SetVerifyErrorClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 857c0a2..7c8e5bc 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -22,7 +22,7 @@
 namespace art {
 
 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '3', '6', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '3', '7', '\0' };
 
 OatHeader::OatHeader() {
   memset(this, 0, sizeof(*this));
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index 3b66abe..abe68ef 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -109,7 +109,16 @@
                         : c->FindVirtualMethod(method_name, method_signature);
     CHECK(method != nullptr);
 
-    *receiver = (is_static ? nullptr : c->AllocObject(self));
+    if (is_static) {
+      *receiver = nullptr;
+    } else {
+      // Ensure class is initialized before allocating object
+      StackHandleScope<1> hs(self);
+      Handle<mirror::Class> h_class(hs.NewHandle(c));
+      bool initialized = class_linker_->EnsureInitialized(h_class, true, true);
+      CHECK(initialized);
+      *receiver = c->AllocObject(self);
+    }
 
     // Start runtime.
     bool started = runtime_->Start();